0

スプライトを簡単に回転できますが、衝突のために長方形を回転させるにはどうすればよいですか (分離軸定理を使用することを考えていますが、それを適用する方法がわかりません) ヘルプまたは例をいただければ幸いです :)

ゲーム 1 クラス:

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace CombatTank
{

public class Game1 : Microsoft.Xna.Framework.Game
{
    //Declare Graphic Manager & Spritebatch
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    //Declare Player 1
    theBody player1TankBody;

    //Declare Player 2
    theBody player2TankBody;

    //Save Player 1 Position
    Vector2 savedPlayer1TankBodyPosition;

    //Save Player 2 Position
    Vector2 savedPlayer2TankBodyPosition;

    //Declare Keyboard States
    KeyboardState currentkeyboardState;
    KeyboardState previousKeyboardState;


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

    protected override void Initialize()
    {
        //TankBody Position Player 1
        Vector2 player1TankBodyPosition = new Vector2(200, 200);
        Vector2 player2TankBodyPosition = new Vector2(400, 200);

        //TankBody Scale 
        float player1TankBodyScale = 1.0F;
        float player2TankBodyScale = 1.0F;

        //TankBody Rotation
        float player1TankBodyRotation = 0.0F;
        float player2TankBodyRotation = 0.0F;

        //TankBody Color
        Color player1TankBodyColor = Color.Red;
        Color player2TankBodyColor = Color.Blue;

        //Create Tank
        player1TankBody = new theBody(player1TankBodyPosition,player1TankBodyScale, player1TankBodyRotation, player1TankBodyColor);
        player2TankBody = new theBody(player2TankBodyPosition, player2TankBodyScale, player2TankBodyRotation, player2TankBodyColor);

        base.Initialize();
    }

    protected override void LoadContent()
    {
        //Create New SpriteBatch
        spriteBatch = new SpriteBatch(GraphicsDevice);

        //Load The Player 1 TankBody Texture
        Texture2D player1SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player1TankBody.LoadContent(Content,"TankBody");

        //Extract Collision Data For Player 1
        player1TankBody.TankBodyTextureData = new Color[player1TankBody.Texture.Width * player1TankBody.Texture.Height];
        player1TankBody.Texture.GetData(player1TankBody.TankBodyTextureData);

        //Load The Player 2 TankBody Texture
        Texture2D player2SpriteTankBody = Content.Load<Texture2D>("TankBody");
        player2TankBody.LoadContent(Content, "TankBody");

        //Extract Collision Data For Player 2
        player2TankBody.TankBodyTextureData = new Color[player2TankBody.Texture.Width * player2TankBody.Texture.Height];
        player2TankBody.Texture.GetData(player2TankBody.TankBodyTextureData);

    }

    protected override void UnloadContent()
    {

    }


    protected override void Update(GameTime gameTime)
    {
        //Save Player 1 Postion
        savedPlayer1TankBodyPosition.X = player1TankBody.Position.X;
        savedPlayer1TankBodyPosition.Y = player1TankBody.Position.Y;

        //Save Player 2 Position
        savedPlayer2TankBodyPosition.X = player2TankBody.Position.X;
        savedPlayer2TankBodyPosition.Y = player2TankBody.Position.Y;

        //Updates Player 1
        UpdatePlayer1(gameTime);

        //Update Player 2
        UpdatePlayer2(gameTime);

        //Collision Player 1
        CollisionPlayer1(gameTime);

        //Collision Player 2
        CollisionPlayer2(gameTime);

        base.Update(gameTime);
    }

    private void UpdatePlayer1(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.W))
        {
            //Move Tank Forward
            player1TankBody.Position.X -= 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y -= 5 * (float)Math.Sin(player1TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.S))
        {
            //Move Tank Backwards
            player1TankBody.Position.X += 5 * (float)Math.Cos(player1TankBody.Rotation);
            player1TankBody.Position.Y += 5 * (float)Math.Sin(player1TankBody.Rotation);

        }
        if (currentkeyboardState.IsKeyDown(Keys.A))
        {
            player1TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.D))
        {
            player1TankBody.Rotation += 0.03f;
        }

    }

    private void UpdatePlayer2(GameTime gameTime)
    {
        //Save the previous state of the keyboard
        previousKeyboardState = currentkeyboardState;

        //Read the current state of the keyboard
        currentkeyboardState = Keyboard.GetState();

        //TankBody Movement
        if (currentkeyboardState.IsKeyDown(Keys.Up))
        {
            //Move Tank Forward
            player2TankBody.Position.X -= 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y -= 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Down))
        {
            //Move Tank Backward
            player2TankBody.Position.X += 5 * (float)Math.Cos(player2TankBody.Rotation);
            player2TankBody.Position.Y += 5 * (float)Math.Sin(player2TankBody.Rotation);
        }
        if (currentkeyboardState.IsKeyDown(Keys.Left))
        {
            player2TankBody.Rotation -= 0.03f;
        }
        if (currentkeyboardState.IsKeyDown(Keys.Right))
        {
            player2TankBody.Rotation += 0.03f;
        }

    }

    private void CollisionPlayer1(GameTime gameTime)
    {


        if (IntersectPixels(player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData, player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData))
        {
            player1TankBody.Position.X = savedPlayer1TankBodyPosition.X;
            player1TankBody.Position.Y = savedPlayer1TankBodyPosition.Y;

        }



    }

    private void CollisionPlayer2(GameTime gameTime)
    {
        if (IntersectPixels(player2TankBody.BoundingBox, player2TankBody.TankBodyTextureData, player1TankBody.BoundingBox, player1TankBody.TankBodyTextureData))
        {
            player2TankBody.Position.X = savedPlayer2TankBodyPosition.X;
            player2TankBody.Position.Y = savedPlayer2TankBodyPosition.Y;

        }
    }


    static bool IntersectPixels(Rectangle rectangleA, Color[] dataA, Rectangle rectangleB, Color[] dataB)
    {
        //Find top Bound of the Rectangle
        int top = Math.Max(rectangleA.Top, rectangleB.Top);
        int bottom = Math.Min(rectangleA.Bottom, rectangleB.Bottom);
        int left = Math.Max(rectangleA.Left, rectangleB.Left);
        int right = Math.Min(rectangleA.Right, rectangleB.Right);

        for (int y = top; y < bottom; y++)
        {
            for (int x = left; x < right; x++)
            {
                //Get Color of both Pixels
                Color colorA = dataA[(x - rectangleA.Left) + (y - rectangleA.Top) * rectangleA.Width];
                Color colorB = dataB[(x - rectangleB.Left) + (y - rectangleB.Top) * rectangleB.Width];

                //Both pixel are not completely Transparent
                if (colorA.A != 0 && colorB.B != 0)
                {
                    //Then an intersection is found 
                    return true;
                }

            }

        }


        //No Intersection
        return false;
    }





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

        spriteBatch.Begin();

        player1TankBody.Draw(spriteBatch);
        player2TankBody.Draw(spriteBatch);

        spriteBatch.End();

        base.Draw(gameTime);
    }
}
}

