Bouncing Ball in Java - java

This is probably a really basic problem but I can't seem to find any other articles on it.
Anyway, I have written a small bouncing ball program in Java to try and expand my basic skills. The program is just a simple bouncing ball that will drop and hopefully bounce for a while. The original program worked fine but now I have tried to add gravity into the program. The gravity actually works fine for a while but then once the bounces get really small the animation becomes erratic for a very short time then the position of the ball just constantly decreases. I've tried to figure out the problem but I just can't see it. Any help would be most welcome.
public final class Ball extends Rectangle {
float xspeed = 1.0f; float yspeed = 1.0f; float gravity = 0.4f;
public Ball(float x, float y, float width, float height) {
super(x, y, width, height);
}
public void update(){
yspeed += gravity;
move(xspeed, yspeed);
if(getX() < 0){
xspeed = 1;
}
if(getX() + getWidth() > 320){
xspeed = -1;
}
if(getY() < 0){
yspeed = 1;
}
if(getY() + getHeight() > 200 && yspeed > 0){
yspeed *= -0.98f;
}
if(getY() + getHeight() > 200 && yspeed < 0){
yspeed *= 0.98f;
}
}
public void move(float x, float y){
this.setX(getX()+x);
this.setY(getY()+y);
}
}
EDIT: Thanks that seems to have sorted the erratic movement. I'm still struggling to see how I can stop my ball moving down when it has stopped bouncing. Right now it will move stop bouncing then continue moving down passed the "floor". I think it's to do with my yspeed += gravity line. I just can't see how I'd go about stopping the movement down.

