In this program I simulate the gravity. All works but when there is no more movement for the ball it keep bouncing 1-5 pixels depending on the gravity value I set. How could i stop the ball when the energy is lost? I want the xSpeed to become 0 and the ball to stay on a fix position.
Edit: The gravity variate from 1 to 100. The user can change the gravity.
energyLoss = 0.9 and dt = 0.2
// right and left wall collision
if (x + xSpeed > this.getWidth() - radius - 1) {
x = this.getWidth() - radius - 1;
xSpeed = -xSpeed;
} else if (x + xSpeed < 0 + radius) {
x = 0 + radius;
xSpeed = -xSpeed;
} else
x += xSpeed;
if (y == this.getHeight() - radius - 1) {
}
if (y > this.getHeight() - radius - 1) {
y = this.getHeight() - radius - 1;
ySpeed *= energyLoss;
ySpeed = -ySpeed;
// friction with the ground
xSpeed *= xFriction;
if (Math.abs(xSpeed) < .4)
xSpeed = 0;
} else {
ySpeed += gravity * dt; // velocity formula
y += ySpeed * dt + .5 * gravity * dt * dt; // position formula
}
repaint();
Simplistic Answer
After this line:
ySpeed *= energyLoss;
Change this line:
ySpeed = -ySpeed;
To something like this:
if (ySpeed < SomeMinimumValue)
{
ySpeed = 0;
}
else // invert speed, i.e. change direction.
{
ySpeed = -ySpeed;
}
Edit; Second try:
if (Math.abs(ySpeed) < SomeMinimumValue)
... as above.
Less code, more talk
It appears that the problem stems from the ball impacting the "ground" with a low y and or x speed. If this is the case, you need to zero the speed when impacting the "ground" with a sufficiently low y or x speed; zero y speed when y speed is low enough and zero x speed when x speed is low enough, not necessarily both at the same time. You also need to make sure you are not zeroing the x speed on a y impact and not zeroing the y speed on an x impact.
The simplest way to fix this problem is to detect a special case where the ball is on the wall with 0 (or very small) Y velocity. This is basically what DwB is suggesting.
However, you then need to go further and make sure that you stop applying gravity when you're in that situation.
Something like this:
// right and left wall collision
if (x + xSpeed > this.getWidth() - radius - 1) {
x = this.getWidth() - radius - 1;
xSpeed = -xSpeed;
} else if (x + xSpeed < 0 + radius) {
x = 0 + radius;
xSpeed = -xSpeed;
} else
x += xSpeed;
if (y == this.getHeight() - radius - 1
&& ySpeed == 0) { // Check speed too here!
// Do nothing for Y.
// friction with the ground
xSpeed *= xFriction;
if (Math.abs(xSpeed) < .4)
xSpeed = 0
}
else if (y > this.getHeight() - radius - 1) {
y = this.getHeight() - radius - 1;
ySpeed *= energyLoss;
if (Math.abs(ySpeed) < SomeMinimumValue)
ySpeed = 0;
else // invert speed, i.e. change direction.
ySpeed = -ySpeed;
// friction with the ground
xSpeed *= xFriction;
if (Math.abs(xSpeed) < .4)
xSpeed = 0;
} else {
ySpeed += gravity * dt; // velocity formula
y += ySpeed * dt + .5 * gravity * dt * dt; // position formula
}
repaint();
Related
I am currently working on a 2D side scroller and have implemented the techniques use in this article for a grapple hook, and it works really well. My problem is I want my player to be able to swing around the rope a little bit to gain a bit of momentum, but currently I can't stop the player from moving all the way up to 90 degrees either side. What techniques can be applied to force this limit?
I have tried using a separate player speed for swinging but this only slows the process down I can still swing up to 90 deg each side.
Here's my update function in the player
public void update(float dt){
//handle friction and air resistance
if(dx !=0){
if(touchingGround) {
// apply friction
if (dx > 0) {
dx -= retardation;
} else {
dx += retardation;
}
} else {
//applied air resistance
if (dx > 0) {
dx -= airResistance;
} else {
dx += airResistance;
}
}
}
// handle gravity
dy -= Constants.GRAVITY * dt;
if(dy < -terminalVelocity){
dy = -terminalVelocity;
}
/*
Handle Player movement
*/
if(right){
if(dx <= maxSpeed){
dx += acceleration;
}
dx = maxSpeed;
}
if(left){
if(dx <= -maxSpeed){
dx -= acceleration;
}
dx = -maxSpeed;
}
if(isGrappling){
//If we collide with something we need to stop grappling
if(hasCollided){
isGrappling = false;
} else {
// This algorithm from here:
// http://gamedev.stackexchange.com/questions/61596/player-rope-swing
float currentD = (float) Math.sqrt(((grappleX - x) * (grappleX - x)) + ((grappleY - y) * (grappleY - y)));
float prevX = getX(), prevY = getY();
if (currentD > grappleRadius) {
Vector2 hookPos = new Vector2(grappleX, grappleY);
Vector2 testPos = (new Vector2(x, y).sub(hookPos)).nor();
y = (hookPos.y + testPos.y * grappleRadius);
x = (hookPos.x + testPos.x * grappleRadius);
// s = d / t
dx += (x - prevX) / dt;
dy += (y - prevY) / dt;
}
}
}
/*
Collision Detection, handle last always!
*/
float oldX = getX(), oldY = getY();
boolean collisionX = false, collisionY = false;
// move on x
x += dx * dt;
// calculate the increment for step in #collidesLeft() and #collidesRight()
increment = collisionLayer.getTileWidth();
increment = getWidth() < increment ? getWidth() / 2 : increment / 2;
if(dx < 0) // going left
collisionX = collidesLeft();
else if(dx > 0) // going right
collisionX = collidesRight();
// react to x collision
if(collisionX) {
setX(oldX);
dx = 0;
}
// move on y
y += dy * dt;
// calculate the increment for step in #collidesBottom() and #collidesTop()
increment = collisionLayer.getTileHeight();
increment = getHeight() < increment ? getHeight() / 2 : increment / 2;
if(dy < 0) {
touchingGround = collisionY = collidesBottom();
// we can only jump 2 times before we have to touch the floor again
if(collisionY){
numberOfJumps = 2;
}
} else if(dy > 0) {
collisionY = collidesTop();
}
// react to y collision
if(collisionY) {
setY(oldY);
dy = 0;
}
hasCollided = collisionX || collisionY;
}
As I am not using any physics engine I chose to just emulate the physics by limiting the angle at which the player can apply force to the swing.
// check if angle permits movement
if(grappleAngle < Math.PI/9 && grappleAngle > -Math.PI/9) {
// handle momentum gaining on rope
if (right) {
dx += swingAcceleration * dt;
}
if (left) {
dx -= swingAcceleration * dt;
}
}
I am attempting to write a game where a ball generates for three turns and if the ball makes it past the bottom of the screen the turn is ended.
Below is the class I have written and I can get the ball to move but when it moves past the bottom of the screen the ball does not regenerate in the middle of the screen as I would anticipate.
Apologies if this question is rudimentary but I have worked on this for a bit and seem to be stuck.
private void initiateBall() {
double bx = (WIDTH / 2) - BALL_RADIUS;
double by = (HEIGHT / 2) - BALL_RADIUS;
GOval ball = new GOval(bx, by,BALL_RADIUS, BALL_RADIUS);
ball.setFilled(true);
ball.setColor(Color.BLACK);
vx = rgen.nextDouble(1.0, 1.2);
if (rgen.nextBoolean(0.5)) vx = -vx;
vy = 3.0;
for (int i = 0; i <= NTURNS; i++) {
add (ball);
while (ball.getY() < HEIGHT && ball.getX() < HEIGHT) {
ball.move(vx, vy);
pause(DELAY);
}
}
private void initiateBall() {
for (int k = 0; k < NTURNS; k ++) {
double bx = (WIDTH / 2) - BALL_RADIUS;
double by = (HEIGHT / 2) - BALL_RADIUS;
GOval ball = new GOval(bx, by, BALL_RADIUS, BALL_RADIUS);
ball.setFilled(true);
ball.setColor(Color.BLACK);
vx = rgen.nextDouble(1.0, 1.2);
if (rgen.nextBoolean(0.5)){
vx = -vx;
}
vy = 3.0;
double x = bx;
double y = by;
add(ball, (x), y);
while (ball.getY() < HEIGHT) {
ball.move(vx,vy);
pause(DELAY);
}
}
}
I'm trying to create a bouncing ball that can move in the x, y, and z coordinates. The ball originally starts a couple units in the y-axis above the origin. I've managed to figure out how to get my ball to bounce up and down in the y plane, but am having troubles figuring out what I am doing wrong whenever I try adding the x and z trajectories.
double initialVelocity = userInputY;
double initVelX = userInputX;
double initVelZ = userInputZ;
double speed = 1/500.0;
double time = 0;
double x, y, z =0;
if (time == 0){
velocity+= initialVelocity;
}
time += speed
velocity = velocity - 9.8 * speed;
if (y+velocity < 0.1){ //collision detection against the floor
velocity *= -1;
}
if (z + initVelZ < 100){ //Collision detection for ceiling of 100 units
initVelZ *= -1;
}
if (x + initVelX < 50){ //Collision detection for if ball moves 50 units away from origin in x
initVelX *= -1;
}
else{
y += velocity;
x += initVelX;
z += initVelZ;
}
gl.gltranslated(x, y, z);
glu.gluSphere() //not really that important to specify
When I only use my y variable my ball has a bouncing animation but only moves up and down.
The comparisons for the z and x coordinates look backwards:
if (z + initVelZ < 100){ //Collision detection for ceiling of 100 units
initVelZ *= -1;
}
if (x + initVelX < 50){ //Collision detection for if ball moves 50 units away from origin in x
initVelX *= -1;
}
This inverts the velocity every time the new position is found to be inside the bounds. But they need to be inverted when the new position would end up being outside the bounds.
Also, you probably need to test for collision with the walls at both ends of each coordinate direction, so that the ball can bounce off all 6 walls.
For example for the z coordinate, the logic could look like this:
if (z + initVelZ < 0.0 || z + initVelZ > 100.0) {
initVelZ *= -1.0;
}
Same thing for the other coordinates.
Maybe a beginner question, but thank you for reading. I'm working on a 2d Java game in which I have missiles that track the position of an object using the following code. I'd like the missiles to stop homing when they reach a certain minimum displacement from their target, at which point they should fall straight down. Right now, the homing behavior turns off whenever the missile is within the minimum displacement, and turns on again if the displacement increases. I'd like the behavior to turn off only once, staying off for the remainder of the missile's lifespan. How can I accomplish this?
public void home(int targetX, int targetY, int scale){
int dy = targetY - y;
int dx = targetX - x;
double speed, sep;
sep = Math.sqrt(dx * dx + dy * dy);
speed = scale/sep;
if(dy > 50 || dx > 50){
x += dx * speed;
y += dy * speed;
}
else{
x += 0;
y += scale;
}
}
Add a member variable, such as boolean homing = true. Then, change your conditional to something like the following:
if (dy < 50 && dx < 50)
homing = false;
if(homing){
x += dx * speed;
y += dy * speed;
}
else{
x += 0;
y += scale;
}
You basically just need to break the mutual dependence between you missile's behaviour and its state.
I have a simple Java applet that has two user-controlled balls, drawn using java.awt. I need a way to detect a collision with between them. I have an algorithm for detecting collision with the walls:
if (xPosition > (300 - radius)){
xSpeed = -xSpeed;
}
else if (xPosition < radius){
xSpeed = -xSpeed;
}
else if (yPosition > (300 - radius)) {
ySpeed = -ySpeed;
}
else if (yPosition < radius){
ySpeed = -ySpeed;
}
xPosition += xSpeed;
yPosition += ySpeed;
and for the second ball:
if (xPosition2 > (300 - radius)){
xSpeed2 = -xSpeed2;
}
else if (xPosition2 < radius){
xSpeed2 = -xSpeed2;
}
else if (yPosition2 > (300 - radius)) {
ySpeed2 = -ySpeed2;
}
else if (yPosition2 < radius){
ySpeed2 = -ySpeed2;
}
xPosition2 += xSpeed2;
yPosition2 += ySpeed2;
The applet is 300 pixels by 300 pixels.
radius stores the radius of the circles.
xPosition and xPosition2 store the x coordinates for the two balls.
yPosition and yPosition store the y coordinates for the two balls,
xSpeed and xSpeed2 store the x velocities for the two balls.
ySpeed and ySpeed2 store the y velocities for the two balls.
Use http://java.sun.com/j2se/1.5.0/docs/api/java/awt/geom/Point2D.html, there's a distance method there, if it's less than the radius they're colliding.
EDIT:
Err, less than the radius * 2 , sorry
There's Point2D in Java or you can do it yourself, it is trivially easy for circle/circle collisions or sphere/sphere collisions.
int distXX = (xPosition1 - xPosition2) * (xPosition1 - xPosition2);
int distYY = (yPosition1 - yPosition2) * (yPosition1 - yPosition2);
if ( radius*radius > distXX * distYY ) {
... // There's a collision
}
public boolean colliding(Ball anotherBall) {
double xDelta = (this.x + this.ballSize/2 + this.dx) - (anotherBall.x + anotherBall.ballSize/2 + anotherBall.dx);
double YDelta = (this.y + this.ballSize/2 + this.dy) - (anotherBall.y + anotherBall.ballSize/2 + anotherBall.dy);
double distance = Math.sqrt(Math.pow(xDelta, 2) + Math.pow(YDelta, 2));
return (distance <= this.ballSize/2 + anotherBall.ballSize/2);
}
This Link is pretty useful!
Circle-Circle Collisions
It's very detailed and didatic
At the bottom of that page there are another links, to even more detailed stuff!
I used the Distance Between Centers method ---
Circles
By measuring the distance between each center you can say if they are colliding.
The distance should never be more then the sum of the 2 radius.
Here's what I did:
private boolean checkDrawContains(ShapeDrawable newHole)
{
long newCenterX = newHole.getBounds().left + (newHole.getBounds().width()/2); //Get the center of my shapes
long newCenterY = newHole.getBounds().top + (newHole.getBounds().height()/2);
for(ShapeDrawable hole: mHoles) // I was storing the circles in an ArrayList
{
long centerX = hole.getBounds().left + (hole.getBounds().width()/2); //Get the center of my shapes
long centerY = hole.getBounds().top + (hole.getBounds().height()/2);
long x = centerX - newCenterX;
long y = centerY - newCenterY;
long aux = (long) ((Math.pow(Math.abs(x),2)) + (Math.pow(Math.abs(y),2))); //Pythagoras the hard way :P
long distance = (long) Math.sqrt(aux);
long sRads = (newHole.getBounds().width()/2) + (hole.getBounds().width()/2);
if(distance <= sRads ) {
return true; //Is Colliding!
}
}
return false; // Is not Colliding!
}