6

I want to move the star (coin in my code) to the exact top right corner of the screen when the car hit the star. Both star and road are moving downward at a constant speed during each update. The car does not move but appears to be moving upward because of the road moving downward. Although it can move to the left and right lane on user's command.

So I calculated the angle between the star and the top right corner of the screen using the following method

public double AngleBetween(Vector2 a, Vector2 b)
{
    return Math.Atan2(b.Y - a.Y, b.X - a.X);
}

In my Update method, the following calculate the velocity to move and send it to the top right corner of the screen

double angleBetween = coin.AngleBetween(coin.Position, new
   Vector2(currentGame.GraphicsDevice.Viewport.Bounds.Right, 0));              
collidedCoinVelocity = new Vector2((float)Math.Sin(angleBetween), 
   -(float)Math.Cos(angleBetween));

In my Draw method, I updated the coin.Position using

coin.Position += collidedCoinVelocity * 10 ;

The problem is the star (coin) is not sent to the top right corner as I wanted but it's somewhere in the middle of the right screen bound.

When the star is hit when it's on the right lane, the angle between it and the top right corner is always

1.2196048576751 radians = 69.878211 degree

When the star is on the left lane the angle is

0.952588487628243 radians = 54.5793 degree

Am I calculating the angle correctly, what am I missing? Perhaps I am forgetting to consider the downward movement of the star?

enter image description here

enter image description here

EDIT

I have updated the image to show the angle I am trying to calculate and edited my question to make it clearer.

EDIT 2

Added a second image to show where the star goes after being hit.

4

4 回答 4

4

看来你是不小心交换了 sin 和 cos,而且里面似乎有一个随机的负数。因此这条线

collidedCoinVelocity = new Vector2((float)Math.Sin(angleBetween), 
   -(float)Math.Cos(angleBetween));

应该是

collidedCoinVelocity = new Vector2((float)Math.Cos(angleBetween), 
   (float)Math.Sin(angleBetween));

虽然你甚至不需要计算这么多角度。要获得没有角度的单位向量,只需使用

double dx = b.X - a.X;
double dy = b.Y - a.Y;
double mag = Math.Sqrt(dx * dx + dy * dy);
collidedCoinVelocity = new Vector2(dx, dy) / mag;
于 2013-09-14T04:28:57.503 回答
2

嗯...仅供参考;从笛卡尔坐标转换为使用角度,然后再转换为笛卡尔坐标在这里没有任何意义。

只需像这样得出您的最终速度:

Vector2 direction = new Vector2(currentGame.GraphicsDevice.Viewport.Bounds.Right, 0) - coin.Position;
direction.Normalize();

Velocity = direction * 10;
Position += Velocity;

还; 永远不要在 Draw 中更新位置。绘图用于绘图,而不是更新。更新停留在更新中!

还有2个;您应该概括您的代码。所有移动对象都应该继承相同的基础,包括速度、位置和加速度等内容,以及处理这些内容的代码。这样,你只需要改变你的逻辑来操纵速度和/或加速度来让东西移动。

移动对象更新:

Velocity += Acceleration * deltaTime;
Positioin += Velocity * deltaTime;

(deltaTime = 自上一帧以来的秒数,或 (float)gameTime.ElapsedGameTime.TotalSeconds)

然后,您只需在子类更新结束时使用 base.Update(),只要您设置正确的值,位置和速度就会起作用:)。

于 2013-09-16T12:44:56.700 回答
1

我认为你应该这样做:

public double AngleBetween(Vector2 a, Vector2 b)
{
    return Math.Atan2(-(b.Y - a.Y), b.X - a.X);
}

考虑到反转的 Y 轴,您需要否定 Y 分量。

然后,正如宗政礼所写,你已经交换了 Sin 和 Cos:

collidedCoinVelocity = new Vector2((float)Math.Cos(angleBetween), 
   -(float)Math.Sin(angleBetween));

Vector2.Y但由于 Y 轴反转,您仍然需要否定该组件。

于 2013-09-14T21:36:37.847 回答
0

Vector2提供点之间插值的静态函数。

star_pos = Vector2.Lerp(position_when_hit, destinatin, percent);
                percent += 0.005f;

使用这种方法,当星星被击中时,设置点 A 和点 B。
将其传递给Vector2.Lerp函数。
包括一个Percentage_of_distance_moved浮点值。

这是修改后的星类:

class star
    {
        Texture2D starT;
        public Vector2 star_pos;
        Vector2 position_when_hit;
        Vector2 destinatin;
        float percent;
        bool star_moving_up;

        public star(Random rand,Texture2D star)
        {
            this.starT = star;
            star_moving_up = false;
            destinatin = new Vector2(800, 0);
            star_pos = new Vector2(rand.Next(500), rand.Next(500));
        }
//Try to call this only once
        public void on_hit(){
            if (!star_moving_up)
            {
                position_when_hit = star_pos;
                star_moving_up = true;
            }
        }

        public void update(GameTime gameTime)
        {
            if (star_moving_up)
            {
                star_pos = Vector2.Lerp(position_when_hit, destinatin, percent);
                //a larger percent value will move the star faster.
                percent += 0.001f;
            }
            else
            {
                //Your Logic for moving it down
            }
        }

        public void draw(SpriteBatch sp)
        {
            sp.Draw(starT, star_pos, Color.White);
        }
}

这就是我使用它的方式:

public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Texture2D star;
        Random rand;
        star STAR;



public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }


    protected override void Initialize()
    {
        graphics.PreferredBackBufferWidth = 800;
        graphics.PreferredBackBufferHeight = 600;

        base.Initialize();
    }


    protected override void LoadContent()
    {
        rand = new Random();
        spriteBatch = new SpriteBatch(GraphicsDevice);            
        star = Content.Load<Texture2D>("Bitmap1");
        STAR = new star(rand, star);

    }


    protected override void UnloadContent()
    {

    }


    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();
//calls on_hit every update call after 4 seconds. just for demo purpose. 
        if (gameTime.TotalGameTime > TimeSpan.FromSeconds(4))
            STAR.on_hit();
        STAR.update(gameTime);
        base.Update(gameTime);
    }


    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);

        spriteBatch.Begin();
        STAR.draw(spriteBatch);
        spriteBatch.End();
        base.Draw(gameTime);
    }
}
于 2013-09-15T18:09:59.500 回答