# Converting 2D Physics to 3D

I'm new to game physics and I am trying to adapt a simple 2D ball simulation for a 3D simulation with the Java3D library. I have this problem:

Two things:

1) I noted down the values generated by the engine: X/Y are too high and minX/minY/maxY/maxX values are causing trouble.

Sometimes the balls are drawing but not moving

Sometimes they are going out of the panel

Sometimes they're moving on little area

Sometimes they just stick at one place...

2) I'm unable to select/define/set the default correct/suitable values considering the 3D graphics scaling/resolution while they are set with respect to 2D screen coordinates, that is my only problem.

This is the code:

``````public class Ball extends GameObject {
private float x, y; // Ball's center (x, y)
private float speedX, speedY; // Ball's speed per step in x and y
// Collision detected by collision detection and response algorithm?
boolean collisionDetected = false;

// If collision detected, the next state of the ball.
// Otherwise, meaningless.
private float nextX, nextY;
private float nextSpeedX, nextSpeedY;

private static final float BOX_WIDTH = 640;
private static final float BOX_HEIGHT = 480;

/**
* Constructor The velocity is specified in polar coordinates of speed and
* moveAngle (for user friendliness), in Graphics coordinates with an
* inverted y-axis.
*/
public Ball(String name1,float x, float y, float radius, float speed,
float angleInDegree, Color color) {
this.x = x;
this.y = y;
// Convert velocity from polar to rectangular x and y.
this.speedX = speed * (float) Math.cos(Math.toRadians(angleInDegree));
this.speedY = speed * (float) Math.sin(Math.toRadians(angleInDegree));
}

public void move()  {
if (collisionDetected) {
// Collision detected, use the values computed.
x = nextX;
y = nextY;
speedX = nextSpeedX;
speedY = nextSpeedY;
} else {
// No collision, move one step and no change in speed.
x += speedX;
y += speedY;
}
collisionDetected = false; // Clear the flag for the next step
}

public void collideWith()  {
// Get the ball's bounds, offset by the radius of the ball
float minX = 0.0f + radius;
float minY = 0.0f + radius;
float maxX = 0.0f + BOX_WIDTH - 1.0f - radius;
float maxY = 0.0f + BOX_HEIGHT - 1.0f - radius;

double gravAmount = 0.9811111f;
double gravDir = (90 / 57.2960285258);

// Try moving one full step
nextX = x + speedX;
nextY = y + speedY;
System.out.println("In serializedBall in collision.");

// If collision detected. Reflect on the x or/and y axis
// and place the ball at the point of impact.
if (speedX != 0) {
if (nextX > maxX) { // Check maximum-X bound
collisionDetected = true;
nextSpeedX = -speedX; // Reflect
nextSpeedY = speedY; // Same
nextX = maxX;
nextY = (maxX - x) * speedY / speedX + y; // speedX non-zero
} else if (nextX < minX) { // Check minimum-X bound
collisionDetected = true;
nextSpeedX = -speedX; // Reflect
nextSpeedY = speedY; // Same
nextX = minX;
nextY = (minX - x) * speedY / speedX + y; // speedX non-zero
}
}
// In case the ball runs over both the borders.
if (speedY != 0) {
if (nextY > maxY) { // Check maximum-Y bound
collisionDetected = true;
nextSpeedX = speedX; // Same
nextSpeedY = -speedY; // Reflect
nextY = maxY;
nextX = (maxY - y) * speedX / speedY + x; // speedY non-zero
} else if (nextY < minY) { // Check minimum-Y bound
collisionDetected = true;
nextSpeedX = speedX; // Same
nextSpeedY = -speedY; // Reflect
nextY = minY;
nextX = (minY - y) * speedX / speedY + x; // speedY non-zero
}
}

speedX += Math.cos(gravDir) * gravAmount;
speedY += Math.sin(gravDir) * gravAmount;
}

public float getSpeed()  {
return (float) Math.sqrt(speedX * speedX + speedY * speedY);
}

public float getMoveAngle()  {
return (float) Math.toDegrees(Math.atan2(speedY, speedX));
}

}

public float getX() {
return x;
}

public float getY() {
return y;
}

public void setX(float f) {
x =  f;
}

public void setY(float f) {
y =  f;
}
}
``````

Here's how I'm drawing the balls:

