I’m making a ‘2D’ game where you keep a ball bouncing in the air. To keep the ball in the same plane as the paddle and walls, I made a method that automatically grabs the vector position of the ball and sets the Z axis position to zero. This isn’t reliable, though, and the ball tends to go behind or in front of the paddle.
In the code below I used get/setPhysicsLocation, and also tried to get/setLinearVelocity in the same way, with no success. Is there some easier way to keep the ball lined up with the paddle, short of making invisible boxes to keep them physically lined up? Or am I just trying to make the engine do something it wasn’t meant to?
[java]package KeepUp;
import com.jme3.app.SimpleApplication;
import com.jme3.bullet.BulletAppState;
import com.jme3.bullet.control.RigidBodyControl;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;
import com.jme3.math.Vector2f;
import com.jme3.math.Vector3f;
import com.jme3.scene.Geometry;
import com.jme3.scene.shape.Box;
import com.jme3.scene.shape.Cylinder;
import com.jme3.scene.shape.Sphere;
import com.jme3.system.AppSettings;
public class Main extends SimpleApplication {
public static void main(String[] args) {
Main app = new Main();
app.setShowSettings(false);
AppSettings settings = new AppSettings(true);
settings.setResolution(480, 640);
app.setSettings(settings);
app.start();
}
private BulletAppState bulletAppState;
private RigidBodyControl paddlePhysics;
private RigidBodyControl paddle;
private RigidBodyControl ballPhysics;
private RigidBodyControl ball;
private RigidBodyControl surfacePhysics;
private RigidBodyControl floor;
private RigidBodyControl ceiling;
private RigidBodyControl wallLeft;
private RigidBodyControl wallRight;
Quaternion tiltAngle = new Quaternion();
Quaternion noAngle = new Quaternion();
@Override
public void simpleInitApp() {
flyCam.setEnabled(false);
//flyCam.setMoveSpeed(40);
// Set up Physics Game
bulletAppState = new BulletAppState();
stateManager.attach(bulletAppState);
//bulletAppState.getPhysicsSpace().enableDebug(assetManager);
ball = makeBall();
floor = makeSurface(0, -5f, 0, 0, 0);
ceiling = makeSurface(0, 4.1f, 0, 0, 0);
wallLeft = makeSurface(-3.05f, 0, 0, 0, 90f);
wallRight = makeSurface(3.05f, 0, 0, 0, 90f);
paddle = makePaddle();
noAngle.fromAngles(0, 0, 0);
}
@Override
public void simpleUpdate(float tpf) {
adjustBall();
movePaddle();
}
private RigidBodyControl makeBall()
{
// Sphere(30, 30, 0.15f)
// Cylinder(4, 20, 0.20f, 0.12f, true)
Geometry ballGeom = new Geometry(“Ball”, new Sphere(30, 30, 0.15f));
Material ballMaterial = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
ballMaterial.setColor(“Color”, ColorRGBA.White);
ballGeom.setMaterial(ballMaterial);
ballPhysics = new RigidBodyControl(0.005f);
ballGeom.addControl(ballPhysics);
ballPhysics.setRestitution(1.0f);
bulletAppState.getPhysicsSpace().add(ballPhysics);
rootNode.attachChild(ballGeom);
return ballPhysics;
}
private RigidBodyControl makePaddle()
{
Geometry paddleGeom = new Geometry(“Paddle”, new Box(0.75f, 0.20f, 0.20f));
Material paddleMaterial = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
paddleMaterial.setColor(“Color”, ColorRGBA.White);
paddleGeom.setMaterial(paddleMaterial);
paddleGeom.setLocalTranslation(new Vector3f(0, -3.5f, 0));
paddlePhysics = new RigidBodyControl(0.0f);
paddleGeom.addControl(paddlePhysics);
paddlePhysics.setRestitution(1.0f);
bulletAppState.getPhysicsSpace().add(paddlePhysics);
rootNode.attachChild(paddleGeom);
return paddlePhysics;
}
private RigidBodyControl makeSurface(float xpos, float ypos, float rotx, float roty, float rotz)
{
Geometry surfaceGeom = new Geometry(“Floor”, new Box(4f, 0.05f, 0.05f));
Material surfaceMaterial = new Material(assetManager, “Common/MatDefs/Misc/Unshaded.j3md”);
surfaceMaterial.setColor(“Color”, ColorRGBA.Gray);
surfaceGeom.setMaterial(surfaceMaterial);
surfaceGeom.rotate(rotxFastMath.DEG_TO_RAD, rotyFastMath.DEG_TO_RAD, rotz*FastMath.DEG_TO_RAD);
surfaceGeom.setLocalTranslation(new Vector3f(xpos, ypos, 0));
surfacePhysics = new RigidBodyControl(0.0f);
surfaceGeom.addControl(surfacePhysics);
surfacePhysics.setRestitution(1.0f);
bulletAppState.getPhysicsSpace().add(surfacePhysics);
rootNode.attachChild(surfaceGeom);
return surfacePhysics;
}
private void movePaddle()
{
// Offset mouse coordinates so that x=0 is at the center.
int halfScreenWidth = settings.getWidth()/2;
Vector2f mousePos = inputManager.getCursorPosition();
float realMousePos = (mousePos.x-halfScreenWidth)/104;
float variableAngle = (float) (realMousePos * 10) * FastMath.DEG_TO_RAD;
tiltAngle.fromAngles(0, 0, variableAngle);
paddle.setPhysicsRotation(tiltAngle);
paddle.setPhysicsLocation(new Vector3f(realMousePos, -3.5f, 0));
}
private void adjustBall()
{
ball.setPhysicsRotation(noAngle);
Vector3f ballPos = ball.getPhysicsLocation();
System.out.println("Original: "+ballPos);
Vector3f adjustedBallPos = new Vector3f(ballPos.x, ballPos.y, 0);
ball.setPhysicsLocation(adjustedBallPos);
Vector3f ballPos2 = ball.getPhysicsLocation();
System.out.println("Adjusted: "+ballPos2);
}
}[/java]
ball.setPhysicsLocation(ball.getPhysicsLocation().getX(),paddle.getPhysicsLocation().getZ(),ball.getPhysicsLocation().getY());
It’s always lined up with paddle?
That was a really good idea! Unfortunately the ball still passed behind the paddle.
My console outputs show the adjustment is being performed properly, even when the ball is doing the wrong thing. Something very odd happens to my numbers, too. Below is the console output, with original ball position and ball position after adjustment:
[xml]
Original: (1.2332349, -1.7871051, 1.2754328E-5)
Adjusted: (1.2332349, -1.7871051, 0.0)
Original: (1.2332349, -1.7871051, 0.0)
…
Adjusted: (1.2332349, -1.7871051, 0.0)
Original: (1.2751576, -1.723972, 1.2754328E-5)
Adjusted: (1.2751576, -1.723972, 0.0)
Original: (1.2751576, -1.723972, 0.0)
[/xml]
So something is making the ball go back to its exact old Z axis position randomly, despite being correctly resetted previously. It’s a different Z axis position each time I run the program. The change in value is tiny, though, less than 0.000013 of a world unit, which wouldn’t matter under most normal applications. I think I’m just trying to make the engine do it on too small a scale, and making everything bigger may solve my problem.
The fact that the ball keeps bouncing back to the same position is strange, though.
@desiquintans said:
That was a really good idea! Unfortunately the ball still passed behind the paddle.
My console outputs show the adjustment is being performed properly, even when the ball is doing the wrong thing. Something very odd happens to my numbers, too. Below is the console output, with original ball position and ball position after adjustment:
[xml]
Original: (1.2332349, -1.7871051, 1.2754328E-5)
Adjusted: (1.2332349, -1.7871051, 0.0)
Original: (1.2332349, -1.7871051, 0.0)
...
Adjusted: (1.2332349, -1.7871051, 0.0)
Original: (1.2751576, -1.723972, 1.2754328E-5)
Adjusted: (1.2751576, -1.723972, 0.0)
Original: (1.2751576, -1.723972, 0.0)
[/xml]
So something is making the ball go back to its exact old Z axis position randomly, despite being correctly resetted previously. It's a different Z axis position each time I run the program. The change in value is tiny, though, less than 0.000013 of a world unit, which wouldn't matter under most normal applications. I think I'm just trying to make the engine do it on too small a scale, and making everything bigger may solve my problem.
The fact that the ball keeps bouncing back to the same position is strange, though.
Got it!
[java]
ball.setPhysicsLocation(ball.getPhysicsLocation().getX(),paddle.getPhysicsLocation().getZ(),ball.getPhysicsLocation().getY());
ballPhysics.setPhysicsLocation(ball.getPhysicsLocation().getX(),paddle.getPhysicsLocation().getZ(),ball.getPhysicsLocation().getY());
[/java]
I don’t think it is a good idea to set the physics location of the ball like this unless it is set to kinematic (maybe it is but I missed it).
The reason is that you interfere with the physics calculations bullet does and strange things will happen. The recommendation is to only apply forces and impulses on rigid bodies (unless they are kinematic).
See https://wiki.jmonkeyengine.org/legacy/doku.php/jme3:advanced:physics
If all you are doing is bouncing off walls and a bat in 2 dimensions you may be better off just doing your own 2d physics implementation.
Flat plane bounce and collision detection is pretty fast and the maths for the reflections is also pretty simple.
Or give the player 3d control over the paddle and make the 3d a feature not a problem
@ivandonat said:
Got it!
[java]
ball.setPhysicsLocation(ball.getPhysicsLocation().getX(),paddle.getPhysicsLocation().getZ(),ball.getPhysicsLocation().getY());
ballPhysics.setPhysicsLocation(ball.getPhysicsLocation().getX(),paddle.getPhysicsLocation().getZ(),ball.getPhysicsLocation().getY());
[/java]
Still goes behind the paddle. I think jBullet really doesn't like it, as jmassing said (nope, I didn't declare it as a kinematic).
@zarch said:
If all you are doing is bouncing off walls and a bat in 2 dimensions you may be better off just doing your own 2d physics implementation.
Flat plane bounce and collision detection is pretty fast and the maths for the reflections is also pretty simple.
Or give the player 3d control over the paddle and make the 3d a feature not a problem :D
I will go with the 2D physics. :D I'm new to making games, and I wanted to keep it simple but challenging by trying to make half a Pong game with a 3D engine.