I made a body which I want to move when a button is clicked, I have been able to move the body using body.setLinearVelocity() but it's not accurate. Let's say I want to move my body for seven meters with a linear X velocity of 40, how do I do that?
//BODY MOVEMENT
//timer = I try to move the body for a certain amount of time
/*isMoveRight and isMoveLeft are Just booleans for activating and deactivating movement*/
if(Gdx.input.isKeyJustPressed(Input.Keys.RIGHT)){
timer = 0f;
isMoveRight = true;
isMoveLeft = false;
}else if(Gdx.input.isKeyJustPressed(Input.Keys.LEFT)){
timer = 0f;
isMoveLeft = true;
isMoveRight = false;
}
if(isMoveRight == true && timer < 0.1f){
timer += 1f * delta; //activate timer
body.setLinearVelocity(52f, 0f);
}else if(isMoveLeft == true && timer < 0.1f){
timer += 1 * delta;
body.setLinearVelocity(-52f, 0f);
}
I could just use body.setTransform() but I need the body to actually move and not to teleport. Thank you in advance
I don't know how complete your code sample is but from waht I see here, you are at least missing the part where you reset the velocity to 0 after 0.1 seconds.
else {
body.setLinearVelocity(0F, 0F);
}
Apart from that your method has a slight vagueness in the moved distance because dependent on your frame rate your check timer < 0.1f is not very exact:
timer = 0.099 -> distance = 5.148
timer = 0.132 -> distance = 6.881 (one frame later with 30 frames/second)
Some (untested) ideas how to handle this problem:
Use a RopeJoint to enforce a maximum distance between the body and the starting point (which has to be a body as well in this case)
Measure the distance (use the Vector2 class) and teleport it back to the point at max distance if needed. (You should use the distance instead of the timer anyway)
Slow your body down if it gets close to the target, this will at least help to reduce the error
Related
I'm building a LibGDX game and need to zoom the camera in and out. But when I do camera.zoom = 1.2f;, it just 'jumps' to that value. Instead, I want to have a smooth zoom.
My question:
What's the best way to smoothly zoom?
I want to zoom like this graph below. y=0 is the start cam.zoom, y=100 is the desired cam.zoom and the x-axis shows the time.
Should I use cam.zoom = f(time);? (With some modification to f(x))
time is the total time passed since the beginning of the zoom.
Or is it better to use:
cam.zoom += (desiredZoom - cam.zoom) * delta * scalar;
delta is the time between two frames and scalar is a float that will be adjusted in order to set the speed.
Or is there another, better way? What do you think?
Thanks a lot!
Simplest way I know is use a countdown with an Interpolation.
// member variables:
float timeToCameraZoomTarget, cameraZoomTarget, cameraZoomOrigin, cameraZoomDuration;
private float zoomTo (float newZoom, float duration){
cameraZoomOrigin = camera.zoom;
cameraZoomTarget = newZoom;
timeToCameraZoomTarget = cameraZoomDuration = duration;
}
// in render():
if (timeToCameraZoomTarget >= 0){
timeToCameraZoomTarget -= deltaTime;
float progress = timeToCameraZoomTarget < 0 ? 1 : 1f - timeToCameraZoomTarget / cameraZoomDuration;
camera.zoom = Interpolation.pow3out.apply(cameraZoomOrigin, cameraZoomTarget, progress);
}
You can replace Interpolation.pow3out with any of the functions pictured here.
You can use the MathUtils.lerp method.
Example:
MathUtils.lerp(currentZoom,targetZoom,progress);
Increase the progress value to change faster or lower to slow down speed the value changes.
I'm making a 2d game in libgdx and I would like to know what the standard way of moving (translating between two known points) on the screen is.
On a button press, I am trying to animate a diagonal movement of a sprite between two points. I know the x and y coordinates of start and finish point. However I can't figure out the maths that determines where the texture should be in between on each call to render. At the moment my algorithm is sort of like:
textureProperty = new TextureProperty();
firstPtX = textureProperty.currentLocationX
firstPtY = textureProperty.currentLocationY
nextPtX = textureProperty.getNextLocationX()
nextPtX = textureProperty.getNextLocationX()
diffX = nextPtX - firstPtX
diffY = nextPtY - firstPtY
deltaX = diffX/speedFactor // Arbitrary, controlls speed of the translation
deltaX = diffX/speedFactor
renderLocX = textureProperty.renderLocX()
renderLocY = textureProperty.renderLocY()
if(textureProperty.getFirstPoint() != textureProperty.getNextPoint()){
animating = true
}
if (animating) {
newLocationX = renderLocX + deltaX
newLocationY = renderLocY + deltaY
textureProperty.setRenderPoint(renderLocX, renderLocY)
}
if (textureProperty.getRenderPoint() == textureProperty.getNextPoint()){
animating = false
textureProperty.setFirstPoint(textureProperty.getNextPoint())
}
batch.draw(texture, textureProperty.renderLocX(), textureProperty.renderLocY())
However, I can foresee a few issues with this code.
1) Since pixels are integers, if I divide that number by something that doesn't go evenly, it will round. 2) as a result of number 1, it will miss the target.
Also when I do test the animation, the objects moving from point1, miss by a long shot, which suggests something may be wrong with my maths.
Here is what I mean graphically:
Desired outcome:
Actual outcome:
Surely this is a standard problem. I welcome any suggestions.
Let's say you have start coordinates X1,Y1 and end coordinates X2,Y2. And let's say you have some variable p which holds percantage of passed path. So if p == 0 that means you are at X1,Y1 and if p == 100 that means you are at X2, Y2 and if 0<p<100 you are somewhere in between. In that case you can calculate current coordinates depending on p like:
X = X1 + ((X2 - X1)*p)/100;
Y = Y1 + ((Y2 - Y1)*p)/100;
So, you are not basing current coords on previous one, but you always calculate depending on start and end point and percentage of passed path.
First of all you need a Vector2 direction, giving the direction between the 2 points.
This Vector should be normalized, so that it's length is 1:
Vector2 dir = new Vector2(x2-x1,y2-y1).nor();
Then in the render method you need to move the object, which means you need to change it's position. You have the speed (given in distance/seconds), a normalized Vector, giving the direction, and the time since the last update.
So the new position can be calculated like this:
position.x += speed * delta * dir.x;
position.y += speed * delta * dir.y;
Now you only need to limit the position to the target position, so that you don't go to far:
boolean stop = false;
if (position.x >= target.x) {
position.x = target.x;
stop = true;
}
if (position.y >= target.y) {
position.y = target.y;
stop = true;
}
Now to the pixel-problem:
Do not use pixels! Using pixels will make your game resolution dependent.
Use Libgdx Viewport and Camera instead.
This alows you do calculate everything in you own world unit (for example meters) and Libgdx will convert it for you.
I didn't saw any big errors, tho' i saw some like you are comparing two objects using == and !=, But i suggest u to use a.equals(b) and !a.equals(b) like that. And secondly i found that your renderLock coords are always being set same in textureProperty.setRenderPoint(renderLocX, renderLocY) you are assigning the same back. Maybe you were supposed to use newLocation coords.
BTW Thanks for your code, i was searching Something that i got by you <3
I have a body following my player in a game I made and the player is of type Actor (scene2D). In his overriding act method he uses libgdx input to move. For example,(pseudo) if(gdxInput.keys(keys.up)){ applyForceToCenter(VElocity) xCoor = body.x yCoor = body.y
How do I make sure the body doesn't slide all over the place? The world has a gravity of 0,0 so if i click the up arrow the player will never stop so in my huge if else if block statement of input i put else linearVelocity = 0 this works however if the player is holding the right arrow key then holds the up arrow key the player moves right more then up as if he is sliding on ice. Please tell me how to turn all gravity off of the player in general. I can't just set the position of the body because im using the bodies as a way of collision and to set the position of the body is to turn off collision.
As soon as you want to stop you will set the velocity to 0 for example
if(!canFall){
velocity.y = 0;
}else
velocity.y += MainScreen.GRAVITY.y;
if(Gdx.input.isKeyPressed(Keys.A)){
velocity.x -= 10 * Gdx.graphics.getDeltaTime();
}
else if(Gdx.input.isKeyPressed(Keys.D)){
velocity.x += 10 * Gdx.graphics.getDeltaTime();
}else
velocity.x = 0;
So once you stop ur velocity will be equal to 0!
Have you got any damping set on your player body?
playerBody.SetLinearDamping(0.2f);
This will reduce positional forces to 0 over time if you're not applying anything to your playerBody.
Right now my code is as follows:
if(Gdx.input.justTouched()) {
if(cl.isPlayerOnGround()) {
playerBody.applyForceToCenter(0, B2DVars.jumpForce, true);
}
}
It works for the most part, however if you click both mouse buttons at the same time on desktop, or multitouch on android, the jumpForce gets multiplied. I need to ignore all clicks/taps but the first until the player touches the ground again.
(cl is the contact listener.)
There are a number of ways to solve this but in my option the best way to solve this is to limit how often a jumpForce can be applied. This will likely prevent other problems down the road.
//class var
float lastJumpForceTime = 0.5f; // start at 0.5f to enable jumping from the start
float jumpForceDelay = 0.5f; // delay between jumps, 0.5f = half second
//method that calls your code
//delta time is the time since last update LibGDX provides this but you will need to pass it
public void yourMethod(float deltaTime, ...){
lastJumpForceTime += deltaTime; // update last jump time
// check if player is on ground and if time since last jump is > delay
if(cl.isPlayerOnGround() && lastJumpForceTime >= jumpForceDelay){
lastJumpForceTime = 0.0f;
playerBody.applyForceToCenter(0, B2DVars.jumpForce, true);
}
}
Hey I am trying to figure out the best way to implement gravity in my program that is simply a ball bouncing. The program uses a method that is called 50 times a second (the rate at which the gametimer ticks) and in this method I call the gravity method. In the gravity method I currently have
public void Gravity(){
this.currentPositionY = this.currentPositionY + 9;
if (this.currentPositionY >= 581){
this.currentPositionY=581;
}
}
Problems with my code: In gravity velocity is not constant it varies with the time, but I am unsure of how to implement time with the gravity method being called so often. Also currently I have it so that the ball stops at 581, so that it does not fall through the screen. How would I implement a bounce that is higher when the ball falls for longer and shorter when the ball falls less? Thanks for your time!
Have a variable outside of the method for its y-velocity. Every tick, increase its velocity accounting for gravity.
If the ball is past a boundary, set it to the boundary and set the velocity to -1*velocity to make it "bounce" in the other direction.
Maybe something like this:
private int currentVelocityY = 0;
private int gravity = 3;
public void Gravity(){
this.currentPositionY = this.currentPositionY + this.currentVelocityY;
if (this.currentPositionY >= 581){
this.currentPositionY=581;
this.currentVelocityY = -1 * this.currentVelocityY;
}
currentVelocityY = currentVelocityY + gravity;
}