Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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.

Please help.

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
    private float radius; // Ball's radius
    // 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));
        this.radius = radius;
    }

    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 getRadius()  {
        return radius;
    }

    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);
        add("Center", c);

        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();

        u.addBranchGraph(scene);

        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);
            objTrans[i].addChild(sphere[i]);

            objRoot.addChild(objTrans[i]);
        }

        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);
        objRoot.addChild(light1);

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

        return objRoot;
    }

    public void startSimulation() {
        playing = true;
        Thread t = new Thread(this);
        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 {
                Thread.sleep(88);
            } 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();
        bb.addKeyListener(bb);
        MainFrame mf = new MainFrame(bb, 600, 400);
    }
}
share|improve this question
    
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
2  
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

1 Answer 1

i think the easiest way to solve your problem is to change your camera type from prespective to isometric, that will solve the problem you are facing, but if you want to realy render tour scene with perspective features you have to change your set position function, the whole idea is to find a position where a ray hits a plane right in front of the camera, you have to compute what ray is using x/y your physics engine (ray's starting point is your camera and it's direction is based on the x/y of your object) and the plane it hits is perpendicular to camera direction right in from of it.

share|improve this answer
    
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
    
i thought you talked about correcting the initial position (vector3f pos), what are u finding wrong now in this function, it just translating the ball according to values returned from engine .. –  static void main May 22 '11 at 17:52
    
if i'm right, you see objects move faster when they get near edges of the screen, that's because you are moving object with a linear function while you are rendering them using perspective view, you have to either change your camera type to render an isometric image or you have to change your function as I explained above (all the ray stuff and where it hits that perpendicular plane), and if you want me to calculate what the correct position should be you have to help me with more details like what game engine are you using what are your camera properties (viewrect) and so on ... –  Ali.S May 22 '11 at 18:01
    
this is all the code what i have, i don't have any other code. on the basis of experience and knowledge, i will try to adapt some other engine. may be this:stackoverflow.com/questions/345838/…, but i have already so much problem with only this little engine/code. –  static void main May 22 '11 at 18:22
    
then how are you rendering your scene you should at least use opengl/directx with their default configurations even if you don't use any gameengine. –  Ali.S May 22 '11 at 18:29

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.