1

从下面的屏幕截图中可以看出,我想要的行为是:

  • 球体从竞技场的中间开始
  • 当你按下回车键时,它会向随机方向移动
  • 当它与四个墙壁之一碰撞时,它将以 0 到 45 度之间的随机角度弹回相反方向

问题是下图中没有显示的是球直接穿过任何墙壁,而不是碰撞或弹跳。

我已经尝试更新球体的模型位置,但它仍然不会切割它。我曾尝试将球的半径设置为 100 之类的大数字 - 但是当它开始移动时,它甚至在撞到墙壁并开始振动之前就会发生碰撞。

世界空间视觉截图

源代码(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);
        }
4

2 回答 2

2

对我来说看起来像是学校/大学的作业;)

尖端:

1)第二次你必须多次编写相同的函数,停下来重新考虑。如果您的函数仅由一个/一小部分变量/值变化,则编写一个接受变量作为参数的函数。2) 如果您执行上述 1),则应该很容易单步执行代码并找出您的命中测试计算失败的原因。然后,您可以在一处应用修复程序。

于 2011-12-12T19:47:59.933 回答
2

一般提示:在 XNA 中,您不应该在 Draw 方法中进行碰撞检测。此方法的调用次数可能少于每秒 60 帧。您应该在类的 Update 方法中执行此操作。有关详细说明,请参见此处

我认为您的碰撞检测不正确。您需要反映方向角度,而不仅仅是选择随机方向。

您还需要添加一个速度矢量,该矢量将添加到您的当前位置。使用这样的向量比尝试直接使用位置要容易得多。

在 C# 中实现 Pong 的教程有很多。这只是一个示例:

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

请注意,您有两个不同的成员,一个代表位置,另一个代表每次更新时将添加到位置的速度。

除此之外,您每次添加到球位置的增量可能太多,因此它“跳过”了边界墙。您可以 1) 减小增量或 2) 使边界墙更宽。

于 2011-12-12T20:28:31.520 回答