Arrow Ballistic - Something is Wrong and Feel Unrealistic

Hello.I have a big problem here, i dont know if anyone can actually spend some time helping me.
I dont have classes until 4/february and last year i spent some time off-classes with him , well he teached me alot about it. I tried my best to absorb everything, and i did absorb like 80% of the knowledge he passed me. But, im being slow in this movingAngle part, what i mean with that (will try my best to explain it in english).

When the arrow is shot, it starts a parabola movement , so, first i need to set the angle of the shot,


  sprite.setRotation((float) Math.toDegrees(shotAngle));

First of, i want to say that, if i only use the shotAngle, i get an almost-perfect simulation.But then again i come with two stupid problems :

-First, im unsure how to make the arrow perform the parabola.Im unsure how to set the gravity and the velocity to make it reasonable.

-Second, when i activate the code to set the moving angle, weird things happens :

*Watch in 480p or + for better reading.

The video Debug complete output is here :
http://sharetext.org/yO3y

Thats what happens,its like, the movingAngle Code is projecting a not-happening parabola. Its like a different one.

So.
Thats my issue. Any Tip or piece of knowledge , anything is welcome.I need start fixing from somewhere/something (tip) .

Video Showing only shot-Angle Working :

Now The Classes im Using , they are a bit Huge, so i will try to point the methods im Using :

Below, Its the Arrow Class, which LightArrow Class Extends to.
The Update Method and Render Method Are Used each frame.

package br.weapons;
public class Arrow {

    private static int xVertice = -1;

    public int type_Arrow;
    public float posX, posY, shotPosX;
    public int damage;
    public double shotAngle, movingAngle;
    private boolean shotAngleUsed = false;
    public Sprite sprite;
    public int manaWaste = 0;

    public int shotToQuadrant = -1;

    public double time;

    public Vector3 touch;
    public Vector2 vector;

    public boolean isInsideWindow;

    public boolean hit = false;
    public boolean toRemoveThis = false;
    public SmokeEffect smokeEffect;

    private TiledMapTileLayer.Cell Cell_Temp;

    public Arrow(double posX, double posY, double angle, int quadrant) {
        shotPosX = (int) posX;

        this.posX = (int) posX;
        this.posY = (int) posY;
        this.shotAngle = angle;

        time = 0;
        isInsideWindow = true;

        smokeEffect = new SmokeEffect();
        damage = 0;
        shotToQuadrant = quadrant;
        touch = new Vector3();
        vector = new Vector2();
        //System.out.println("Shot To Quadrant : " + shotToQuadrant);

    }

    public void render(SpriteBatch sb) {
        if (hit) {
            smokeEffect.render(sb, posX, posY);
            if (smokeEffect.isFinished()) {
                toRemoveThis = true;
            }
        } else {
            if (toRemoveThis == false) {
                //System.out.println("Sprite Rotation" + (float) toDegrees(shotAngle));

                sprite.setPosition(posX, posY);
                sprite.draw(sb);

            }
        }
    }

    public void update(TiledMapTileLayer collisionLayer, Camera camera) {
        if (hit == false) {

            lookNearbyCells(collisionLayer);

            System.out.println("\n &Arrow Update&");
            System.out.println("Update Tick :" + time);

            posX = (float) ArrowBallistic.getSX(posX, posY, ArrowBallistic.vo, ArrowBallistic.gravity, shotAngle, time);
            posY = (float) ArrowBallistic.getSY(posY, ArrowBallistic.vo, ArrowBallistic.gravity, shotAngle, time);

            //Fix Needed
            movingAngle = ArrowBallistic.getMovingAngle(shotAngle, shotPosX, posX, shotToQuadrant);

            System.out.println("Moving Angle : " + movingAngle);
            System.out.println("posX : " + posX);
            System.out.println("posY : " + posY);
            System.out.println("Shot Angle :" + shotAngle);

            if (!shotAngleUsed) {
                sprite.setRotation((float) Math.toDegrees(shotAngle));
                shotAngleUsed = true;
            } else {
                sprite.setRotation((float) Math.toDegrees(movingAngle));
            }
            
            time += 0.1;    //0.001

            touch.set(posX, posY, 0);
            camera.project(touch);
            vector.set(touch.x, touch.y);

            isInsideWindow = (vector.x > (-Gdx.graphics.getWidth()) && vector.x < (Gdx.graphics.getWidth() * 2)) && (vector.y > (-Gdx.graphics.getHeight()));

            if (!isInsideWindow) {

                toRemoveThis = true;

            }

        }
    }

    public boolean isIsInsideWindow() {
        return isInsideWindow;
    }

Below Now, its the ArrowBallistic Class, which i use to make the Math.

package br.weapons;

/**
 * André V Lopes 
 */
public class ArrowBallistic {

    private static int normal = 1; //TEST
    public static double vo = 20 / normal;
    public static double gravity = 2 / normal;

    public static int FIRST_QUADRANT = 1;
    public static int SECOND_QUADRANT = 2;
    public static int THIRD_QUADRANT = 3;
    public static int FOURTH_QUADRANT = 4;

    private static double atan = 0;
    private static double dx, dy;