theBody クラス:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;
using Microsoft.Xna.Framework.Content;

namespace CombatTank
{
class theBody
{
    //TankBody Texture
    private Texture2D texture;
    public Texture2D Texture
    {
        get
        { 
            return texture; 
        }
    }

    //TankBody Height
    private float height;
    public float Height
    {
        get
        {
            return height;
        }
    }

    //TankBody Width
    private float width;
    private float Width
    {
        get
        {
            return width;
        }

    }

    //TankBody Position
    public Vector2 Position;

    //TankBody Origin
    public Vector2 Origin;

    //TankBody Rotation
    public float Rotation = 0.0F;

    //TankBody Color
    public Color Color = Color.White;

    //TankBody Scale
    public float Scale = 1F;

    //TankBody BoundingBox
    public Rectangle BoundingBox
    {
        get
        {
            return new Rectangle((int)Position.X, (int)Position.Y, (int)texture.Width, (int)texture.Height);
        }
    }

    //TankBody color Data(Used For Pixel Collision)
    public Color[] TankBodyTextureData;

    //TankBody Constructor
    public theBody(Vector2 position,float scale,float rotation, Color color)
    {
        Position = position;
        Scale = scale;
        Rotation = rotation;
        Color = color;
    }

    //LoadContent
    public void LoadContent(ContentManager contentManager, string assetname)
    {
        texture = contentManager.Load<Texture2D>(assetname);
        Origin = new Vector2(Texture.Width / 2, Texture.Height / 2);
    }

    //Draw
    public virtual void Draw(SpriteBatch spriteBatch)
    {
        spriteBatch.Draw(texture, Position, null, Color, Rotation, Origin, Scale, SpriteEffects.None, 0);
    }

    //Update
    public void Update(GameTime gameTime)
    {

    }
}
}
4

3 に答える 3

1

これが物理エンジンのコーディング方法を学習するための練習でない限り、車輪を再発明するのではなく、無料の 2D 衝突/物理ライブラリを使用することをお勧めします。Box2Dが思い浮かびます。

透明度に基づいて、テクスチャ間でピクセルごとの衝突を実行しようとしていることに気付きました。現代のゲーム (非常に小さなゲームであっても) は、コンベックスに基づいて衝突と物理演算を行います。これにより、より洗練された衝突結果を得ることができます (2 つのピクセルがヒットした場合、法線はどうなるでしょうか?)。

于 2013-02-03T07:42:21.083 に答える
0

AABB を使用していて、スプライトを回転させようとしているので、AABB (つまり、OBB) を回転させる必要があることを質問で理解しています。

私が間違っていない場合、それがあなたのケースである場合、1つのアプローチはあなたが提案したものです:SAT. しかし、別のアプローチは AABB を使用することです。

OBB は、独自の座標系で定義された唯一の AABB であることに注意してください (オブジェクトに AABB をより適切に適合させる最適な座標系)。2 つの OOBB (A と B) があるため、2 つの座標系に 2 つの AABB があります。

Bの AABB を取得し、Aの座標系でその AABB を計算します (この新しい AABB を"C"と呼ぶことができます)。CA の衝突の AABB を確認します。次に、逆の順序で同じことを行います ( Bの座標系でAの AABB (これを新しい AABB "D"と呼びます)、 Bの AABB との衝突をチェックします)。

2 つのチェックが衝突した場合、OBB は衝突しています。写真を見てください:

ここに画像の説明を入力

于 2013-07-14T22:04:54.153 に答える
0

私はあなたのコードをまだ見ていませんが、コード例で SAT を説明する良いチュートリアルがあります。C# ではありませんが、変換は簡単です ;)

于 2013-07-14T23:49:58.773 に答える