``````public class 3DMovingBodies extends Applet implements Runnable {

private static final int BOX_WIDTH = 800;
private static final int BOX_HEIGHT = 600;
private int currentNumBalls = 1; // number currently active

private volatile boolean playing;
private long mFrameDelay;
private JFrame frame;

private int currentFrameRate;
private Ball[] ball = new Ball[currentNumBalls];

private Random rand;
private Sphere[] sphere = new Sphere[currentNumBalls];
private Transform3D[] trans = new Transform3D[currentNumBalls];
private TransformGroup[] objTrans = new TransformGroup[currentNumBalls];

public 3DMovingBodies() {

rand = new Random();
float angleInDegree = rand.nextInt(360);

setLayout(new BorderLayout());
GraphicsConfiguration config = SimpleUniverse
.getPreferredConfiguration();
Canvas3D c = new Canvas3D(config);

ball[0] = new Ball(0.5f, 0.0f, 0.5f, 0.4f, angleInDegree, Color.yellow);
// ball[1] = new Ball(1.0f, 0.0f, 0.25f, 0.8f, angleInDegree,
// Color.yellow);
// ball[2] = new Ball(0.0f, 1.0f, 0.15f, 0.11f, angleInDegree,
// Color.yellow);

trans[0] = new Transform3D();
// trans[1] = new Transform3D();
// trans[2] = new Transform3D();

sphere[0] = new Sphere(0.5f);
// sphere[1] = new Sphere(0.25f);
// sphere[2] = new Sphere(0.15f);
// Create a simple scene and attach it to the virtual universe
BranchGroup scene = createSceneGraph();

SimpleUniverse u = new SimpleUniverse(c);
u.getViewingPlatform().setNominalViewingTransform();

startSimulation();
}

public BranchGroup createSceneGraph() {
// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();

for (int i = 0; i < currentNumBalls; i++) {

// Create a simple shape leaf node, add it to the scene graph.

objTrans[i] = new TransformGroup();
objTrans[i].setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
Transform3D pos1 = new Transform3D();
pos1.setTranslation(randomPos());
objTrans[i].setTransform(pos1);

}

BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0),
100.0);

Color3f light1Color = new Color3f(1.0f, 0.0f, 0.2f);
Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f);
DirectionalLight light1 = new DirectionalLight(light1Color,
light1Direction);
light1.setInfluencingBounds(bounds);

// Set up the ambient light
Color3f ambientColor = new Color3f(1.0f, 1.0f, 1.0f);
AmbientLight ambientLightNode = new AmbientLight(ambientColor);
ambientLightNode.setInfluencingBounds(bounds);

return objRoot;
}

public void startSimulation() {
playing = true;
t.start();
}

public void stop() {
playing = false;
}

public void run() {

long previousTime = System.currentTimeMillis();
long currentTime = previousTime;
long elapsedTime;
long totalElapsedTime = 0;
int frameCount = 0;

while (true) {
currentTime = System.currentTimeMillis();
elapsedTime = (currentTime - previousTime); // elapsed time in
// seconds
totalElapsedTime += elapsedTime;
if (totalElapsedTime > 1000) {
currentFrameRate = frameCount;
frameCount = 0;
totalElapsedTime = 0;
}
for (int i = 0; i < currentNumBalls; i++) {
ball[i].move();
ball[i].collideWith();
drawworld();
}

try {
} catch (Exception e) {
e.printStackTrace();
}
previousTime = currentTime;
frameCount++;
}
}

public void drawworld() {

for (int i = 0; i < currentNumBalls; i++) {
printTG(objTrans[i], "SteerTG");
trans[i].setTranslation(new Vector3f(ball[i].getX(),
ball[i].getY(), 0.0f));
objTrans[i].setTransform(trans[i]);
}
}

private Vector3f randomPos()
/*
* Return a random position vector. The numbers are hardwired to be within
* the confines of the box.
*/
{
Vector3f pos = new Vector3f();
pos.x = rand.nextFloat() * 5.0f - 2.5f; // -2.5 to 2.5
pos.y = rand.nextFloat() * 2.0f + 0.5f; // 0.5 to 2.5
pos.z = rand.nextFloat() * 5.0f - 2.5f; // -2.5 to 2.5
return pos;
} // end of randomPos()

public static void main(String[] args) {
System.out.println("Program Started");
3DMovingBodiesbb = new 3DMovingBodies();
MainFrame mf = new MainFrame(bb, 600, 400);
}
}
``````
-
You should try to add a Z coordinate value, to begin with. I'm pretty sure that your engine returns 3 values and not 2. Thus, you need to use all of the 3 values if you want to test collision correctly. – Valkea May 22 '11 at 0:39
Thanks, but no,it's not as i told i m adapting this engine which is written for 2d graphics so there is no Z coordinate there,and i don't think that is the reason of all above problems – static void main May 22 '11 at 0:51
You convert 2D to 3D without Z ? I must have missed something. I think it's time for me to sleep few hours. Even if your balls are moving on a 2D plan, as long as you are using the returned values to change the position of the balls in a 3D world, you need some sort of Z coordinate. It can be fixed at Z=1 or Z=15 no matter, but you will need some sort of Z coordinate to convert the 2D position of your physic simulation into a 3D position to render the balls in your 3D world. I may have misunderstood the problem though. – Valkea May 22 '11 at 1:08
i have shown all the code, i don't have any more and this is not working. Do u really think Z has the same importance as X and Y to move the ball ideally...the only problem is to select and produce the right/suitable value for X and Y so that ball don't go out of the panel and for this the minX/minY/maxY and maxX also needs to be set with suitable and appropriate values... – static void main May 22 '11 at 1:22
The problem is that the X coordinate for the same pixel on your screen is generally not the same value at Z=1 and Z=15 in your 3D render engine (because it use to be a perspective projection) except if you render using orthographic projection. Thus the X coordinate you get is probably not corresponding to the positions of the pixels on your screen. – Valkea May 22 '11 at 1:37

in function `public void drawworld()` you have to change ` trans[i].setTranslation(new Vector3f(ball[i].getX(), ball[i].getY(), 0.0f));` but i have to calculate the exact formulas if you want to know what you yuo write there, try solving the problem I described and if you couldn't comment here so that I'll try! – Ali.S May 22 '11 at 15:59