0

1280 x 1280 ピクセルのマップがあります。画面に 32 x 32 ピクセルのタイルを描画しています。また、各タイルに 32 x 32 ピクセルの長方形を指定します。各タイルには、ブロックされているかどうかを示すブール値もあります。私のスプライトには、32 x 32 ピクセルの長方形があります。

スプライトとタイルが交差するとき、タイルの左上端のピクセルだけがスプライトの四角形と接触します。

長方形を変更せずに膨らませてみました。

Core.playerOneSpriteRectangle = new Rectangle((int)Core.playerOneSprite.Position.X, (int)Core.playerOneSprite.Position.Y, Engine.TileWidth, Engine.TileHeight);

        #region Player One Controls
        // Player One Controls
        Tile tile;
        Rectangle destination = new Rectangle(0, 0, Engine.TileWidth, Engine.TileHeight);
        if (keyState.IsKeyDown(Keys.W) || (gamePadOneState.DPad.Up == ButtonState.Pressed))
        {
            Core.playerOneSprite.CurrentAnimation = AnimationKey.Up;
            foreach (var layer in tileMapLayers)
            {
                for (var y = 0; y < layer.Height; y++)
                {
                    destination.Y = y * Engine.TileHeight;
                    for (var x = 0; x < layer.Width; x++)
                    {
                        tile = layer.GetTile(x, y);

                        destination.X = x * Engine.TileWidth;

                        // Check Collision With Tiles
                        if (Core.playerOneSpriteRectangle.Intersects(destination) && tile.TileBlocked)
                        {
                            playerOneMotion.Y = destination.Bottom;
                            //Console.WriteLine("Intersected with" + destination + tile.TileBlocked);
                        }
                        else if (Core.playerOneSpriteRectangle.Intersects(destination) && tile.TileBlocked == false)
                        {
                            playerOneMotion.Y = -1f;
                        }  
                    }
                }
            }
        }

スプライトが四角形を通過しないように、各タイルに四角形を作成しようとしています。

アップデート

これは、提案で修正した後の現在のコードです。

Tile tile;
        Point playertile = new Point((int)Core.playerOneSprite.Position.X / Engine.TileWidth, (int)Core.playerOneSprite.Position.Y / Engine.TileHeight);

        if (keyState.IsKeyDown(Keys.W) || (gamePadOneState.DPad.Up == ButtonState.Pressed))
        {
            Core.playerOneSprite.CurrentAnimation = AnimationKey.Up;
            foreach (var layer in GraelenAreaOne.graelenAreaOneSplatterTileMapLayers)
            {
                tile = layer.GetTile(playertile.X, playertile.Y - 1);

                // Check Collision With Tiles
                if (tile.TileBlocked)
                {
                    playerOneMotion.Y = 0;

                    //Console.WriteLine("Intersected with" + destination + tile.TileBlocked);
                }
                else
                {
                    playerOneMotion.Y = -1;
                }  
            }
        }

タイルと衝突できるようになりましたが、スプライトの四角形が正しく交差しません。スプライト テクスチャの位置 0,0 は左上隅にあり、1x1 ピクセルのみです。32x32 に設定したのに、長方形がテクスチャ全体を取り囲んでいないのはなぜですか?

4

1 に答える 1

3

四角形に煩わされることなく、行きたいタイルが歩行可能かどうかを確認するだけです。

いくつかの擬似コード:

// Convert pixel coordinates to tile coords
Point playerTile = new Point(player.X / tileWidth, player.Y / tileHeight);
Point targetTile = new Point(target.X / tileWidth, target.Y / tileHeight);

// Take a decision 
if(Direction == Up)
    var tile = layer.GetTile(playerTile.X, playerTile.Y - 1);
    if(tile == walkable)
        // Move to your tile
    else
        ...

さらに、表示されているものだけを描画することでレベルの描画を最適化することに興味があるかもしれない、少し前に書いたコードを次に示します。

https://gamedev.stackexchange.com/questions/29121/organize-a-game-set/29930#29930

ここに画像の説明を入力

注 : https://gamedev.stackexchange.com/は、これらの種類の質問に適した場所です。

編集

これが私にとってうまくいく簡単な例です:

プレイヤーがタイルに移動できない場合は戻ることに注意してください。

タイル : 0 は歩行可能、1 は壁、2 はプレイヤー

using System;
using System.Linq;
using System.Windows;
using System.Windows.Navigation;
using Microsoft.Phone.Controls;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input.Touch;
using Point = Microsoft.Xna.Framework.Point;

namespace SlXnaApp1
{
    public partial class GamePage : PhoneApplicationPage
    {
        private readonly GameTimer _timer;
        private int[] _levels;
        private Point _player;
        private Texture2D _t1;
        private Texture2D _t2;
        private Texture2D _t3;
        private Texture2D[] _textures;
        private ContentManager _contentManager;
        private SpriteBatch _spriteBatch;

