2

在此处输入图像描述

从图像中您可以看到,在左侧开火的球在其后面开火,与计算出的轨迹不匹配。我使用来自 SO question的方程式绘制球轨迹,对此进行了修改以考虑每秒 30 帧的 box2d 步骤。这确实计算了一个有效的轨迹,但它与球的实际轨迹不匹配,球的轨迹较小。我正在对球施加一个 box2d 力,这也有一个密度集和一个形状。形状半径因球的种类而异。我在触地事件中设置开始速度。

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

1 回答 1

4

这是我用于我的其他游戏之一的代码,它被证明是非常精确的。诀窍是在身体上施加脉冲并读取初始速度。有了这个,我计算出身体在 0.5 秒内的 10 个位置。该语言称为 Squirrel,它基于 Lua,具有类似 C/C++ 的语法。您应该能够掌握那里发生的事情。从 getTrajectoryPointsForObjectAtImpulse 返回的是一个包含 10 个位置的数组,球将在 0.5 秒内通过这些位置。

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;
}

如果您不理解代码的任何部分,请告诉我,我会尽力解释。

于 2013-09-13T11:19:55.123 回答