-
Notifications
You must be signed in to change notification settings - Fork 0
/
Ball.jr
297 lines (252 loc) · 8.77 KB
/
Ball.jr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
import javax.swing.*; import java.awt.*; import java.lang.*;
import edu.ucdavis.jr.JR;
import java.awt.image.BufferedImage;
import java.io.*;
import javax.imageio.ImageIO;
public class Ball extends Toy {
////////////////////
// Class Variables
////////////////////
private static int number_of_ball_objects;
private static Image image_scaled;
private boolean firstmydraw = true;
private int deltax, deltay;
private String mystring;
////////////////////
// Constructor
////////////////////
public Ball(float x, float y, float xinc, float yinc,
Color myco, Color mycot, float size, int ball_id) {
super(x, y, xinc, yinc, myco, mycot, size, ball_id);
if(number_of_ball_objects == 0) {
// you are the first ball! Read in the file and load up the Image object
try {
//File input = new File("/home/eyan/140b/HW5/bouncers/ball.png");
// File input = new File("/home/crystalt/ecs140b/hw5/bouncers/ball.png");
File input = new File("/mnt/hgfs/VMWare/140b/bouncers/ball.png");
BufferedImage image = ImageIO.read(input);
image_scaled = image.getScaledInstance((int)size,(int)size, 1);
} catch (IOException ie) {
System.out.println("Error:"+ie.getMessage());
}
}
number_of_ball_objects++;
}
////////////////////
// Class Methods
////////////////////
/////////////////////////
// punch () - apply a "punch" to this Ball object. We always apply a upward
// "punch" of force constant punchVal. However, this function will also
// calculate the resultant vector in the X direction, depending on where
// the user punches the ball at.
/////////////////////////
public void punch (int mouse_x, int mouse_y, float punchVal) {
// calculate middle coordinates of the Ball
float toy_mid_x = x + size/2;
float toy_mid_y = y + size/2;
// distance between the punch and the center of the ball
float deltax = mouse_x - toy_mid_x;
// make easier on the player so the X velocity is not changed as much
float deltay = 2 * (mouse_y - toy_mid_y);
// avoid division by zero
if(deltax == 0) {
yinc -= (int)punchVal;
return;
}
// anything hit on the top half of the circle is "mirrored" as if they
// punched from the bottom
if(deltay < 0) {
deltay = -deltay;
}
float finalx;
if(deltax > 0) { // punch on RIGHT side of Ball
double theta = Math.atan((double)deltay/(double)deltax);
finalx = punchVal * (float)Math.cos(theta);
} else { // punch on LEFT side of Ball
deltax = -deltax;
double theta = Math.atan((double)deltay/(double)deltax);
finalx = punchVal * -(float)Math.cos(theta); // invert the x caues punching from other side now
}
// Change velocity of the ball
xinc -= finalx;
yinc -= punchVal;
}
/////////////////////////
// moveToyOneUnit () - method to move the Ball one time unit depending on
// its velocity, current gravity, and other factors. Also, check if the
// new position hits any walls (including the bottom GAME OVER one). This
// is called every time iteration.
/////////////////////////
public op void moveToyOneUnit (int H, int W, float gravity,
float punchVal, cap void() gameOver) {
// change y-velocity by current gravity value
yinc -= gravity;
// enforce MAX velocity
if(xinc > 10)
xinc = 10;
if(yinc > 10)
yinc = 10;
// move the Ball one time unit
x += xinc;
y += yinc;
// CHECK WALL BORDERS
// ------------------
if (y < 0) { // top
y = 0;
yinc = -yinc;
if(Math.abs(yinc) > punchVal) {
yinc -= punchVal / 4; // dampen speed when you hit walls
}
}
else if (y >= H-size) { // bottom
// send gameOver to BoardHost
send gameOver(); // GAME OVER
return;
}
if (x >= W-size) { // right
x = W-size;
xinc = -xinc;
if(Math.abs(xinc) > punchVal) {
xinc += punchVal / 4; // dampen speed when you hit walls
}
}
else if (x < 0) { // left
x = 0;
xinc = -xinc;
if(Math.abs(xinc) > punchVal) {
xinc -= punchVal / 4; // dampen speed when you hit walls
}
}
}
/////////////////////////
// doCollision () - Assumes collision has occured between this and Ball B.
// Calculates resultant position and velocities of each ball after the
// collision
/////////////////////////
public op void doCollision(Ball B) {
// 1. move balls apart
// -------------------
float me_mid_x = x + size/2;
float me_mid_y = y + size/2;
float other_mid_x = B.getX() + B.getSize()/2;
float other_mid_y = B.getY() + B.getSize()/2;
float deltax = other_mid_x - me_mid_x;
float deltay = other_mid_y - me_mid_y;
float distance = (float)Math.sqrt((deltax * deltax) + (deltay * deltay));
if(distance == 0) {
// if right on top of each other, don't do anything
return;
/*
distance = size/2 + B.getSize()/2 - 1;
deltax = size/2 + B.getSize()/2;
deltay = size/2 + B.getSize()/2;
*/
}
// re-check collidesWithBall() in case there were race conditions
if(distance > (size/2 + B.getSize()/2)) {
return;
}
// found the minimum translation distance (how much to move balls by)
float mtd_x = deltax * ((size/2 + B.getSize()/2) - distance) / distance;
float mtd_y = deltay * ((size/2 + B.getSize()/2) - distance) / distance;
// change each ball's position
// NOTE: We are assuming equal mass here, thus multiply by 1/2
// usually, this will be inversely proportional to A's mass to the sum
// of A+B mass
// change "this"
x -= mtd_x * (1.0f / 2.0f);
y -= mtd_y * (1.0f / 2.0f);
// change Ball B
B.setX(B.getX() + mtd_x * (1.0f / 2.0f));
B.setY(B.getY() + mtd_y * (1.0f / 2.0f));
// 2. adjust Ball velocities
// --------------------------
float my_vx = xinc;
float my_vy = yinc;
float B_vx = B.getXinc();
float B_vy = B.getYinc();
// impact speed
float v_x = my_vx - B_vx;
float v_y = my_vy - B_vy;
// normalize mtd
float mtd_len = (float)Math.sqrt((mtd_x * mtd_x) + (mtd_y * mtd_y));
// Check if Balls don't actually collide. If so, return.
if(mtd_len == 0.0f) {
return;
}
float normal_mtd_x = mtd_x / mtd_len;
float normal_mtd_y = mtd_y / mtd_len;
// dot product
float vn = (v_x * normal_mtd_x) + (v_y * normal_mtd_y);
if (vn < 0) {
return; // collide, but moving away already
}
// impulse
float elasticity = .7f; // 1 is elastic, < 1 is inelastic
float i = -((1.0f + elasticity) * vn) / 2.0f; // assuming equal mass=2
float impulse_x = normal_mtd_x * i;
float impulse_y = normal_mtd_y * i;
// modify velocities
xinc += impulse_x;
yinc += impulse_y;
B.setXinc(B.getXinc() - impulse_x);
B.setYinc(B.getYinc() - impulse_y);
}
/////////////////////////
// collidesWithBall () - Checks if "this" and Ball B collide
/////////////////////////
public boolean collidesWithBall(Ball B) {
// calculate middle coordinates for myself
float me_mid_x = x + size/2;
float me_mid_y = y + size/2;
// calculate middle coordinates for Ball B
float other_mid_x = B.getX() + B.getSize()/2;
float other_mid_y = B.getY() + B.getSize()/2;
// distance between my middle and B's middle
float deltax = other_mid_x - me_mid_x;
float deltay = other_mid_y - me_mid_y;
float distance = (float)Math.sqrt((deltax * deltax) + (deltay * deltay));
// if the distance between the balls is less than the sum of the radii
// of the two balls, they have collided
return distance <= (size/2 + B.getSize()/2);
}
/////////////////////////
// isClicked () - Checks if a certain (X,Y) pair is "inside" of this Ball
/////////////////////////
public boolean isClicked (int mouse_x, int mouse_y) {
// the x,y are for the upper-left corner of the object. To get the
// "middle", we need to add half the size(diameter)
float toy_mid_x = x + size/2;
float toy_mid_y = y + size/2;
// distance between my middle and the mouse click
float deltax = mouse_x - toy_mid_x;
float deltay = mouse_y - toy_mid_y;
float distance = (float)Math.sqrt((deltax * deltax) + (deltay * deltay));
// if the distance between the ball and the click is less than the
// radius of the ball, then the ball has been clicked
return distance <= (size / 2.0f);
}
/////////////////////////
// mydraw () - Swing overloaded method to draw this Ball
/////////////////////////
public void mydraw (Graphics2D g2) {
// since size and font size don't change,
// compute only on first time.
// takes into account size of text to center text.
if (firstmydraw) {
firstmydraw = false;
mystring = ""+toy_id;
FontMetrics metrics = g2.getFontMetrics();
int width = metrics.stringWidth( mystring );
int height = metrics.getHeight();
deltax = (int)(size-width)/2;
deltay = (int)(size+height)/2;
}
// draw the ball in its current (x,y) coordinates
g2.drawImage( image_scaled, (int)x, (int)y, null);
// draw the ball_id string in the middle
g2.setColor( Color.red );
g2.drawString(mystring,x+deltax,y+deltay);
}
}