Сфера модели XNA не столкнется с одной или всеми четырьмя сетками - PullRequest
1 голос
/ 12 декабря 2011

Как вы можете видеть на скриншоте ниже, мое желаемое поведение:

  • сфера начинается в середине арены
  • когда вы нажимаете ввод, он перемещается в случайном направлении
  • когда он сталкивается с одной из четырех стен, он отскакивает назад в противоположном направлении под случайным углом от 0 до 45 градусов

Проблема, которая не показана на рисунке ниже, состоит в том, что мяч проходит прямо через любую из стен, вместо того, чтобы сталкиваться или подпрыгивать.

Я попытался обновить модельное положение сферы шара, но она все равно не обрежет его. Я попытался установить радиус шара на большое число, например, 100, но он сталкивается, когда начинает двигаться, прежде чем ударится о стену и начнет вибрировать.

Visual Screenshot Of World Space

Исходный код (Ball.cs):

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 _3D_Pong
{
    class Ball
    {
        private Model model;
        private Vector3 modelpos;
        private Random random = new Random();
        public Vector3 ModelPosition { get; set; }
        private Vector3 FowardDirection { get; set; }
        private float randomangle;
        private int direction = 0;
        private bool start = false;
        private int v;
        public Ball(Model m, Vector3 initial_position, int velocity = 30)
        {
            v = velocity;
            model = m;
            modelpos = initial_position;
            randomangle = MathHelper.ToRadians(random.Next(0, 45));
            direction = random.Next(1);
            FowardDirection = Matrix.CreateRotationY(randomangle).Forward;

        }
        public void BeginMoving()
        {
            start = true;
        }
        private BoundingSphere BallsBounds()
        {
            Matrix worldTransform = Matrix.CreateTranslation(modelpos);
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[0];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]),  worldTransform);
                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }

            BoundingSphere sphere = BoundingSphere.CreateFromBoundingBox(new BoundingBox(min, max));
            return sphere;
        }
        public void Draw(Camera camera, ArenaRenderer arena)
        {
            if (start)
            {


                bool predicate1, predicate2, predicate3, predicate4;
                predicate1 = BallsBounds().Intersects(arena.FirstWall());
                predicate2 = BallsBounds().Intersects(arena.SecondWall());
                predicate3 = BallsBounds().Intersects(arena.ThirdWall());
                predicate4 = BallsBounds().Intersects(arena.FourthWall());
                if (predicate1 || predicate2 || predicate3 || predicate4)
                {
                    if (direction == 0)
                    {
                        direction = 1;
                        randomangle = MathHelper.ToRadians(random.Next(0, 45));
                        FowardDirection = Matrix.CreateRotationY(randomangle).Forward;

                    }
                    else if (direction == 1)
                    {
                        direction = 0;
                        randomangle = MathHelper.ToRadians(random.Next(0, 45));
                        FowardDirection = Matrix.CreateRotationY(randomangle).Forward;
                    }
                }
                if (direction == 1)
                {
                    modelpos += FowardDirection * v;
                }
                else
                {
                    modelpos -= FowardDirection * v;
                }
            }
            model.Draw(Matrix.CreateTranslation(modelpos), camera.View, camera.Projection);
        }
    }
}

Источник (Arena.cs)

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 _3D_Pong
{
    class ArenaRenderer
    {
        private Model model;
        public ArenaRenderer(Model m)
        {
            model = m;
        }
        public BoundingBox FirstWall()
        {
            Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero);
            // Initialize minimum and maximum corners of the bounding box to max and min values
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[0];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                // Vertex buffer parameters
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                // Get vertex data as float
                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform);

                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }


            // Create and return bounding box
            return new BoundingBox(min, max);
        }
        public BoundingBox SecondWall()
        {
            Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero);
            // Initialize minimum and maximum corners of the bounding box to max and min values
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[1];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                // Vertex buffer parameters
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                // Get vertex data as float
                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform);

                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }


            // Create and return bounding box
            return new BoundingBox(min, max);
        }
        public BoundingBox ThirdWall()
        {
            Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero);
            // Initialize minimum and maximum corners of the bounding box to max and min values
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[2];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                // Vertex buffer parameters
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                // Get vertex data as float
                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform);

                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }


            // Create and return bounding box
            return new BoundingBox(min, max);
        }
        public BoundingBox FourthWall()
        {
            Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero);
            // Initialize minimum and maximum corners of the bounding box to max and min values
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[3];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                // Vertex buffer parameters
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                // Get vertex data as float
                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform);

                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }


            // Create and return bounding box
            return new BoundingBox(min, max);
        }

        public void Draw(Camera camera)
        {

            model.Draw(Matrix.CreateTranslation(Vector3.Zero), camera.View, camera.Projection);
        }
    }
}

