I have a game that is almost done but I forgot about gravity and impulse, i did not want to implement box2d and i got the gravity to work, but can some body explain how to apply an impulse without box2d?
You can simulate an impulse just by adding a velocity to the objects velocity. Like that:
class GameObject {
private Vector2 velocity = new Vector2();
public void applyImpulse(Vector2 impulse) {
velocity.add(impulse);
}
public void update(float deltaTime) {
float dampingPerSecond = 0.5f;
float dampingFactor = Math.max(0f, 1 - deltaTime*dampingPerSecond);
velocity.scl(dampingFactor);
}
}
Now you might use it like this: object.applyImpulse(new Vector2(3, 2));. In case you update all your GameObjects in every frame, your object will slow down after an impulse was given. Which is what you would expect to happen, if no further impulses hit your object. Doing this in a realistic way though is difficult and might only be achieved by using box2d. You might however tweak that and hope that it will work in your game. Remember to always apply your gravity after that though.
Related
I am working on a project in LibGDX, and I am using Scene2D actors for some of my sprites. In this regard, I have a sprite, which is spawning somewhere on the screen and needs to move to another position on the screen. To do this I am using the moveTo(xPos, yPos, duration, interpolation) method in the Actions, to make the move animation.
However, when I use this approach, the actor moves like I told it to, but it only moves in a straight line, from point A to B. I have tried several Interpolation options, like Circle interpolation and such, but it seems only to impact the speed of the animation line.
So now my question: How do I make my animation make a smooth curved line (See picture), from A to B?
I am currently using this code to make the Actions animation:
adultCustomerPointActor.addAction(Actions.sequence(
Actions.moveTo(300, 200, 2f, Interpolation.circle)
));
Thanks in advance for your help :)
It's a geometry problem. Using vectors, find the point halfway between the two points:
vec1.set(bx, by).sub(ax, ay).scl(0.5f).add(ax, ay);
Get another vector that is 90 or 270 to from the vector between the points:
vec2.set(bx, by).sub(ax, ay).rotate90().add(vec1);
This vec2 can be scaled to adjust how extreme curvature of the arc is. If you leave it alone, you'll have a quarter circle. You can also scale it negative to reverse the curvature.
Then add the second vector to the first to find the center point of your arc, which we can call point C.
vec1.set(bx, by).sub(vec2); // CB
vec3.set(ax, ay).sub(vec2); // CA
float angle = vec1.angle(vec3);
Now you need a vector that points from point C to point A. You will rotate this vector until it reaches point B. So you need the angle between CA and CB.
So here's a very simplistic class that implements this. It doesn't account yet for deciding if you want the arc to go up or down and if you want to scale how extreme it looks. You could add those as additional parameters with getters/setters. I haven't tested it, so it may need some debugging.
public class ArcToAction extends MoveToAction {
private float angle;
private final Vector2 vec1 = new Vector2(), vec2 = new Vector2(), vec3 = new Vector2();
#Override
protected void begin () {
super.begin();
float ax = target.getX(getAlignment()); // have to recalculate these because private in parent
float ay = target.getY(getAlignment());
vec1.set(getX(), getY()).sub(ax, ay);
vec2.set(vec1).rotate90();
vec1.scl(0.5f).add(ax, ay);
vec2.add(vec1);
vec1.set(bx, by).sub(vec2); // CB
vec3.set(ax, ay).sub(vec2); // CA
angle = vec1.angle(vec3);
}
protected void update (float percent) {
if (percent >= 1){
target.setPosition(getX(), getY(), getAlignment());
return;
}
vec1.set(vec3).rotate(percent * angle);
target.setPosition(vec1.x, vec1.y, getAlignment());
}
}
If you want to support automatic pooling, you can add a method like this:
static public ArcToAction arcTo (float x, float y, float duration, Interpolation interpolation) {
ArcToAction action = Actions.action(ArcToAction .class);
action.setPosition(x, y);
action.setDuration(duration);
action.setInterpolation(interpolation);
return action;
}
Problem: my player model is supposed to turn into the direction of the last mouse click but instead of turning slowly it spins in all possible ways(Game has an isometric view, the model is supposed to rotate only around the Y-axis but it rotates around the X- and Z-axis too).
Following method(called in render()) is responsible for the turning behavior of the model:
public static void turnUnit(){
if(Gdx.input.isButtonPressed(Input.Buttons.LEFT)){
mX = Gdx.input.getX();
mY = Gdx.input.getY();
angle = (float) (180+Math.atan2(mX-Gdx.graphics.getWidth()/2, mY-Gdx.graphics.getHeight()/2)*(180/Math.PI));
newAngle = ((((currentAngle - angle) % 360) + 540) % 360) - 180;
turning = newAngle/60*turnRate;
currentAngle = currentAngle-turning;
}
TestGround.player.transform.setToRotation(Vector3.Y, currentAngle).setTranslation(posX,0,posZ);
}
And the movement-method(also called in render()):
public static void movement(){
if(northM==true){
TestGround.player.transform.trn(0,0,-1f);
}
if(southM==true){
TestGround.player.transform.trn(0,0,1f);
}
if(westM==true){
TestGround.player.transform.trn(-1f,0,0);
}
if(eastM==true){
TestGround.player.transform.trn(1f,0,0);
}
posX = TestGround.player.transform.getTranslation(Vector3.X).x;
posY = TestGround.player.transform.getTranslation(Vector3.Y).y;
posZ = TestGround.player.transform.getTranslation(Vector3.Z).z;
}
Tried to use "rotate" in the last line but then it just spins faster.
Also, even though this makes no sense to me but after some testing it seems the movement-method somehow interferes with the turn-method(moving in a certain direction will rotate the model in a certain way).
Am I doing something fundamentally wrong here?
Additional Info:
originally I used simple polling to get all keyboard and mouse input
calculated movement/rotation in one big method and everything worked
fine
decided to use the inputprocessor of libgdx to make the code more readable and open-ended
The Matrix4#getTranslation(Vector3) method will set the specified vector to the translation component of the matrix and return it for chaining. What this means is that the vector you supply as argument to the TestGround.player.transform.getTranslation(vector) method, will be set (read: overwritten) to the translation (position) of the model instance.
So, in the case of the call to:
TestGround.player.transform.getTranslation(Vector3.Y)
This will practically modify the Vector3.Y variable from the default [x:0, y:1, z:0], to whatever the translation component of the matrix is set to. This will result in any other call that uses the Vector3.Y variable (like your call to setToRotation) to behave differently.
To fix that you can modify the last few lines to:
Vector3 pos = new Vector3();
TestGround.player.transform.getTranslation(pos);
posX = pos.x;
posY = pos.y;
posZ = pos.z;
Note that you should move the creation of the Vector3 out of the method and therefor might as well remove the posX, posY and posZ members in favor of the pos member.
So, you might be wondering two questions:
Why does the getTranslation method modify its arguments? This is because libGDX is designed to avoid creating garbage, because that will create hick-ups on some platforms, like Android. So instead of creating a new Vector3 every time the method is called, it allows you to specify an instance of that class which you want to reuse. You will see this pattern throughout the lib at multiple places because of this reason.
Why is it even possible to modify Vector3.Y, making it useless and cause all kind of problems? This is because the Vector3 class is mutable and does not encapsulate its members. So practically it allows you to do vector.x += 3; instead of forcing you to call vector.setX(vector.getX() + 3);. This is both for readability and performance reasons (although the latter might vary on your target platform). Also, java does not support something comparable to const.
I'm trying to make a simple bit of code that will detect whether a model was clicked on. So far the best method I've seen is to create some sort of rectangle around the mesh and detect with Gdx.input.justTouched() to get the x,y coordinates, and then check if the rectangle contains the coordinates returned by justTouched().
I have no idea if there's a better way to do this, some kind of mesh onClick listener or something that LibGDX has in place that I'm unaware of (I've been scouring Google and the javadocs but I can't seem to find anything). I don't really need to deal with the z-axis coordinate, at least I don't think so. I only have the one PerspectiveCamera and it's not going to be moving around that much (not sure if this matters?)
Anyways, in my render() method I have:
if (Gdx.input.justTouched()) {
//this returns the correct values relative to the screen size
Vector2 pos = new Vector2(Gdx.input.getX(), Gdx.input.getY());
//I'm not sure how to get the correct rectangle to see what the
//width and height are for the model relative to the screen?
Rectangle modelBounds = new Rectangle(<<not sure what to put here>>);
if (modelBounds.contains(pos.x, pos.y) {
System.out.println("Model is being touched at: " + pos.x + ", " + pos.y);
}
}
I'm really not sure if this is the correct way to do this. I can get the position of the model with:
modelInstance.getNode("Node1").globalTransform.getTranslation(new Vector3());
but I'm not sure how to get the width and height as a rectangle relative to the screen size, if it's even possible.
I'm also unsure if this would cause massive lag, as I'm going to have about 7 nodes total that I need to detect if they're clicked on or not.
Is there a better way to do this? If not, is there a way to get the model width & height relative to the screensize (or camera, maybe)?
EDIT: Read about using Bounding Boxes, seems like what I need. Not quite sure how to implement it properly, however. I've changed my code to such:
public ModelInstance modelInstance;
public BoundingBox modelBounds;
#Override
public void create() {
...
//omitted irrelevant bits of code
modelInstance = new ModelInstance(heatExchangerModel);
modelBounds = modelInstance.calculateBoundingBox(new BoundingBox());
}
#Override
public void render() {
...
if (Gdx.input.justTouched()) {
Vector3 pos = new Vector3(Gdx.input.getX(), Gdx.input.getY(), 0);
System.out.println(pos);
if (modelBounds.contains(pos)) {
System.out.println("Touching the model");
}
}
}
I'm not really sure what the output of BoundingBox is supposed to be, or how the numbers it gives me correlates to the position in a 2d space. Hmm..
EDIT2: Think I'm getting closer.. Read about Rays and the .getPickRay method for my PerspectiveCamera. .getPickRay seems to return completely unusable numbers though, like really tiny numbers. I think I need to do something like:
if (Gdx.input.justTouched()) {
Vector3 intersection = new Vector3();
Ray pickRay = perspectiveCamera.getPickRay(Gdx.input.getX(), Gdx.input.getY());
Intersector.intersectRayBounds(pickRay, modelBounds, intersection);
}
and then intersection should give me the point where they overlap. It appears to be not working, however, giving me really small numbers like (4.8066642E-5, 2.9180354E-5, 1.0) .. hmmm..
I am trying to re-create Pong using LibGDX and Box2D. I have 2 problems, if I fix one it creates another.
My paddles are currently set to Kinematic and are controlled using the up/down keys via a controller class. This works just fine and I can happily play back and forth.
Problem being, my walls are static bodies and my paddles just travel right through them.
Now I can fix this by simple changing the paddle body to a dynamic one, this stops the paddles from going through the walls but then when my ball strikes off a paddle, it goes flying off the X axis and off the screen.
I have tried adding an update method in my controller class as follows:
public void update(float delta){
paddleBodyPosY = paddleBody.getPosition().x;
paddleBodyPosY = paddleBody.getPosition().y;
System.out.println(paddleBodyPosY);
}
The console reports the paddle position being updated every frame, from top to bottom of screen.
So I went back to my GameScreen class and tried all sorts of code in the Render() method like so:
if(playerOnePaddle.paddleBodyPosY < 0){
playerOnePaddle.paddleBody.getPosition().y = 0;
System.out.println("resetting paddle");
}
I have tried LOADS of variations, I can easily break movement by calling paddleBody.setLinearVelocity(0,0) but then it gets stuck like this and it's not movable anymore. Obviously the problem must lie with the fact that I can't set a position using a getter lol.
Any ideas? If you need more snippets ask, I didn't want to overload the question with 100 lines of code you don't need to see :S.
The paddle creation method:
public void createPaddle(World world, float x, float y){
//Define a body for the paddle
BodyDef paddleBodyDef = new BodyDef();
paddleBodyDef.type = BodyType.KinematicBody;
paddleBodyDef.position.set(x, y);
//Define a shape for the paddle
PolygonShape paddleShape = new PolygonShape();
paddleShape.setAsBox(paddleWidth, paddleHeight);
//Define a fixture for the paddle
FixtureDef paddleFixtureDef = new FixtureDef();
paddleFixtureDef.shape = paddleShape;
paddleFixtureDef.density = 0;
//Ensures ball bounces off paddle
//Consistently without losing velocity
paddleFixtureDef.restitution = 1.005f;
//Create the paddles
paddleBody = world.createBody(paddleBodyDef);
paddleFixture = paddleBody.createFixture(paddleFixtureDef);
paddleShape.dispose();
}
Heh, so what I did was.
Set my paddles to dynamic, then set there mass to a stupidly high number so that the a ball would not move them on the x axis, well not enough for the human eye to see at least.
Seems like a cheap fix, if anyone has anything better...that would be great lol
in libgdx game
I want to touchDown and then drag somewhere and then on the release (touchUp) apply a directional force based on the distance and direction from the target body. When you touchdown the target body stays still and then on touchup the force is applied along the desired trajectory.
(very similar to Angry birds - where you get to see the trajectory in dotted lines for the target body when you hold hack the slingshot - I want to do the same)
So I guess that this might not be the hardest thing to do but given a few options Im leaning towards using a MouseJointDef but its an immediate force applied (i.e. the target moves immediately - I want it to stay still and then once the touchup event happens then apply the force)
Whats the easiest way to draw the trajectory also? Im using Box2D also.
Create a class that inherits InputAdapter class, then create an instance of it and register it to listen the touch inputs.
Gdx.input.setInputProcessor(inputAdapter);
There are 3 methods to handle the touch events touch_down, touch_dragged and touch_up that you have to override.
In touch_down, check the touching position to whether is in the birds area or not. If it is, make a boolean flag true.
In touch_dragged, check the flag above and if it was true, calculate the distance of the touch position relative to the bird shooting center and the shooting angle.
In touch_up, you can order to shoot with the calculated amounts by calling
body2shoot.applyLinearImpulse(impulse, body2shoot.getWorldCenter());
There is no need to MouseJointDef to move the body2shoot. Just set the transform of body2shoot in touching position to be dragged in each cycle of render.
For calculating the trajectory I wrote a class like this:
public class ProjectileEquation
{
public float gravity;
public Vector2 startVelocity = new Vector2();
public Vector2 startPoint = new Vector2();
public ProjectileEquation()
{ }
public float getX(float t)
{
return startVelocity.x*t + startPoint.x;
}
public float getY(float t)
{
return 0.5f*gravity*t*t + startVelocity.y*t + startPoint.y;
}
}
and for drawing it just I set the startPoint and startVelocity and then in a loop I give a t (time) incrementally and call getX(t) and getY(t).