Box2D - Controlled Movement with Physics - java

I am creating a Java desktop 2D Game using LibGDX.
I need to be able to move objects (controlled by the player with W/A/S/D).
The movement speed is always the same (read out from a field of the moving object).
While they are moving, they should still be affected by physics.
This means that when moving away from a magnet would make you move slower, moving towards it makes you faster and moving past it would cause you to move a curve. (see blue part of image)
Also a single impulse in while moving would knock you away but you keep moving (see red part of image)
You should also be able to change direction or stop, only stopping your own movement, so you will still be affected by physics.
So I need to apply constant forces that will still be accessible (and removable) after the next step.
Can I do this with Box2D?
-If yes, how?
-If no, any other libraries that can do this? I don't really need density and stuff like that, the use cases in the image is pretty much all I need (+ Collision Detection).
*A magnet would be a body constantly pulling other bodies in a certain range to itself
*Kockback would just be a simple impulse or the collision of a projectile with the object.
EDIT: If you know The Binding of Isaac, thats the kinda physics I'm aiming for.

Set the distance where the magnet has his influence:
float magnetRadius = 30;
Set the attractive force of the magnet:
float magnetForce = 400;
Get the position of the player and of the magnet:
Vector2 magnetPos = magnet.getWorldCenter();
Vector2 playerPos = player.getWorldCenter();
Now calculate the distance between the player and the magnet:
Vector2 magnetDist = new Vector2((playerPos.x - magnetPos.x), (playerPos.y - magnetPos.y));
float distance = (float) Math.sqrt((magnetPos.x) * (magnetPos.x) + (magnetPos.y) * (magnetPos.y));
Then, if the player is inside the magnet's radius, you must apply a force to him that depends on the distance of the player from the magnet:
if (distance <= magnetRadius) {
float vecSum = Math.abs(magnetDist.x)+Math.abs(magnetDist.y);
Vector2 force = new Vector2((magnetForce*magnetDist.x * ((1/vecSum)*magnetRadius/distance)), (magnetForce*magnetDist.y * ((1/vecSum)*planetRadius/distance)));
player.applyForceToCenter(force, true);
}

Related

Calculating collisions, taking into account velocity

I'm making a platformer game. The jumping and movement are working, and now I want to program the collisions. I have a sort of idea as to how this will work:
I wasn't sure whether this question should be here or in the game dev site.
I have two Vector2's - velo and momentum (velo is the velocity). Both are (0, 0). The momentum is what's added to the velocity each frame.
Each frame, I first get the input. Momentum is increased and/or increased based on the keys pressed (e.g: if (Gdx.input.isKeyPressed(Keys.A)) { momentum.x -= speed; })
I then multiply the momentum by 0.15. This is so that it slows down.
After this, I multiply the velocity by 0.8.
Then, I add the momentum to the velocity, to increase the velocity, as
this is what actually moves the player.
I then add the velocity to the position of the player.
To apply the gravity, I add a gravity vector (0, -10) to the position of the player.
So I need to find a way to move the player, but not allowing it to overlap any part of the world. The world is made up of lots of Rectangle instances. The player's body is also an instance of Rectangle. Would it be easier to rewrite the collisions using Box2D? What I've tried is checking if the player overlaps any rectangles when it's moved, and if it will, not moving it. But this doesn't seem to take everything into account - sometimes it works, but other times, it stops before touching the world.
TL;DR: I want to make collisions of my player with a world which is stored as a grid of rectangles. How would I do this, as my player is also a Rectangle. Would it be easier to use Box2D?
This answer gives a good overview about the details of collision detection:
https://gamedev.stackexchange.com/a/26506
However, that might be a bit overwhelming if you just want to get a simple game going. Does your game loop happen in fixed interval or is it dependent on the framerate? Maybe you could solve a part of your issue by simply dividing the collision detection into more steps. Instead of moving the full way during one update, you could make 10 little updates that each move you only a 10th of the distance. Then you do a collision check after each step, so it's less likely that you stop too early or move through thin objects.
That would of course be more taxing on the performance, but it's a naive and easy to implement approach to a solution.
EDIT:
Just wrap the position update in a for loop. I don't know how your code for collision checking and updating, but the general structure would be something like
for (int i = 0; i < 10; i++) {
newPosX += deltaX * 0.1; // 1/10th of the usual update
newPosY += deltaY * 0.1; // 1/10th of the usual update
if (checkCollision(newPosX, newPosY))
{
posX = newPosX;
posY = newPosY;
}
else
{
break; // We hit something, no more mini-updates necessary.
}
}

LibGDX 3D Camera spasm when player looks directly up or down

