As you can see from the screenshot below, my desired behavior is:
- the sphere starts out in the middle of the arena
- when you press enter it moves in a random direction
- when it collides with one of the four walls it will bounce back to the opposite direction at a random angle between 0 and 45 degrees
The problem is which is not shown in the picture below is that the ball goes right through any of the walls, instead of colliding or bouncing.
I have tried updating the model position of the ball's sphere but it still won't cut it. I have tried setting the radius of the ball to a large number like 100 - but it collides when it starts moving before it even hits the wall and starts vibrating.

Source Code (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);
}
}
}
Source (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);
}
}
}
I haven't implemented the paddles until I fix collision detection problem. If I am missing a piece of information please leave a comment, I have tried everything I can think of.
I have changed it so there is one function for each wall's bounds.
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);
}