6

車が星にぶつかったときに、星 (私のコードではコイン) を画面の右上隅に正確に移動したいと考えています。星と道路の両方が、各更新中に一定の速度で下に移動しています。車は動かないが、道路が下に動いているため、上に動いているように見える。ユーザーのコマンドで左右の車線に移動できますが。

そこで、次の方法を使用して、星と画面の右上隅の間の角度を計算しました

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

私のUpdate方法では、以下は移動する速度を計算し、画面の右上隅に送信します

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

私の方法では、 usingDrawを更新しましたcoin.Position

coin.Position += collidedCoinVelocity * 10 ;

問題は、スター (コイン) が思ったように右上隅に送信されず、右画面の中央のどこかにバインドされていることです。

スターが右レーンにあるときにヒットすると、スターと右上隅の間の角度は常に

1.2196048576751 radians = 69.878211 degree

星が左車線にある場合、角度は

0.952588487628243 radians = 54.5793 degree

角度を正しく計算していますが、何が欠けていますか? 星の下向きの動きを忘れているのではないでしょうか?

ここに画像の説明を入力

ここに画像の説明を入力

編集

計算しようとしている角度を示すように画像を更新し、質問を編集してより明確にしました。

編集2

攻撃を受けた後の星の移動先を示す 2 番目の画像を追加しました。

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 で位置を更新しないでください。Draw は描画用であり、更新用ではありません。アップデートはアップデートのまま!

また 2; コードを一般化する必要があります。すべての移動オブジェクトは、速度、位置、加速度などを含む同じベースと、これらを処理するコードを継承する必要があります。そうすれば、ロジックを変更して速度や加速度を操作して物を動かすだけで済みます。

MovingObject.Update:

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

(deltaTime = 最後のフレームからの秒数、または (float)gameTime.ElapsedGameTime.TotalSeconds)

次に、サブクラスの更新の最後に base.Update() を使用するだけで、正しい値を設定している限り、位置と速度が機能します:)。

于 2013-09-16T12:44:56.700 に答える
0

Vector2ポイント間の補間のための静的関数を提供します。

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

このメソッドを使用して、星がヒットしたときに、ポイント A とポイント B を設定
し、関数に渡しVector2.Lerpます。float 値を
含めます。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 に答える