        public GamePage()
        {
            InitializeComponent();

            // Get the content manager from the application
            _contentManager = (Application.Current as App).Content;

            // Create a timer for this page
            _timer = new GameTimer();
            _timer.UpdateInterval = TimeSpan.FromTicks(333333);
            _timer.Update += OnUpdate;
            _timer.Draw += OnDraw;
        }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            // Set the sharing mode of the graphics device to turn on XNA rendering
            var graphicsDevice = SharedGraphicsDeviceManager.Current.GraphicsDevice;
            graphicsDevice.SetSharingMode(true);

            // Create a new SpriteBatch, which can be used to draw textures.
            _spriteBatch = new SpriteBatch(graphicsDevice);

            // TODO: use this.content to load your game content here
            _t1 = new Texture2D(graphicsDevice, 32, 32);
            _t1.SetData(Enumerable.Repeat(Color.Red, 32*32).ToArray());
            _t2 = new Texture2D(graphicsDevice, 32, 32);
            _t2.SetData(Enumerable.Repeat(Color.Green, 32*32).ToArray());
            _t3 = new Texture2D(graphicsDevice, 32, 32);
            _t3.SetData(Enumerable.Repeat(Color.Blue, 32*32).ToArray());
            _textures = new[] {_t1, _t2, _t3};
            _levels = new int[4*4]
                {
                    2, 0, 0, 0,
                    0, 0, 1, 0,
                    1, 1, 1, 0,
                    0, 0, 0, 1,
                };
            _player = new Point();

            TouchPanel.EnabledGestures = GestureType.Flick;
            // Start the timer
            _timer.Start();

            base.OnNavigatedTo(e);
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            // Stop the timer
            _timer.Stop();

            // Set the sharing mode of the graphics device to turn off XNA rendering
            SharedGraphicsDeviceManager.Current.GraphicsDevice.SetSharingMode(false);

            base.OnNavigatedFrom(e);
        }

        /// <summary>
        ///     Allows the page to run logic such as updating the world,
        ///     checking for collisions, gathering input, and playing audio.
        /// </summary>
        private void OnUpdate(object sender, GameTimerEventArgs e)
        {
            Vector2 vector = new Vector2();
            while (TouchPanel.IsGestureAvailable)
            {
                var gestureSample = TouchPanel.ReadGesture();
                var vector2 = gestureSample.Delta;
                vector2.Normalize();
                vector = new Vector2((float) Math.Round(vector2.X), (float) Math.Round(vector2.Y));
            }

            Direction direction = new Direction();
            if (vector.X > 0) direction = Direction.Right;
            else if (vector.X < 0) direction = Direction.Left;
            else if (vector.Y < 0) direction = Direction.Up;
            else if (vector.Y > 0) direction = Direction.Down;

            Point newPos = new Point();
            switch (direction)
            {
                case Direction.None:
                    return;
                case Direction.Up:
                    if (GetTile(_player.X, _player.Y - 1) == 0)
                        newPos = new Point(_player.X, _player.Y - 1);
                    else return;
                    break;
                case Direction.Down:
                    if (GetTile(_player.X, _player.Y + 1) == 0)
                        newPos = new Point(_player.X, _player.Y + 1);
                    else return;
                    break;
                case Direction.Left:
                    if (GetTile(_player.X - 1, _player.Y) == 0)
                        newPos = new Point(_player.X - 1, _player.Y);
                    else return;
                    break;
                case Direction.Right:
                    if (GetTile(_player.X + 1, _player.Y) == 0)
                        newPos = new Point(_player.X + 1, _player.Y);
                    else return;
                    break;
                default:
                    throw new ArgumentOutOfRangeException();
            }

            SetTile(_player.X, _player.Y, 0);
            SetTile(newPos.X, newPos.Y, 2);
            _player = newPos;
        }

        private int GetTile(int x, int y)
        {
            return _levels[y*4 + x];
        }

        private void SetTile(int x, int y, int value)
        {
            _levels[y*4 + x] = value;
        }

        /// <summary>
        ///     Allows the page to draw itself.
        /// </summary>
        private void OnDraw(object sender, GameTimerEventArgs e)
        {
            SharedGraphicsDeviceManager.Current.GraphicsDevice.Clear(Color.CornflowerBlue);
            _spriteBatch.Begin();
            for (int i = 0; i < _levels.Length; i++)
            {
                var tile = _levels[i];
                Point point = new Point(i%4, i/4);
                var texture2D = _textures[tile];
                _spriteBatch.Draw(texture2D, Vector2.Multiply(new Vector2(point.X, point.Y), 32), Color.White);
            }
            _spriteBatch.End();
        }

        private enum Direction
        {
            None,
            Up,
            Down,
            Left,
            Right
        }
    }
}

また、レベルを 1 次元配列として作成した方法により、たとえば x=3、y=0 で右に移動すると、タイルが下に移動します。これはまったく意図したものではありませんが、境界をチェックしないので正常です。簡単にするために、レベルを 2 次元配列として保持する必要があります。

于 2013-07-02T00:53:28.537 に答える