    public static double getAngle(double posXplayer, double xClick, double posYPlayer, double yClick) {

        if (xClick < posXplayer && yClick < posYPlayer) {
            atan = Math.PI + (Math.atan((posYPlayer - yClick) / (posXplayer - xClick)));
        } else if (xClick >= posXplayer && yClick >= posYPlayer) {

            atan = Math.atan((posYPlayer - yClick) / (posXplayer - xClick));
        } else if (xClick < posXplayer && yClick >= posYPlayer) {

            atan = Math.PI - (Math.atan((yClick - posYPlayer) / (posXplayer - xClick)));

        } else if (xClick > posXplayer && yClick < posYPlayer) {
            atan = (2 * Math.PI) - (Math.atan((yClick - posYPlayer) / (posXplayer - xClick)));
        } else {
            atan = 0;
        }

        return atan;
    }

    public static double getSX(double xo, double yo, double vo, double gravity, double angle, double time) {
        dx = (xo) + vo * Math.cos(angle) * time;

        return dx;
    }

    public static double getSY(double yo, double vo, double gravity, double angle, double time) {

        dy = yo + vo * (Math.sin(angle) * time) - ((gravity / 2) * (time * time));

        return dy;
    }

    public static double getMovingAngle(double angle, double xo, double sx, int shotToQuadrant) {

        double tanO = 0;

        if (shotToQuadrant == FIRST_QUADRANT) {
            tanO = Math.atan(Math.tan(angle) - (gravity / ((vo * vo) * (Math.cos(angle) * Math.cos(angle)))) * (sx - xo));
        } else if (shotToQuadrant == SECOND_QUADRANT) {
            tanO = Math.atan(Math.PI / 2 + (Math.tan(angle) - (gravity / ((vo * vo) * (Math.cos(angle) * Math.cos(angle)))) * (sx - xo)));
        } else if (shotToQuadrant == THIRD_QUADRANT) {
            tanO = Math.atan(Math.PI + (Math.tan(angle) - (gravity / ((vo * vo) * (Math.cos(angle) * Math.cos(angle)))) * (sx - xo)));
        } else if (shotToQuadrant == FOURTH_QUADRANT) {
            tanO = Math.atan(Math.PI * 2 + (Math.tan(angle) - (gravity / ((vo * vo) * (Math.cos(angle) * Math.cos(angle)))) * (sx - xo)));
        }

        //Change quadrant Calculations
        if (shotToQuadrant == FIRST_QUADRANT && sx <= getXVertice(angle, gravity, vo, xo, sx)) {
            shotToQuadrant = FOURTH_QUADRANT;
        } else if (shotToQuadrant == SECOND_QUADRANT && sx <= getXVertice(angle, gravity, vo, xo, sx)) {
            shotToQuadrant = THIRD_QUADRANT;
        }

        return tanO;
        
        
        
    }

    public static double getXVertice(double angle, double gravity, double velocity, double xo, double dx) {
        double xv = 0;
        double b = 0;
        double a2 = 0;

        //-b
        b = -((xo * gravity) / ((velocity * velocity) * (Math.cos(angle) * Math.cos(angle))));

        //2a
        a2 = 2 * (-gravity / ((2 * (velocity * velocity)) * Math.cos(angle) * Math.cos(angle)));

        xv = b / a2;

        return xv;
    }

}

I hope this isnt too complicated for anyone to help me.

I am working on this project “by-myself”, i get help from friends here or in chat or my teachers but its just me, so i hope you understand that im really trying.

Thanks :slight_smile:

I love you dude, great idea! Working on it now, i was working in levels code, but im halting it!

Ok, i will make it read the file every frame just for debug purpose, so i can change it!

Thanks!!!

Im tweaking it, seems fun! But im still having problems with movingAngle.

Well i was able to make it slower.

 
   public static double vo = 2;
   public static double gravity = 0.02;

And now i increment time in 1.0++

 
time += 1; 

Should make things more readable.

Aside from that, i will have to find more theory knowledge.

I would try increasing your gravity first to 10 and then to 100, just to see if the arrow is actually going down at all. If it does then you know your calculations are correct and you can figure out how to tweak your numbers. Or do something simpler. The code for shooting an arrow does look overly complicated.

It does work, though the parabola seems… weird.

Was my Engineer Teacher who teached me all the math.
He checked the code last year and said it was ok, except the movingAngle, which is incomplete if i shoot to the left side.

I will try to link him this post by email and see what he thinks.Just didnt want to bother him since hes too busy.

Is all that complicated/hardToDebug math REALLY nesasary?
Why not :

(Assume)
xMomentum = 30;
yMomentum = 5;
gravity = .1;
airResistance = .975;

(Every Frame/Tick)
arrow.move(xMomentum, yMomentum);
yMomentum -= gravity;
xMomentum *= airResistance;
yMomentum *= airResistance;

Basically you’ll want to implement a time-discrete version of this formula:

p = a * t * t + v0 * t + p0

t is the time since the moment when the projectile was fired.
The other variables are vector types of the space in which the projectile travels.

p0 = starting position of the projectile
v0 = initial velocity of the projectile
a = acceleration (e.g. gravity or thrust) of the projectile

This is fairly realistic with exception of air or other media resistance and while the speed isn’t very close to the speed of light. It also assumes a flat space.

Good old way is to simply


Vector2 pos,vel,accl;

public void method()
{
vel += acc;
pos += vel; 
}


accl is gravity/other forces.

Launch the arrow via


float angle = 45;
float speed = 12;

vel.x = Math.cosDeg(angle)*speed;
vel.y = Math.sinDeg(angle)*speed;

This is not for say, “click this spot arrow moves to that spot along a cure” but “launch arrow with this velocity and seed what happens given wind and gravity.”

All code is pseudo code.

I printed this topic, i will review this with my teacher and compare to our code/idea.

Thanks all! I will post again once i have some new “floor”.

Thanks a lot! You guys are awesome for sharing knowledge :slight_smile: