Showing trajectory indicator

烂漫一生 提交于 2019-12-05 04:50:17

问题


From the image you can see that the ball fired on the left that fire behind it, does not match the calculated trajectory. Im drawing the ball trajectory using an equation from a SO question, this is modified to take into consideration the box2d steps of 30 frames per second. This does calculate a valid trajectory but it does not match the actual trajectory of the ball, the ball has a smaller trajectory. I am applying a box2d force to the ball, this also has a density set and a shape. The shape radius varies depending on the type of ball. Im setting the start velocity in the touchdown event.

public class ProjectileEquation {  

    public float gravity;  
    public Vector2 startVelocity = new Vector2();  
    public Vector2 startPoint = new Vector2();  
    public Vector2 gravityVec = new Vector2(0,-10f);

    public float getX(float n) {  
        return startVelocity.x * (n * 1/30f) + startPoint.x;  
    }  

    public float getY(float n) {
        float t = 1/30f * n;
        return 0.5f * gravity * t * t + startVelocity.y * t + startPoint.y;  
    }  



} 

@Override  
    public void draw(SpriteBatch batch, float parentAlpha) {  
        float t = 0f;  
        float width = this.getWidth();  
        float height = this.getHeight();  

        float timeSeparation = this.timeSeparation;  

        for (int i = 0; i < trajectoryPointCount; i+=timeSeparation) {  
            //projectileEquation.getTrajectoryPoint(this.getX(), this.getY(), i);
            float x = this.getX() + projectileEquation.getX(i);  
            float y = this.getY() + projectileEquation.getY(i);  

            batch.setColor(this.getColor());  
            if(trajectorySprite != null) batch.draw(trajectorySprite, x, y, width, height);  

           // t += timeSeparation;  
        }  
    } 



public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
                if(button==1 || world.showingDialog)return false;
                touchPos.set(x, y);
                float angle = touchPos.sub(playerCannon.position).angle();
                if(angle > 270 ) {
                    angle = 0;
                }
                else if(angle >70) {
                    angle = 70;
                }
                playerCannon.setAngle(angle);
                world.trajPath.controller.angle = angle;
                float radians =  (float) angle * MathUtils.degreesToRadians;
                float ballSpeed = touchPos.sub(playerCannon.position).len()*12;
                world.trajPath.projectileEquation.startVelocity.x = (float) (Math.cos(radians) * ballSpeed);
                world.trajPath.projectileEquation.startVelocity.y = (float) (Math.sin(radians) * ballSpeed);
                return true;
            }



public CannonBall(float x, float y, float width, float height, float damage, World world,  Cannon cannonOwner) {
        super(x, y, width, height, damage, world);
        active = false;
        shape = new CircleShape();
        shape.setRadius(width/2);

        FixtureDef fd = new FixtureDef();
        fd.shape = shape;
        fd.density = 4.5f;
        if(cannonOwner.isEnemy) { //Enemy cannon balls cannot hit other enemy cannons just the player
            fd.filter.groupIndex = -16;
        }
        bodyDef.type = BodyType.DynamicBody;
        bodyDef.position.set(this.position);

        body = world.createBody(bodyDef);
        body.createFixture(fd);
        body.setUserData(this);
        body.setBullet(true);
        this.cannonOwner = cannonOwner; 
        this.hitByBall = null;
        this.particleEffect = null;
    }

  private CannonBall createCannonBall(float radians, float ballSpeed, float radius, float damage)
    {
        CannonBall cannonBall =  new CannonBall(CannonEnd().x, CannonEnd().y, radius * ballSizeMultiplier, radius * ballSizeMultiplier, damage, this.world, this);
        cannonBall.velocity.x = (float) (Math.cos(radians) * ballSpeed);
        //cannonBall.velocity.x = (float) ((Math.sqrt(10) * Math.sqrt(29) *
            //  Math.sqrt((Math.tan(cannon.angle)*Math.tan(cannon.angle))+1)) / Math.sqrt(2 * Math.tan(cannon.angle) - (2 * 10 * 2)/29))* -1f;
        cannonBall.velocity.y = (float) (Math.sin(radians) * ballSpeed);
        cannonBall.active = true;
        //cannonBall.body.applyLinearImpulse(cannonBall.velocity, cannonBall.position);
        cannonBall.body.applyForce(cannonBall.velocity, cannonBall.position );
        return cannonBall;
    }


trajPath = new TrajectoryActor(-10f);
        trajPath.setX(playerCannon.CannonEnd().x);
        trajPath.setY(playerCannon.CannonEnd().y);
        trajPath.setWidth(10f);
        trajPath.setHeight(10f);
        stage.addActor(trajPath);

回答1:


Here is a code that I used for one of my other games, which proved to be very precise. The trick is to apply the impulse on the body and read the initial velocity. Having that I calculate 10 positions where the body will be within 0.5 seconds. The language is called Squirrel which is Lua based with C/C++ like syntax. You should be able to grasp what is going on there. What returns from the getTrajectoryPointsForObjectAtImpulse is an array of 10 positions through which the ball will pass within 0.5 seconds.

const TIMESTER_DIVIDOR = 60.0;

function getTrajectoryPoint( startingPosition, startingVelocity, n )
{
    local gravity = box2DWorld.GetGravity();
    local t = 1 / 60.0;
    local stepVelocity =  b2Vec2.Create( t * startingVelocity.x, t * startingVelocity.y );
    local stepGravity = b2Vec2.Create( t * t * gravity.x, t * t * gravity.y );

    local result = b2Vec2.Create( 0, 0 );
    result.x = ( startingPosition.x + n * stepVelocity.x + 0.5 * ( n * n + n ) * stepGravity.x ) * MTP;
    result.y = ( startingPosition.y + n * stepVelocity.y + 0.5 * ( n * n + n ) * stepGravity.y ) * -MTP;

    return result;
}

function getTrajectoryPointsForObjectAtImpulse (object, impulse) 
{
    if( !object || !impulse ) return [];

    local result = [];

    object.bBody.ApplyLinearImpulse( impulse, object.bBody.GetWorldCenter() );

    local initialVelocity = object.bBody.GetLinearVelocity();

    object.bBody.SetLinearVelocity( b2Vec2.Create(0, 0) );
    object.bBody.SetActive(false);

    for ( local i = 0.0 ; i < ( 0.5 * TIMESTER_DIVIDOR ) ; )
    {
        result.append( getTrajectoryPoint(object.bBody.GetPosition(), initialVelocity, i.tointeger() ) );

        i += ( (0.5 * TIMESTER_DIVIDOR) * 0.1 );
    }
    return result;
}

If you do not understand any part of the code, please let me know and I will try to explain.



来源:https://stackoverflow.com/questions/18713856/showing-trajectory-indicator

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!