While practicing wanted to create basic game-kind-of(?) - there is just a basic shape (rectangle) and you move forward with one button, move backwards with another, and rotate it with 2 additional buttons, that shape as well should move to other direction accordingly to it's rotation. What i have done so far is:
Input handling:
if (input.isKeyDown(Input.KEY_UP)) {
rectX += Math.cos(Math.toRadians(rotation)) * (0.2*delta);
rectY += Math.sin(Math.toRadians(rotation)) * (0.2*delta);
}
if (input.isKeyDown(Input.KEY_DOWN)) {
rectX -= Math.cos(Math.toRadians(rotation)) * (0.2*delta);
rectY -= Math.sin(Math.toRadians(rotation)) * (0.2*delta);
}
if(input.isKeyDown(Input.KEY_LEFT)){
rotation-=(0.1*delta);
rectangle = rectangle.transform(Transform.createRotateTransform(rotation, rectX, rectY));
if(rotation <= 0f) {
rotation = 360f;
}
}
if(input.isKeyDown(Input.KEY_RIGHT)){
rotation+=(0.1*delta);
rectangle = rectangle.transform(Transform.createRotateTransform(rotation, rectX, rectY));
if(rotation >= 360f) {
rotation = 0f;
}
}
rectangle.setCenterX(rectX);
rectangle.setCenterY(rectY);
}
rectX, rectY are obviously center coordinates of rectangle (floats)
and rotation is... well rotation..
And I think that's it, other code isn't worth mentioning.
In my opinion this should work, but the thing is while movement direction is changin at normal speed, my rectangle is spinning wildly, probably about 100 times or so faster than its movement direction.
Delta is the number of milliseconds since the last call to update().
Related
I've been trying from hours to setup gravity and relate it to time or what we call frame independent bounce ball. I did everything correct I guess, and I tried to implement the system where height of ball would decrease after every bounce. I did not even start that, and my code is creating something absurd I don't understand why. Here's my code:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentFrame = System.currentTimeMillis();
dt = currentFrame - lastFrame;
dt = dt/1000;
lastFrame = currentFrame;
myFreakinRect.set(0,0, canvas.getWidth(), canvas.getHeight());
freakinRed.setColor(Color.RED);
freakinRed.setStyle(Paint.Style.FILL);
canvas.drawRect(myFreakinRect, freakinRed);
//
// o yuea
if(goingDown) {
//velocityY = Math.sqrt(100 + 2*gravity*(posY));
velocityY = gravity*(currentFrame - runTime);
} else {
velocityY = downV - gravity*(currentFrame - runTime);
}
if(posX > w - ballRadius*2) {
goingRight = false;
}
if(posX < 0) {
goingRight = true;
}
if(posY > h - ballRadius*2) {
//initY = initY - 0.25F;
//if(initY < 0) initY = 0;
Log.i("xxx", String.valueOf(initY));
runTime = currentFrame;
downV = velocityY;
goingDown = false;
}
if(velocityY <= 0) {
goingDown = true;
runTime = currentFrame;
}
if(goingDown) posY += velocityY*dt;
else posY -= velocityY*dt;
if(goingRight) posX += velocityX*dt;
else posX -= velocityX*dt;
canvas.drawText(String.valueOf(posX)+" "+String.valueOf(posY), 10, 10, new Paint());
canvas.drawBitmap(rBall, (float)posX, (float)posY, myFreakingFaintPaint);
invalidate();
}
Here's a GIF what is happening:
UPDATE:
Here's my updated code which is clean, understandable and works perfect:
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
currentFrame = System.currentTimeMillis();
dt = currentFrame - lastFrame;
dt = dt/1000;
lastFrame = currentFrame;
velocityY = downV + gravity*(currentFrame - runTime);
posY += velocityY*dt;
posX += velocityX*dt;
if(posX > w - ballRadius*2 || posX < 0) {
velocityX = -velocityX;
}
if(posY >= h - ballRadius*2) {
posY = h - ballRadius*2 - 2;
runTime = currentFrame;
downV = -0.8*velocityY;
}
canvas.drawBitmap(rBall, (float)posX, (float)posY, null);
invalidate();
}
Here ...
if(goingDown) {
//velocityY = Math.sqrt(100 + 2*gravity*(posY));
velocityY = gravity*(currentFrame - runTime);
} else {
velocityY = downV - gravity*(currentFrame - runTime);
}
... you update the velocity (speed, actually) assuming that the ball will not bounce during this frame.
Then here ...
if(posY > h - ballRadius*2) {
//initY = initY - 0.25F;
//if(initY < 0) initY = 0;
Log.i("xxx", String.valueOf(initY));
runTime = currentFrame;
downV = velocityY;
goingDown = false;
}
... you have not yet updated posY, so you are determining whether the ball hit the floor as a result of the previous update. If it did, you reverse the direction of motion, but keep the speed you already computed for this frame. As a result, each time the ball bounces, its initial upward speed is one frame's worth of acceleration greater than the speed it was traveling when it hit the floor.
You have a similar effect at the top of the ball's motion, but it's smaller because the speed is small there.
There are a couple of ways you might solve this problem. The simplest is probably to perform the bounce check after the position update instead of before.
Additional notes:
use the signs of your X and Y speeds instead of separate direction-of-motion flags (thus making the names velocityY etc. accurate). Your code will be simpler, and you'll need to handle only one change of vertical direction, not two, because the equations of motion will handle the other automatically.
you have a bit of a precision problem because you assume that the ball travels in the same direction for a whole frame. This may become noticeable if you allow the ball to reach high speeds: it will appear to penetrate the floor before bouncing back up.
this computation is suspicious: dt = dt/1000. Since dt seems to be computed from System.currentTimeMillis(), I am inclined to guess that it, too, has type long. In that case, you are performing an integer division and thereby losing precision.
In general:
Split up into model and view. In that case the rendering still runs fine, because the calculations are pretty light-weight, but you shouldn't run code inside the rendering-routine that isn't directly related to painting something.
Next point:
Stay as close to reality as possible, if you simulate physics. You can always optimize afterwards, but first make sure your code is actually doing what it's supposed to do. I'm currently playing a bit around with projectile-motion, so I've got a basic idea of what the code is supposed to do. I've been attempting to understand yout code for 10 mins so far. Interim result: I'm confused and don't quite get it.
My suggestion:
Start off with clearer code and try to stick as close to physical rules as possible. This code isn't optimized as far as it could be, but it's readable, understandable and simulates close enough to the real life. That makes it a lot simpler to debug:
final double GRAVITY = -9.81;
final double BALL_ELASTICITY = 0.95;
double vx, vy;
double x, y;
//dt is delta-time in seconds!!!
void simulateBall(double dt){
//calculate when the ball will touch the floor the next time
double next_floor_touch = (-vy + Math.sqrt(vy * vy - 2 * GRAVITY * y)) / GRAVITY;
double after_floor_touch = dt - next_floor_touch;
boolean touches_floor = (next_floor_touch <= dt);
//calculate new y
if(touches_floor){
//predict the speed the ball will have, after it bounces from the floor
double vy_at_floor = vy + GRAVITY * next_floor_touch;
double vy_from_floor = vy_at_floor * (-1) * BALL_ELASTICITY;
//predict y starting from the floor at t = next_floor_touch until dt
y = 0 + vy_from_floor * after_floor_touch + 0.5 * GRAVITY * after_floor_touch * after_floor_touch;
}else{
//uniform acceleration
y = y + vy * dt + 0.5 * GRAVITY * dt * dt;
}
//calculate vy
if(touches_floor){
//see above
double vy_after_floor = (vy + GRAVITY * next_floor_touch) * (-1) * BALL_ELASTICITY;
vy = vy_after_floor + GRAVITY * after_floor_touch;
}else{
vy = vy + GRAVITY * dt;
}
... //that's already the hardest part
}
This uses the quadratic equation to predict when the ball will hit the floor and uniform acceleration to calculate the position from a given position, speed and acceleration. Unless I've made any mistakes in my calculation (this code is not tested), this should be physically precise. BALL_ELASTICITY represents how much of the speed is left, after the ball hits the floor. That's not physically precise - might be, IDK - , but should do for this purpose.
I am trying to make a sprite walk to the mouse position. However, when the mouse is clicked and the sprite walks to the mouse position, it won't stop and keeps moving in the same direction.
Here's my code:
public void render(float delta) {
Gdx.gl.glClearColor(1,1,1,1);
Gdx.gl.glClear(GL30.GL_COLOR_BUFFER_BIT);
if(Gdx.input.isTouched()){
projected= new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
cam.unproject(projected);
if(position.x != projected.x || position.y != projected.y){
pathX = projected.x - position.x;
pathY = projected.y - position.y;
distance = (float) Math.sqrt(pathX * pathX + pathY * pathY);
directionX = pathX / distance;
directionY = pathY / distance;
}
}
position.x += directionX * Speed * delta;
position.y += directionY * Speed * delta;
}
Please help and thank you so much.
This is basically a duplicate of How to stop drawing a SpriteBatch animation in libgdx? || how do I pause the SpriteAnimation in libGDX with a button to be able to view the current frame when pause button is pressed? , check out this article to see if it helps.
In short, you want to keep track of the player moving and when they get to the x, y coordinates of your mouse, set the moving to false. Have the logic within your render to only render when your boolean is true.
I am trying to get my bullets to fire towards (input coords) at a constant speed.
So far I was able to get it to shoot at the direction but the farther I click (touch, android game) the faster the bullet goes. I have tried different methods by scaling but failed miserably, I have started coding just a month ago and using this as a project to increase my knowledge of how things work before I work on a full game but having too much trouble with this.
This is what I have been using to get the bullet to move towards the direction I want it to, the codes with // in front were other samples I got while browsing through the internet in hopes of getting what I wanted. I have thought of not using velocity to set the direction, but I have no clue of another method for this.
EDIT: All in short, I cannot get all the bullets to move in the same speed, farther I click, higher velocity bullet has.
Any help guys? Thanks a bunch
Player Class :
public void update(float delta) {
if (Gdx.input.isTouched()) {
if (System.currentTimeMillis() - lastShot >= FIRE_RATE) {
bullets.add(new Bullet(position.x + 6,position.y + 6,4,4,Gdx.input.getX() / 2,Gdx.input.getY() / 2));
lastShot = System.currentTimeMillis();
}
}
for (int i=0;i<bullets.size();i++) {
bullets.get(i).update(delta);
}
}
Bullet Class :
public Bullet(float x, float y, int width, int height, float targetX, float targetY) {
this.width = width;
this.height = height;
position = new Vector2( x , y );
velocity = new Vector2( 0 , 0 );
velocity.set(targetX - position.x,targetY - position.y);
//velocity.set(targetX - position.x, targetY - position.y).nor().scl(Math.min(position.dst(targetX, targetY), speedMax));
}
public void update(float deltaTime) {
//position.add(position.x + speedMax * deltaTime * ax,position.y + speedMax * deltaTime * ay);
position.add(velocity.x * deltaTime, velocity.y * deltaTime);
//velocity.scl(1 - (0.98f * deltaTime));
// Linear dampening, otherwise the ball will keep going at the original velocity forever
}
Well, normalizing vectors should be rather straightforward. Take your components, square them, and add them together (pythagorean theorem) and then divide each component by this result. I.e. vX = (targetX - position.x)/Math.sqrt(((targetX - position.x) * (targetX - position.x)) + ((targetY - position.y) *(targetY - position.y )))
Then you can multiply vX by some constant, and do the same for a vY and then set your velocity.
I've noticed some very strange behaviour with a simple piece of code, I've stripped it down to remove any variables, time-step, acceleration, etc.
I have a shape on the screen, pressing the left side of the screen thrusts the shape right, pressing the right side thrusts left. For some reason the shape favours moving left (speed < 0). It seems to be that it decelerates properly when moving right but when moving left it finishes decelerating then continues for maybe 0.3 seconds before stopping.
float speed;
int x;
Update method for the shape:
speed *= 0.9f;
if (Math.abs(speed) < 0.1f)
speed = 0;
if (Gdx.input.isTouched()) {
if (Gdx.input.getX() < Gdx.graphics.getWidth() / 2) {
speed = 10;
} else {
speed = -10;
}
}
x += speed;
x should be defined as float. I used int because the viewport is set to the screen size but finally realised it needs to have the precision.
So i'm just trying to make a ball bounce around the screen which should slow down due to gravity and reflect (bounce) from the wall like a normal ball would.
Can someone give some basics and VERY simple implementation of this?
Other examples seem a bit "overdone" and seem to go beyond what I want to do.
I've tried this:
public void updateLogic() {
if (x < -1) {
xPos += (-x * gravity);
} else if (x > 1) {
xPos -= (x * gravity);
}
if (y > 1) {
yPos += (y * gravity);
} else if (y < -1) {
yPos -= (-y * gravity);
}
}
This is the closest I got by myself.
By the way the x and y values are from the accelerometer.
Any help would be much appreciated, thanks!
I think you'll need 3 things for this, forces (x and y, which you have), velocities (call them xVel and yVel) and positions (xPos and yPos which you also have). The position of the ball is updated (in the simplest way) by:
xPos += dt*xVel;
yPos += dt*yVel;
xVel += dt*x;
yVel += dt*y;
The variable 'dt' is the timestep, which controls how fast the ball will move. If this is set too large, though, the program will be unstable! Try dt = 0.001 or so to start and gradually set it higher.
Then, to get the ball to reflect from the walls, just flip the velocity if it hits a wall:
if (xPos > xMax) {
xPos = xMax;
xVel *= -1.0;
} else if (xPos < 0.0) {
xPos = 0.0;
xVel *= -1.0;
}
and the same for y. The 'xPos = ...' is just to stop the ball going off the edge of the screen. If you'd like the ball to bounce a little less every time it hits a wall, change the '-1.0' to '-0.9' or something (this is the coefficient of restitution).
Hopefully that should be all. Good luck!
Some comments on your actual code:
Both of these lines do exactly the same thing:
yPos -= (-y * gravity);
yPos += (y * gravity);
likewise, both of these lines do the same thing:
xPos += (-x * gravity);
xPos -= (x * gravity);
You are not handling the cases -1 <= x <= 1 or -1 <= y <= 1
Some comments on the concepts:
Start with one ball.
You want the ball to have two separate velocities (both either positive or negative), one in the x-direction and one in the y-direction. Every frame, add those velocities to the ball's position.
Then add collision detection. Check each frame if the center of the ball is outside the screen. If it is, make it bounce (the easiest way to do this is to make the ball's y-velocity positive when it goes off the most-negative y-value displayed on the screen; and do similarly for the other screen-edges).
Improve the collision detection: see if you can figure out how to check if any part of the ball it outside the screen (hint: to check if the ball is off the left-side of the screen, you only need to check the left-most coordinate of the ball)
Then take gravity into consideration - gravity will be a constant number subtracted from the y-velocity every frame, until the y-velocity hits 0.
Youtube video
Source code available at github.
Your x coordinate should not be affected by gravity.
I would advise against using accelerometers until you understand how the physics work for the simple case.
Break it up into stages. First, ensure that you can get the ball falling at a constant velocity.
Once you have that working, worry about the gravity causing the velocity to increase.
Once you have that working, worry about the intersection with walls and velocity changes. A simple algorithm for bouncing off the walls would be to multiply the x velocity by -1 when you hit a vertical wall, and multiply the y velocity by -1 when you hit a horizontal wall.