When you do
yspeed += gravity;
you are assuming that the ball has space move through a distance dx = v_i * t + 1/2 (-g) t^2. When you are very near the floor this may not be true. It fail if:
You are near enough the the floor and moving down
You are very near the floor and have low velocity (like when the ball has lost most of it's energy)
This bug causes your simulation to stop conserving energy, resulting in the erratic behavior you see at low amplitude.
You can reduce the problem by using smaller time steps, and you can get rid of it outright if you do test computation to notice when you're out of room and to select a safe time step for that iteration (i.e. always use your default unless there is a problem, then calculate the best time step).
However, the basic approximation you're using here has other problems as well. Look in any numeric analysis text for a discussion of solving differential equations numerically.

First things first: setting y-speed to 1 when you bounce on the top of the window is not correct, you should set yspeed to -yspeed (but if you start within the borders, it should never bounce up to the top anyway).
Secondly, your multiply by -0.981 when bouncing on the bottom is okay but I'm concerned with the constant 0.4 gravity being added to yspeed every iteration. I think that's what is causing you wiggles at the bottom since you do the move before checking which can result in the ball dropping below ground level.
I would try ensuring the the y value can never go below ground level by replacing the move with:
if (getY() + getHeight() + yspeed > 200) {
move(xspeed, 200 - getY() - getHeight());
} else {
move(xspeed, yspeed);
}

The problem is that when the bounces get really small, the
yspeed *= -0.981;
line will get called in short succession. The ball will go below the bottom, start coming back up, but still be below the bottom (because 0.981 < 1.0) eventually, and it will behave eradically. Here's how you fix it:
if(getY() + getHeight() > 200){
yspeed *= -0.981;
setY(400 - getY() - getHeight()); // I believe this is right.
}
By fixing the position, you won't alternate between decreasing and increasing as quickly and won't get stuck in the situation where it is always decreasing because it is always below the bounds.

[EDIT: I think I misunderstood, so this probably isn't much use :) ]
if(getY() + getHeight() > 200){
yspeed *= -0.981;
}
You're negating the vertical velocity on every update. I'd probably try handling gravity in update-sized slices. Assuming you're doing 30 updates per second (for 30fps), maybe something like
// Define some constants
SecondsPerUpdate = (1.0f / 30);
AccelDueToGravity = 0.981;
if(getY() + getHeight() > 200){
yspeed -= (AccelDueToGravity * SecondsPerUpdate);
}

I suspect it's because when the ball bounces, it will actually be slightly below the "ground", and at low speeds, it won't move back above the ground in one tick - so the next update() will see it still below the ground, and bounce again - but downwards this time, so the cycle continues.
You need to move the ball back up to ground level when it bounces, something like this:
if(getY() + getHeight() > 200){
yspeed *= -0.981;
setY(200 - getHeight());
}

Related

How do you make a Bitmap image point forward the entire time it's moving and turning?

Is there some sort of formula for rotating the arrow in this link right here to make sure it's always pointing toward the red? Each time I've tried, I'd always get a number that's off, and the arrow's rotation is not in sync with the arrow's turning and movement.
A couple of snippets of code to show what I'm working with:
arrow.moveX(true);
arrow.moveY(true);
if(arrow.turning) {
arrow.turn(player.direction / (0.75 * arrow.getSpeed()));
}
The arrow's speed is 12.5 units/time if that's important. As for the movement itself:
public void moveX(boolean turn) {
if(turn) {
x += speed * Math.cos(angle);
} else {
x += speed;
}
}
public void moveY(boolean turn) {
if(turn) {
y += speed * Math.sin(angle);
} else {
y += speed;
}
}
I'm trying to figure out how to render the arrow's sprite make sure that the pointer itself is facing that "forward" direction that it's moving in, no matter how much it rotates. Here is the render method itself if that's necessary:
#Override
public void render(Canvas c, Paint p) {
matrix.setTranslate((float)x, (float)y);
if(alive) {
matrix.postRotate(drawnAngle, (float) (x + width / 2), (float) (y + height / 2));
} else {
matrix.postRotate(angle, (float) (x + width / 2), (float) (y + height / 2));
angle += speed * 2;
}
c.drawBitmap(getSprite(), matrix, p);
}
The variable drawnAngle has a value of 0 right now, it's a placeholder. It was just my attempt of trying to find the right number to rotate the arrow by.
So I've actually spent hours trying to figure this out, and the moment I decide to post for help, I figured it out! It turns out that while I was using radians in the first snippet of code (the actual movement), I was supposed to be using degrees in the actual rotate in that last snippet!
I changed drawnAngle to (float)(angle * (180 / Math.PI)) and this worked as a solution for me!
Hopefully no one else has this problem.

Creating a circle out of tiles

This is my first attempt at creating a 2D game, so my code probably isn't as efficient as it could be. Anyway, I tried creating a method to create circles out of my tiles. The point of this method is to create circular dirt patches across my screen. Here is a bit of my code:
private void generateDirt(int x, int y) {
int dirt = 3;
int radius = random.nextInt(7) + 3;
for (int i = radius; i > 1; i--) {
for (int angle = 0; angle < 360; angle++) {
double theta = Math.toRadians(angle);
// Broken Line to solve jutting blocks
// if (theta % Math.PI == 0) theta = 0;
tiles[(int) (x + radius * (Math.sin(theta) * Math.cos(theta)))
+ (int) (y + radius
* (Math.sin(theta) * Math.sin(theta))) * width] = dirt;
}
radius--;
}
}
If I comment out the part where I decrease the radius, and draw just a single circle outline (comment out the outermost for loop(int i = radius...) then the circle is drawn perfectly, except for these two strange tiles jutting out in the side. Sometimes the jutting block is on the right side (I thought it was when it was equal to pi / 2) and on the bottom side as well. But the main problem is that when I attempt to fill the circle by decreasing the radius, the circle...well... becomes a square. It loses its round shape and develops very rigid corners.
I worked on this pretty late, I'm not even sure if my math is correct. TBH, I just kinda threw in the trig functions at random and finally got something that looked like a circle. If you can help me identify what is wrong, or tell me a better way to do this, please let me know! Thanks for the help!
*Also, the radius is actually the diameter (I counted), I need to change the name...
Well I found the answer to my own question. It turns out I don't need to convert my angles to radians. In fact, that just messes up the coordinates. Just using the "angle" instead of "theta" variable fixes the problem.

Make ball bounce in canvas

I have written code that should form the basis for a simple Pong game. It works, but I don't understand why. It should not work. I'm hoping somebody can give me the insight I'm missing as to why it does work.
I have the following concept in my canvas (which has (0,0) on the top left):
A ball always bounces in an angle between 0 and 180 degrees. I have taken the bottom of my canvas as the basis. Left is 0 degrees, right is 180 degrees. If it bounces on a wall the ball's angle (ball_angle) changes to 180 - ball_angle degrees. A ball's trajectory is defined by 2 more variables (x_traj and y_traj) indicating the direction on each axis.
The part I don't get is the ballHits() method. If the ball is hitting the cealing, coming from the right with a degree of e.g. 100, then it should bounce off at a degree of 80. The ball is coming from the right so the x_traj is negative. We are bouncing on the cealing so the ball drops instead of lifts, ergo we change the y_traj from negative (lifting) to positive (dropping). The ball will still be going to the right, so we leave that direction in tact.
Second scenario is when the ball hits the left wall. The ball is coming from the right again, so we know that traj_x is negative. We bounce off so the ball goes back to the right, ergo traj_x should be multiplied by -1 to make it positive again (move to the right). Wether we hit the wall coming from above or below, we are still going that same direction after bouncing of the wall. We don't change the traj_y variable.
However, below is the working code. I do not have to change any variable when I hit the left or right wall. Could somebody explain to me why?
If needed, the full compiling project can be found on GitHub.
Code to move the ball to new coordinates:
private void updateBall()
{
// http://gamedev.stackexchange.com/questions/73593/calculating-ball-trajectory-in-pong
// If the ball is not hitting anything, we simply move it.
// http://en.wikipedia.org/wiki/Polar_coordinate_system
if (ballHits())
{
// Bounce the ball off the wall.
ball_angle = 180 - ball_angle;
}
// http://en.wikipedia.org/wiki/Polar_coordinate_system
// Convert the angle to radians.
double angle = (ball_angle * Math.PI) / 180;
// Calculate the next point using polar coordinates.
ball_x = ball_x + (int) (x_traj * BALL_STEPSIZE * Math.cos(angle));
ball_y = ball_y + (int) (y_traj * BALL_STEPSIZE * Math.sin(angle));
System.out.printf("Ball: (%d,%d) # %d\n", ball_x, ball_y, ball_angle);
}
Code that determines if we have hit a wall:
private boolean ballHits()
{
// If we came out of bounds just reset it.
ball_y = Math.max(0, ball_y);
ball_x = Math.max(0, ball_x);
// Check to see if it hits any walls.
// Top
if(ball_y <= 0)
{
System.out.println("Collision on top");
y_traj *= -1;
x_traj *= -1;
return true;
}
// Left
if(ball_x <= 0)
{
System.out.println("Collision on left");
//y_traj *= -1;
//x_traj *= -1;
return true;
}
// Right
if(ball_x >= B_WIDTH)
{
System.out.println("Collision on right");
//y_traj *= -1;
//x_traj *= -1;
return true;
}
// Bottom
if(ball_y >= B_HEIGHT)
{
System.out.println("Collision on bottom");
y_traj *= -1;
x_traj *= -1;
return true;
}
return false;
}
Well it's working in a tricky way because cosine goes negative when your angle is > 90°.
Making him start with a different initial trajectory and angle should not work if the ball hits the bottom or top first.
Edit : I thought it would do that but doing it on paper proves me wrong, well it's a weird way to do it but it's working as intended. I'll investigate to find if there's a way it doesn't work.
Edit 2 : Does a start angle in range of [88-92] work ?

Ball collision in Java

I am making a game where a ball goes and collects other balls.
I have written a collision detector, but I am finding that it is a little off kilter.
If the controlled ball is about 10 pixels to the right of the ball to be collected, it will still register a collision.
If the user's ball is on the left side of the ball to be collected, the collision works well.
Could someone please explain why this is happening and/or suggest a fix? Thanks!
Here is my collision detector:
private void checkForCollision(UserBall b) {
int ballX = b.getX();
int ballY = b.getY();
int ballR = b.getRadius();
int a = x - ballX;
int bb = y - ballY;
int collide =radius + ballR;
if (a*a + bb*bb <=collide*collide){
performAction(b);
createNew= true;
}
}
This is js code, nearest I found on my computer. It works fine.
Ball.prototype.intersects = function (p) {
'use strict';
switch (p.id) {
case IDS.Ball:
var dist = this.radius + p.radius,
dx = this.x - p.x, //x - is center of Ball
dy = this.y - p.y;
return dist * dist >= (dx * dx + dy * dy);
default:
throw "Ball does not provide intersects for " + p.id;
}
};
Also C++ code, I found on my computer. It also works fine
bool Ball::intersects(Ball &b) {
if (this != &b) {
int dx = b.x - this->x; //x is center of Ball
int dy = b.y - this->y;
int sqrdist = dx*dx + dy*dy;
int sumrad = b.radius + this->radius;
return sumrad*sumrad >= sqrdist;
}
return false;
}
It also works fine. So I suggest that you calculate position of balls before check for intersection.
P.S. And please, distinguish method to check intersection, which return bool. Do not mix checking of event with action on event.
I just inserted your code snippet on a similar collision detection method in one of my games and it worked as expected.
However, i remember i ran into a similar issue when i was testing mine, the issue was with the image displaying, not the collision detection. If you are using LWJGL or something like that for rendering, check that your textures/images are of a power of two size. Sometimes, they just add padding to the nearest power of two and it "seems" like they are not colliding when they actually are, just not visually.

OpenGL + Processing: Rotate and move based on direction

I'm trying to rotate and move a triangle into a certain direction, based on the pointing direction of the triangle. In theory, I calculate the sine and cosine of the direction (0-360 degrees) and add these values to the x- and y-position, right? It just doesn't work.
Also, the triangle should point up in the beginning, not down.
public void speedUp() {
float dirX, dirY;
speed *= acceleration;
if(speed > 50) speed = 50;
println("dir: " + direction + " x: " + cos(direction) + " y: " + sin(direction));
dirX = cos(direction);
dirY = sin(direction);
xPos+=dirX;
yPos+=dirY;
}
public void redraw() {
GL gl = pgl.beginGL(); // always use the GL object returned by beginGL
gl.glTranslatef(xPos, yPos, 0);
gl.glRotatef(direction, 0, 0, 1000);
gl.glBegin(GL.GL_TRIANGLES);
gl.glColor4f(0.1, 0.9, 0.7, 0.8);
gl.glVertex3f(-10, -10, 0); // lower left vertex
gl.glVertex3f( 10, -10, 0); // lower right vertex
gl.glVertex3f( 0, 15, 0); // upper vertex
gl.glEnd();
}
It looks like you need to convert from polar coordinates(moving about using an angle and a radius) to cartesian coordinates(moving about using the x and y).
The formula looks a bit like this:
x = cos(angle) * radius;
y = sin(angle) * radius;
So, as #Lie Ryan mentions, you also need to multiply with speed (which is your radius in polar coordinates).
Either have your angle in degrees but use radians() when using cos,sin as they work with radians, or use radians, and use degrees() with glRotatef, up to you
Also, you might want to have a look at glPushMatrix() and glPopMatrix(). Bascially, they allow you to nest transformations. Whatever transformations you do withing the blocks, they affect just that block locally.
Here's what I mean, use w,a,s,d keys:
import processing.opengl.*;
import javax.media.opengl.*;
float direction = 0;//angle in degrees
float speed = 0;//radius
float xPos,yPos;
void setup() {
size(600, 500, OPENGL);
}
void keyPressed(){
if(key == 'w') speed += 1;
if(key == 'a') direction -= 10;
if(key == 'd') direction += 10;
if(key == 's') speed -= 1;
if(speed > 10) speed = 10;
if(speed < 0) speed = 0;
println("direction: " + direction + " speed: " + speed);
}
void draw() {
//update
xPos += cos(radians(direction)) * speed;
yPos += sin(radians(direction)) * speed;
//draw
background(255);
PGraphicsOpenGL pgl = (PGraphicsOpenGL) g;
GL gl = pgl.beginGL();
gl.glTranslatef(width * .5,height * .5,0);//start from center, not top left
gl.glPushMatrix();
{//enter local/relative
gl.glTranslatef(xPos,yPos,0);
gl.glRotatef(direction-90,0,0,1);
gl.glColor3f(.75, 0, 0);
gl.glBegin(GL.GL_TRIANGLES);
gl.glVertex2i(0, 10);
gl.glVertex2i(-10, -10);
gl.glVertex2i(10, -10);
gl.glEnd();
}//exit local, back to global/absolute coords
gl.glPopMatrix();
pgl.endGL();
}
You don't actually need the { } for the push and pop matrix calls, I added them like a visual aid. Also, you can do this without push/pop, by concatenating your transforms, but it's handy to know those are there for your when you need them. Might come in handy when you want to shoot some GL_LINES out of that triangle...pew pew pew!
HTH
You have your units messed up. glRotatef excepts degrees and the trigonometrical functions expect radians. This is the most obvious mistake.
Also, speed is never used in your snippet. I suppose that every frame you're using it somehow, but in the code you pasted there's:
xPos+=dirX
Which is basically "add direction to the position" - not making much sense, unless you want to "move it exactly 1 unit in the given direction instantenously at the moment when speedUp() is called. The usual approach for continous movement would be to:
// each frame:
xPos += dirX * speed * deltaTime;
yPos += dirY * speed * deltaTime;
Try this:
dirX = speed * cos(direction);
dirY = speed * sin(direction);
You are obviously new to OpenGl, so I would recommend you, that you look into quaternions to do your roations. Here are two pretty nice article about this matter: Gamedev and Nehe. I would recommend you to use the Quaternion class from the JMonkeyEngine. Just remove the savable and some other interfaces and you can use them with ease. Here they are located: JMonkey Source
I also use the JME math classes for my own projects. I have already striped most of the dependencies and you can download some classes from here: Volume Shadow. However the Quaternion class is missing, but you WILL need Vector3f :D.

Categories

Resources