My circumstance
I am making a 3D LibGDX game. I am using a custom camera controller, based off of the one over here. It takes out the use of delta Y, when determining where to move the player, so that they can stay on the same level whether they are looking up or down.
My problem
My problem is that whenever the player looks too far up, or down, the camera kinda starts spazing out. I believe that it is trying to look either strait up, or down. My problem is that I don't want that. In previous projects I have tried to set a limit like so:
if(camera.direction.y + deltaY >= 0.9){
return;
}
(Code might not be exactly correct), but when that happens, the player usually cannot see enough.
My code
There is a link to my code here.
I got my code fixed with the help of one of the fine fellows over at Github. Here is my new FirstPersonCameraController#touchDragged:
float deltaX = -Gdx.input.getDeltaX() * degreesPerPixel;
float deltaY = -Gdx.input.getDeltaY() * degreesPerPixel;
camera.direction.rotate(camera.up, deltaX);
Vector3 oldPitchAxis = tmp.set(camera.direction).crs(camera.up).nor();
Vector3 newDirection = tmp2.set(camera.direction).rotate(tmp, deltaY);
Vector3 newPitchAxis = tmp3.set(tmp2).crs(camera.up);
if (!newPitchAxis.hasOppositeDirection(oldPitchAxis))
camera.direction.set(newDirection);
(I removed a couple of parts that are specific to my game)

Camera movement around the model

