2
\$\begingroup\$

I am a new Android game developer. I want to force my game object to move in a projectile trajectory, like in Angry Birds.Related example here and my example You can see an example in the image.

enter image description here

I used jbox2d to write a little bit of code, but I don't know how to make it work. How do I force movement along a projectile trajectory?

My code is below:

    private static class ProjectileEquation {

        public float gravity;
        public Vector2 startVelocity = new Vector2();
        public Vector2 startPoint = new Vector2();

        public float yogx(float t) {
            return startPoint.x + t * startVelocity.x;
        }

        public float yogy(float t) {

            float u = (float) -4.97741939970554;
            float v = (float) 30.88079;
            float tt = 1/6f;  
            float n = (u+v)/2*tt;

            return startPoint.y + n * t *startVelocity.y + 0.5f *(n*n+n) 
                * t * t * gravity;
        }
    }

    private static class Controller {
        public float power = -66f;
        public float angle = 585f;      
    }
}

 public float P2M(float xPixels) {
    return xPixels * metersPerPixel;
}

public float M2P(float xMetres) {
    return xMetres * pixelsPerMeter;
}

public float MaxHeight(){

     if (projectileEquation.startVelocity.y > 0){

            return projectileEquation.startPoint.y;   
     }
        return projectileEquation.startPoint.y;
        }

public void Update() {
    projectileEquation.startVelocity.set(controller.power,controller.power);
    projectileEquation.startVelocity.rotate(controller.angle);
     //     bd = bodies;

}



    @Override
    protected void onDraw(Canvas c) {
        super.onDraw(c);

        MaxHeight();

        Update();

        float t = 0f;
        x = c.getWidth()/2;
        y = c.getHeight()-20;

        float timeSeparation = this.timeSeparation;    

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

            float x = this.x +  projectileEquation.yogx(t);
            float y = this.y +  -projectileEquation.yogy(t);

            t += timeSeparation;

            if(A) {
                c.drawBitmap(bmp, x, y, null);
            }else if(B) { 

                float bX = M2P(body.getPosition().x);
                float by = c.getHeight() - M2P(body.getPosition().y); 
                body.setActive(true);

                c.drawCircle(bX, by, M2P(body.m_fixtureList.m_shape.m_radius), circlePaint);
            }
        }
    }       


public class jbox2d {

    public float targetFps = 30.0f;
    public float timeStep = (1.0f / targetFps);
    private int interations = 2;
    public Body body;
    private World world;
    private BodyDef bodydef;

    public void Create(){

        Vec2 gravity = new Vec2(0,-10f);
        boolean doSleep = true;
        world = new World(gravity, doSleep);
    }

    public void addboll() {

        bodydef = new BodyDef();
        bodydef.type = BodyType.DYNAMIC;
        bodydef.allowSleep = true;


        bodydef.position.set(8.24f,10f);

        body = world.createBody(bodydef);
        body.setActive(false);
        float tt = 0f;     

        Vec2 stx = new Vec2();
        Vec2 sty =new Vec2();

        for (int it = 0; it < 20; it++) { 

            stx = M2P(projectileEquation.startVelocity.x);
            sty = M2P(projectileEquation.startVelocity.y);

            stx = M2P(projectileEquation.yogx(tt));
            sty = -M2P(projectileEquation.yogy(tt));

            body.setLinearVelocity(new Vec2(stx,sty));
            body.applyLinearImpulse(body.getLinearVelocity(), body.getWorldCenter());

            tt += timeSeparation;
        }

        CircleShape circle = new CircleShape();
        circle.m_radius = (float).42;

        FixtureDef fixturedef = new FixtureDef();
        fixturedef.density = 1.0f;
        fixturedef.restitution  = 0.9f;
        fixturedef.friction = 0.2f;
        fixturedef.shape = circle;
        body.createFixture(fixturedef);

    }

    public void update(){
        world.step(timeStep, interations, interations);
    }   
}
\$\endgroup\$
  • \$\begingroup\$ Aside: more descriptive identifiers would make it easier to parse what's going on. Edit: there seems to be unused fields, a minimal example is prefered. \$\endgroup\$ – Theraot Feb 9 '17 at 6:21
  • \$\begingroup\$ As Theraot said, could you provide a minimal example of what you've tried? Browsing through all the code to find what you wanted to do and what you actually did is much harder. \$\endgroup\$ – Vaillancourt Feb 9 '17 at 11:56
  • 1
    \$\begingroup\$ I suggest you visit this page to have your accounts merged, this will allow you to edit and comment on your question :) \$\endgroup\$ – Vaillancourt Feb 9 '17 at 12:56
4
\$\begingroup\$

You should think the other way around. Instead of defining an arc and then forcing the game object to follow it, you should let the game object define the arc.

Games usually solve this by giving the object a velocity vector (an x and y component in 2d and an additional z in 3d), set it to something, then each frame they add it to the position vector. They also subtract gravity from the velocity vector's y component to make it eventually start falling down.

Then you could apply some physics-based wizardry to move the object just the right way. Do you want the ball to reach x in time t while having a maximum height of y? No problem (vx and vy are the velocity vectors, px and py are the positions and g is the gravity):

vx = (x - px) / t
// s = v0*t+at^2/2 -> v0 = s/t-at/2
vy = (y - py) / t - g * t / 2
\$\endgroup\$
0
\$\begingroup\$

I would recommend a physics based approach as Bálint stated.

He covered how you could pick what your Vx and Vy would be based on a desired distance and tie.

You can also define those values based on launch velocity and angle

vX = vLaunch * cos( launchAngle )  //Be careful of radians / degrees 
vY = vLaunch * sin( launchAngle )

Then in your update loop you simulate physics:

x += vX * dt
v += vY * dt - 0.5*g *dt*dt
vY += -g *dt

And there you go. dt is your delta time. The time between each frame. You can also have it run faster or slower than real time by modifying that. g is the acceleration due to gravity. If each pixel represents 1 meter (3 feet), you would make it 9.8 to reflect Earth-like gravity. Make it smaller if you wanter a smaller scale (for example .98 would give you 10 pixels to a meter.

The nice way about this is that you can modify it to be more dynamic and respond to a change in forces. You could, for example, have it reverse the velocity if it detected a collision to have it bounce (real bouncing is a bit more complicated, but you can get something fairly convincing).

ALTERNATIVELY

If you want to force a projectile to move along a predefined parabola:

each step you would do the following in your update

t+=1;
x+=vx*t
y = h + vy*t -0.5*9.8*t*t    //h is the starting height

This will move it along the parabola defined by your parameters. Personally, I prefer the first way, but I also used to be a Physicist.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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