Я не реализовал весла, пока не решу проблему обнаружения столкновений. Если мне не хватает информации, пожалуйста, оставьте комментарий, я перепробовал все, что мог придумать.

Я изменил его, поэтому для каждой стены есть одна функция.

 public BoundingBox GetWallBounds(int index)
        {
            Matrix worldTransform = Matrix.CreateTranslation(Vector3.Zero);
            // Initialize minimum and maximum corners of the bounding box to max and min values
            Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
            Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);

            ModelMesh mesh = model.Meshes[index];
            foreach (ModelMeshPart meshPart in mesh.MeshParts)
            {
                // Vertex buffer parameters
                int vertexStride = meshPart.VertexBuffer.VertexDeclaration.VertexStride;
                int vertexBufferSize = meshPart.NumVertices * vertexStride;

                // Get vertex data as float
                float[] vertexData = new float[vertexBufferSize / sizeof(float)];
                meshPart.VertexBuffer.GetData<float>(vertexData);

                // Iterate through vertices (possibly) growing bounding box, all calculations are done in world space
                for (int i = 0; i < vertexBufferSize / sizeof(float); i += vertexStride / sizeof(float))
                {
                    Vector3 transformedPosition = Vector3.Transform(new Vector3(vertexData[i], vertexData[i + 1], vertexData[i + 2]), worldTransform);

                    min = Vector3.Min(min, transformedPosition);
                    max = Vector3.Max(max, transformedPosition);
                }
            }


            // Create and return bounding box
            return new BoundingBox(min, max);
        }

Ответы [ 2 ]

2 голосов
/ 13 декабря 2011

Общий совет: в XNA не следует обнаруживать столкновения в методе Draw. Этот метод может вызываться менее 60 раз в секунду. Вы должны сделать это в методе Update вашего класса. См. здесь для подробного объяснения.

Я думаю, что ваше обнаружение столкновений неверно. Вам нужно отразить угол направления, а не просто выбрать случайное направление.

Также вам нужно добавить вектор скорости, который будет добавлен к вашей текущей позиции. С таким вектором работать намного проще, чем пытаться работать с позицией напрямую.

Существует множество учебных пособий по реализации Pong в C #. Это всего лишь образец:

http://www.freewebs.com/campelmxna/XNATutorials/XNATut4.htm

Обратите внимание, что у вас есть два разных члена, один представляет позицию, а другой - скорость, которая будет добавляться к позиции при каждом обновлении.

Кроме того, возможно, что дельта, которую вы добавляете в положение мяча каждый раз, слишком велика, поэтому она "пропускает" ограничивающие стены. Вы можете 1) уменьшить дельту или 2) сделать ваши ограничивающие стены шире.

2 голосов
/ 12 декабря 2011

Выглядит как школьное / колледжное задание для меня;)

Советы:

1) Во-вторых, вы должны написать одну и ту же функцию более одного раза, остановить и пересмотреть. Если ваша функция изменяется только на одну / a-small-number-of-s (s) / value (s), то напишите одну функцию, которая принимает переменную (s) в качестве параметров. 2) Если вы сделаете 1) выше, вам будет довольно легко пройтись по коду и выяснить, почему ваши расчеты по тестам на хиты не дают результатов. Затем вы можете применить исправление в одном месте.

...