I want to make my camera move behind the model when it rotates, just like in a Third Person Perspective game - to have it "look" always on the back of the model. Im provided with a framework so the syntax may be bit different than normal opengl. I use the standard camera
Mat4 mv = MatrixMath.lookAt(this.eyeX,this.eyeY,this.eyeZ,this.at,this.up);
and to rotate the camera i tried
this.mouseRotation += 20.0f;
this.eyeX = (float) Math.sin(this.mouseRotation / 180.0f * 3.14f) * 2.0f;
this.eyeZ = (float) Math.cos(this.mouseRotation / 180.0f * 3.14f) * 2.0f;
mouseRotation is the angle which the model is located so obviously the camera should be also move to a position located 20 degrees further on the "circle". But instead of this the object rotates around itself, and the camera makes a circular movement but not around the model, but next to it, still looking at the same point.
Any ideas how to make this work?
From your example, I believe the short answer is to add this.at (which should be the position of your object) into your this.eye so that that the eye is positioned relative to the object.
In more detail, say your object's position is at this.at, and you want the camera to follow the object at some distance, say 'd' "behind" the object. If you have a unit vector (i.e., one's whose length is 1.0) pointing out of the front of the object, then the this.at - d should be the position of the camera (i.e., this.eye). In order to get the camera to rotate around the object, first apply a rotation to 'd' (in the example above, you appear to be rotating around the 'Y' axis [since you're only modifying eyeX and eyeZ]), so that
this.eye = this.at - rotation(Y) * d;

Java3D: Rotating the universe by increments

I'm trying to develop a Java3D method for rotating the universe in increments from the current viewing direction to the direction at the center of an object.
In other words, I want the 3D universe to rotate in, say, 100 short steps, so that an object that I click on appears to move gradually to the center of the screen.
I've reviewed the various answers to 3D rotation questions here on StackOverflow (as well as on the Web), but pretty much all of them are specific to rotating objects, not the world itself.
I've also tried to review my linear algebra, but that's not helping me to identify Java-specific functions that accomplish my requirements.
So far I've tried defining a set of incremental XYZ coordinates and dynamically using lookAt() in each pass through the loop. That almost works, but I don't see any way to preserve or obtain viewpoint values from one complete rotation pass to the next; each rotation pass starts out looking at the origin.
I've also tried defining a rotation matrix by obtaining the difference between the target and start transforms and dividing by the number of increments (and removing the scaling value), then adding that incremental rotation matrix to the current view direction at each pass through the loop. That works just fine for an increment value of 1. But splitting the rotation into two or more increments always generates the "BadTransformException: Non-congruent transform above ViewPlatform" error. (I've read the meager documentation of this exception in the Java3D API reference; it might as well have been written in Urdu for all I could make out from it. There seems to be no plain-English definition of 3D-context terms like "affine" or "shear" or "congruent" or "uniform" anywhere that Google can see.)
I then tried to cudgel my code into providing an AxisAngle4d, obtaining the angle (in radians), dividing that angle into my desired increments, and rotating by the incremental angle value. That rotated the world, all right, but nowhere near the object I picked, and not to any pattern I could see.
In desperation I tried using rotX and rotY (setting Z to the endpoint) on the extracted angle, and even blindly threw a couple of Math.cos() and Math.sin() wrappers in there. Still no joy.
My instincts are telling me that I've got the basics in place and that there's a relatively simple solution in Java3D. But clearly there's a comprehension wall I'm hitting. Rather than continue that, I thought I'd go ahead and see if anyone here can suggest a solution in Java3D. Code is preferred, but I'm willing to try to follow an explanation in linear algebra if that will get me to a code solution.
Below is the core of the method I'm using to schedule rotation increments using Java's Timer method. The part I need help with is just before the ActionListener. Presumably that's where the magic code would go that creates some kind of incremental rotation value I can apply (in the loop) to the current view direction in order to rotate the universe without getting "non-congruent" errors.
private void flyRotate(double endX, double endY, double endZ)
{
// Rotate universe by increments until target object is centered in view
//
// REQUIREMENTS
// 1. Rotate the universe by NUMROTS increments from an arbitrary (non-origin)
// 3D position and starting viewpoint to an ending viewpoint using the
// shortest path and preserving the currently defined "up" vector.
// 2. Use the Java Timer() method to schedule the visual update for each
// incremental rotation.
//
// GLOBALS
// rotLoop contains the integer loop counter for rotations (init'd to 0)
// viewTransform3D contains rotation/translation for current viewpoint
// t3d is a reusable Transform3D variable
// vtg contains the view platform transform group
// NUMROTS contains the number of incremental rotations to perform
//
// INPUTS
// endX, endY, endZ contain the 3D position of the target object
//
// NOTE: Java3D v1.5.1 or later is required for the Vector3D getX(),
// getY(), and getZ() methods to work.
final int delay = 20; // milliseconds between firings
final int pause = 10; // milliseconds before starting
// Get translation components of starting viewpoint vector
Vector3d viewVector = new Vector3d();
viewTransform3D.get(viewVector);
final double startX = viewVector.getX();
final double startY = viewVector.getY();
final double startZ = viewVector.getZ();
// Don't try to rotate to the location of the current viewpoint
if (startX != endX || startY != endY || startZ != endZ)
{
// Get a copy of the starting view transform
t3d = new Transform3D(viewTransform3D);
// Define the initial eye/camera position and the "up" vector
// Note: "up = +Y" is just the initial naive implementation
Point3d eyePoint = new Point3d(startX,startY,startZ);
Vector3d upVector = new Vector3d(0.0,1.0,0.0);
// Get target view transform
// (Presumably something like this is necessary to get a transform
// containing the ending rotation values.)
Transform3D tNew = new Transform3D();
Point3d viewPointTarg = new Point3d(endX,endY,endZ);
tNew.lookAt(eyePoint,viewPointTarg,upVector);
tNew.invert();
// Get a copy of the target view transform usable by the Listener
final Transform3D tRot = new Transform3D(tNew);
//
// (obtain either incremental rotation angle
// or congruent rotation transform here)
//
ActionListener taskPerformer = new ActionListener()
{
public void actionPerformed(ActionEvent evt)
{
if (++rotLoop <= NUMROTS)
{
// Apply incremental angle or rotation transform to the
// current view
t3d = magic(tRot);
// Communicate the rotation to the view platform transform group
vtg.setTransform(t3d);
}
else
{
timerRot.stop();
rotLoop = 0;
viewTransform3D = t3d;
}
}
};
// Set timer for rotation steps
timerRot = new javax.swing.Timer(delay,taskPerformer);
timerRot.setInitialDelay(pause);
timerRot.start();
}
}
As is often the case with these things, there may be a better way to do what I'm trying to accomplish here by stepping back and rethinking the problem. I'm open to constructive suggestions there as well.
Thanks very much for any assistance with this!
UPDATE
Let me try to define the goal a little more concretely.
I have a Java3D universe containing many Sphere objects. I can click on each object and dynamically obtain its predefined XYZ coordinates.
At any moment, I am looking at all currently visible objects with a "camera" at a particular XYZ position and a view direction, which are contained in a transform holding the rotation matrix and translation vector.
(Note: I can both rotate the universe and translate through it using the mouse independently of clicking on objects. So there will be times when the view transform containing the camera's current rotation matrix and translation vector is not pointing at any target object with known XYZ coordinates.)
Given the camera transform and the object's XYZ coordinates, I want to rotate the universe around my current camera position until the selected object is centered in the screen. And I want to do this as a sequence of discrete incremental rotations, each of which is rendered so that the visible universe appears to "spin" in the viewing window until the selected object is centered. (I'm following this up with a translation to the object; that part at least is working!)
Example: Suppose the camera is at the origin, "up" is 1.0 along the Y-axis, and the selected object is centered ten units directly to my left. Assuming I had a 180-degree field of view, I could click on the half of the sphere that is visible all the way to the left of the screen and halfway between the top and bottom of the screen.
When I give the word, every visible object in the universe should appear to move in a sequence of evenly-spaced steps (let's say 50) from my left to my right until the selected object is exactly centered in the screen.
In coding terms, I need to work out the Java3D code by which I can rotate the universe around an imaginary line that runs through my camera position (currently at 0,0,0) and that is perfectly aligned with the Y-axis of the universe's coordinate system. (I.e., the axis of rotation sweeps through a plane where Z is always equal to the Z component of the camera's position.)
The complicating requirements are:
The camera can be translated somewhere in 3D space other than the origin.
Objects can be anywhere in 3D space with respect to the camera's current position and view, including being visible but off the screen (outside the view frustum) entirely.
Rotations should take the shortest path -- no spinning the universe more than 180 degrees at a time.
There should not be any "jump" or "twisting" of the visible universe as the first step in the rotation process; i.e., the current "up" vector (not the universe's absolute "up" vector) should be preserved.
So there's the question: given a transform holding the (virtual) camera's current translation and rotation information, and the XYZ coordinates in universe space of a target object, what Java3D code will rotate the universe around the camera in N equal steps until the object is centered in the screen?
Presumably this solution is in two parts: first, some 3D math (expressed in Java3D) to calculate the incremental rotation information given only the camera transform and object's XYZ coordinates; second, a loop that [applies the incremental rotation to the current viewing transform and updates the screen] until the loop counter equals the number of increments.
It's that 3D math part that's beating me. I'm not seeing and can't bash out a way to obtain some form of incremental rotation information from the current camera transform and target object position that I can then apply to the camera transform. At least, I haven't found any way that doesn't cause jumping or twisting or unequal incremental movement steps (or a "non-congruent transform above ViewPlatform" exception).
There must be a simple solution....
So if I understand correctly, your goal is to rotate the camera so it centers on the selected object, but that rotation should not be about an arbitrary vector, but instead should preserve the camera's "up" direction.
A solution that might work then:
First, calculate the rotation angle (let's call it A) about the "up" vector necessary so that the camera is facing the object you want.
Second, calculate the translation distance/direction (let's call it D) necessary along the "up" vector so that the object lines up as necessary with the camera. This will likely just be the difference in the Z/Y coordinate between the camera/object.
Find dA and dD by diving A/D by N, the number of increments you want to take to smooth the motion.
In a timer/time loop increment A/D by dA/dD respectively N times, taking them to the final values. Remember that you are rotating the camera about it's "up" vector and current location, not about the origin..
If you want an even smoother, more realistic looking rotation, consider using SLERP.

Math For Pong Game

Lets say I have an angle... what would be a reasonable way to go about finding the next point of where the ball would be?
Variables: bSpeed, bAngle, Ball.x, Ball.y
You knwon when you do c^2 = a^2 + b^2... is there a way you could find how long c^2 could be and actually "draw" it out and then use speed to go only part of that... with that find a^2 and b^2 so you can actually have a x and a y to draw the ball...
Thanks ahead of time! (BTW, I don't need code... just reasoning and wisdom)
Your 4 variables are effectively a vector - where the vector is a measure of both direction and magnitude/velocity (i.e. what you've represented as bSpeed and bAngle). Using this representation means that Ball.x and Ball.y simply become the horizontal and vertical components of the vector.
Given a vector called v1 we can calculate the movement in the x and y axis as follows...
xVelocityOfBall = v1.magnitude * cos(v1.angle);
yVelocityOfBall = v1.magnitude * sin(v1.angle);
GPWiki (Games Programming Wiki) is a great resource for anything maths/physics for games development. Here's a handy link to their vector page
delta_x = speed*cos(angle)
delta_y = speed*sin(angle)
new_x = x+delta_x
new_y = y+delta_y
and then you need just change speed and angle of ball in the case of wall strike)
Open up your textbooks on Sin, Cos and Tan since you're using bAngle. Specifically you'll probably be looking Sin for the vertical motion and Cos for the horizontal motion. Depending on where you've defined degree 0 to face.
Also, you could consider caching the horizontal and vertical speeds since Sin and Cos are expensive
You probably will need to consider the physics of the movement that the pong player is moving also. For example, if a player's paddle is speeding to the left as it contacts the ball, the ball will need to speed up wrt to the left direction. This represents transfer of momentum in physics. The general system of equations in the x and y directions will always be:
mass*velocity (in x) = the sum of the mass*velocity of all objects in x
mass*velocity (in y) = the sum of the mass*velocity of all objects in y
generally speaking sine you always have the speed of the ball in x and y all you need to do is determine the masses of both the ball and the paddles (i suppose that's up to you but I suggest making them the same for ease of calculation).
In terms of solving for the angle, it's very simple, you would just make sure the reflection is equal. If the ball is approaching a paddle (or wall) from a 60 degree incident, then the bounce should also be at a 60 degree incident.
First, convert the angle to a vector using the sin and cos functions. This tells you the relative x-speed and y-speed of the ball. Then, to find out how far the ball actually went, multiply these numbers by the ball's speed and time-of-flight. Finally, add to the ball's starting position. This gives you the ball's ending position.
In a pong game, the ball may hit an object, in which case you need to correct for the change in velocity.

Categories