从下面的屏幕截图中可以看出,我想要的行为是:
- 球体从竞技场的中间开始
- 当你按下回车键时,它会向随机方向移动
- 当它与四个墙壁之一碰撞时,它将以 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);
}