Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I am creating a classic game in 3D that deals with asteriods and you have to shoot them and avoid being hit from them. I can generate the asteroids just fine and the ship can shoot bullets just fine. But the asteroids always hit the ship even if it doesn't look they are even close. I know 2D collision very well but not 3D so can someone please shed some light to my problem? Thanks in advance.

Code for ModelRenderer:

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_Asteroids
{
    class ModelRenderer
    {
        private float aspectratio;
        private Model model;
        private Vector3 camerapos;
        private Vector3 modelpos;
        private Matrix rotationy;
        float radiansy = 0;
        private bool isalive;

        public ModelRenderer(Model m, float AspectRatio, Vector3 initial_pos, Vector3 initialcamerapos)
        {
            isalive = true;
            model = m;
            if (model.Meshes.Count == 0)
            {
                throw new Exception("Invalid model because it contains zero meshes!");
            }
            modelpos = initial_pos;
            camerapos = initialcamerapos;
            aspectratio = AspectRatio;
            return;
        }
        public float RadiusOfSphere
        {

            get
            {
                return model.Meshes[0].BoundingSphere.Radius;
            }
        }
        public BoundingBox BoxBounds
        {
            get
            {

                return BoundingBox.CreateFromSphere(model.Meshes[0].BoundingSphere);
            }
        }

        public BoundingSphere SphereBounds
        {

            get
            {

                return model.Meshes[0].BoundingSphere;
            }
        }
        public Vector3 CameraPosition
        {
            set
            {
                camerapos = value;
            }
            get
            {
                return camerapos;
            }

        }
        public bool IsAlive
        {
            get
            {
                return isalive;
            }
        }
        public Vector3 ModelPosition
        {
            set
            {
                modelpos = value;
            }
            get
            {
                return modelpos;
            }
        }
        public void RotateY(float radians)
        {
            radiansy += radians;
            rotationy = Matrix.CreateRotationY(radiansy);
        }
        public Matrix RotationY
        {
            set
            {
                rotationy = value;
            }
            get
            {
                return rotationy;
            }
        }
        public float AspectRatio
        {
            set
            {
                aspectratio = value;
            }
            get
            {
                return aspectratio;
            }
        }
        public void Kill()
        {
            isalive = false;
        }
        public void Draw(float scale)
        {
            Matrix world;
            if (rotationy == new Matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
            {
                world = Matrix.CreateScale(scale) * Matrix.CreateTranslation(modelpos);
            }
            else
            {
                world = rotationy * Matrix.CreateScale(scale) * Matrix.CreateTranslation(modelpos);
            }
            Matrix view = Matrix.CreateLookAt(camerapos, Vector3.Zero, Vector3.Up);
            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), this.AspectRatio, 1f, 100000f);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = world;
                    effect.View = view;
                    effect.Projection = projection;

                }
                mesh.Draw();
            }
        }
        public void Draw()
        {
            Matrix world;
            if (rotationy == new Matrix(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0))
            {
                world = Matrix.CreateTranslation(modelpos);
            }
            else
            {
                world = rotationy * Matrix.CreateTranslation(modelpos);
            }
            Matrix view = Matrix.CreateLookAt(camerapos, Vector3.Zero, Vector3.Up);
            Matrix projection = Matrix.CreatePerspectiveFieldOfView(MathHelper.ToRadians(45.0f), this.AspectRatio, 1f, 100000f);

            foreach (ModelMesh mesh in model.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.World = world;
                    effect.View = view;
                    effect.Projection = projection;

                }
                mesh.Draw();
            }
        }
    }

Code for Game1:

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_Asteroids
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        int score = 0, lives = 5;
        SpriteBatch spriteBatch;
        GameState gstate = GameState.OnMenuScreen;
        Menu menu = new Menu(Color.Yellow, Color.White);
        SpriteFont font;
        Texture2D background;
        ModelRenderer ship;
        Model b, a;
        List<ModelRenderer> bullets = new List<ModelRenderer>();
        List<ModelRenderer> asteriods = new List<ModelRenderer>();
        float time = 0.0f;
        int framecount = 0;
        SoundEffect effect;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            graphics.PreferredBackBufferWidth = 1280;
            graphics.PreferredBackBufferHeight = 796;
            graphics.ApplyChanges();
            Content.RootDirectory = "Content";

        }



        /// <summary>
        /// Allows the game to perform any initialization it needs to before starting to run.
        /// This is where it can query for any required services and load any non-graphic
        /// related content.  Calling base.Initialize will enumerate through any components
        /// and initialize them as well.
        /// </summary>
        protected override void Initialize()
        {
            // TODO: Add your initialization logic here

            base.Initialize();
        }

        /// <summary>
        /// LoadContent will be called once per game and is the place to load
        /// all of your content.
        /// </summary>
        protected override void LoadContent()
        {
            // Create a new SpriteBatch, which can be used to draw textures.
            spriteBatch = new SpriteBatch(GraphicsDevice);
            font = Content.Load<SpriteFont>("Fonts\\Lucida Console");
            background = Content.Load<Texture2D>("Textures\\B1_stars");
            Model p1 = Content.Load<Model>("Models\\p1_wedge");
            b = Content.Load<Model>("Models\\pea_proj");
            a = Content.Load<Model>("Models\\asteroid1");
            effect = Content.Load<SoundEffect>("Audio\\tx0_fire1");
            ship = new ModelRenderer(p1, GraphicsDevice.Viewport.AspectRatio, new Vector3(0, 0, 0), new Vector3(0, 0, 9000));
        }

        /// <summary>
        /// UnloadContent will be called once per game and is the place to unload
        /// all content.
        /// </summary>
        protected override void UnloadContent()
        {

        }

        /// <summary>
        /// Allows the game to run logic such as updating the world,
        /// checking for collisions, gathering input, and playing audio.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Update(GameTime gameTime)
        {

            KeyboardState state = Keyboard.GetState(PlayerIndex.One);
            switch (gstate)
            {
                case GameState.OnMenuScreen:
                {
                    if (state.IsKeyDown(Keys.Enter))
                    {
                        switch (menu.SelectedChoice)
                        {
                            case MenuChoices.Play:
                            {
                                gstate = GameState.GameStarted;
                                break;
                            }
                            case MenuChoices.Exit:
                            {
                                this.Exit();
                                break;
                            }
                        }

                    }
                    if (state.IsKeyDown(Keys.Down))
                    {
                        menu.MoveSelectedMenuChoiceDown(gameTime);
                    }
                    else if(state.IsKeyDown(Keys.Up))
                    {
                        menu.MoveSelectedMenuChoiceUp(gameTime);
                    }
                    else
                    {
                        menu.KeysReleased();
                    }

                    break;
                }
                case GameState.GameStarted:
                {
                    foreach (ModelRenderer bullet in bullets)
                    {
                        if (bullet.ModelPosition.X < (ship.ModelPosition.X + 4000) && bullet.ModelPosition.Z < (ship.ModelPosition.X + 4000) && bullet.ModelPosition.X > (ship.ModelPosition.Z - 4000) && bullet.ModelPosition.Z > (ship.ModelPosition.Z - 4000))
                        {
                            bullet.ModelPosition += (bullet.RotationY.Forward * 120);
                        }
                        else if (collidedwithasteriod(bullet))
                        {
                            bullet.Kill();
                        }
                        else
                        {

                            bullet.Kill();
                        }

                    }
                    foreach (ModelRenderer asteroid in asteriods)
                    {
                        if (ship.SphereBounds.Intersects(asteroid.BoxBounds))
                        {
                            lives -= 1;
                            asteroid.Kill(); // This always hits no matter where the ship goes.
                        }
                        else
                        {
                            asteroid.ModelPosition -= (asteroid.RotationY.Forward * 50);
                        }
                    }
                    for (int index = 0; index < asteriods.Count; index++)
                    {
                        if (asteriods[index].IsAlive == false)
                        {
                            asteriods.RemoveAt(index);
                        }
                    }
                    for (int index = 0; index < bullets.Count; index++)
                    {
                        if (bullets[index].IsAlive == false)
                        {
                            bullets.RemoveAt(index);
                        }

                    }
                    if (state.IsKeyDown(Keys.Left))
                    {
                        ship.RotateY(0.1f);
                        if (state.IsKeyDown(Keys.Space))
                        {
                            if (time < 17)
                            {
                                firebullet();
                                //effect.Play();
                            }
                        }
                        else
                        {
                            time = 0;
                        }
                    }
                    else if (state.IsKeyDown(Keys.Right))
                    {
                        ship.RotateY(-0.1f);
                        if (state.IsKeyDown(Keys.Space))
                        {
                            if (time < 17)
                            {
                                firebullet();
                                //effect.Play();
                            }
                        }
                        else
                        {
                            time = 0;
                        }
                    }
                    else if (state.IsKeyDown(Keys.Up))
                    {
                        ship.ModelPosition += (ship.RotationY.Forward * 50);
                        if (state.IsKeyDown(Keys.Space))
                        {
                            if (time < 17)
                            {
                                firebullet();
                                //effect.Play();
                            }
                        }
                        else
                        {
                            time = 0;
                        }
                    }
                    else if (state.IsKeyDown(Keys.Space))
                    {
                        time += gameTime.ElapsedGameTime.Milliseconds;
                        if (time < 17)
                        {
                            firebullet();
                            //effect.Play();
                        }
                    }

                    else
                    {
                        time = 0.0f;
                    }
                    if ((framecount % 60) == 0)
                    {
                        createasteroid();
                        framecount = 0;
                    }
                    framecount++;
                    break;
                }
            }

            base.Update(gameTime);
        }
        void firebullet()
        {
            if (bullets.Count < 3)
            {
                ModelRenderer bullet = new ModelRenderer(b, GraphicsDevice.Viewport.AspectRatio, ship.ModelPosition, new Vector3(0, 0, 9000));            
                bullet.RotationY = ship.RotationY;
                bullets.Add(bullet);
            }

        }
        void createasteroid()
        {
            if (asteriods.Count < 2)
            {
                Random random = new Random();
                float z = random.Next(-13000, -11000);
                float x = random.Next(-9000, -8000);
                Random random2 = new Random();
                int degrees = random.Next(0, 45);
                float radians = MathHelper.ToRadians(degrees);
                ModelRenderer asteroid = new ModelRenderer(a, GraphicsDevice.Viewport.AspectRatio, new Vector3(x, 0, z), new Vector3(0,0, 9000));
                asteroid.RotateY(radians);
                asteriods.Add(asteroid);
            }
        }
        /// <summary>
        /// This is called when the game should draw itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);

            switch (gstate)
            {
                case GameState.OnMenuScreen:
                {
                    spriteBatch.Begin();
                    spriteBatch.Draw(background, Vector2.Zero, Color.White);
                    menu.DrawMenu(ref spriteBatch, font, new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2) - new Vector2(50f), 100f);
                    spriteBatch.End();
                    break;
                }
                case GameState.GameStarted:
                {
                    spriteBatch.Begin();
                    spriteBatch.Draw(background, Vector2.Zero, Color.White);
                    spriteBatch.DrawString(font, "Score: " + score.ToString() + "\nLives: " + lives.ToString(), Vector2.Zero, Color.White);
                    spriteBatch.End();
                    ship.Draw();
                    foreach (ModelRenderer bullet in bullets)
                    {
                        bullet.Draw();
                    }
                    foreach (ModelRenderer asteroid in asteriods)
                    {
                        asteroid.Draw(0.1f);
                    }
                    break;
                }
            }

            base.Draw(gameTime);
        }
        bool collidedwithasteriod(ModelRenderer bullet)
        {
            foreach (ModelRenderer asteroid in asteriods)
            {
                if (bullet.SphereBounds.Intersects(asteroid.BoxBounds))
                {
                    score += 10;
                    asteroid.Kill();
                    return true;
                }
            }
            return false;
        }
    }
}

}
share|improve this question
add comment

1 Answer

up vote 5 down vote accepted

In your ModelRenderer class, you have a property that gets the mesh's bounding sphere, 'SphereBounds'. But each frame you have to update the object to reflect the current position of the ship or asteroid.

When you load a model into the game, it is usually situated at the world origin. Since you never update the spheres, both the asteroid & ship spheres are still at the world origin registering collision frame after frame.

It isn't enough just to updated a field or variable that reflects a new model position each frame. You also have to update the sphere's center by the same amount each frame. It's like a the beginning of the game, the asteroid & the ship went flying off but left their spheres at the world origin.

share|improve this answer
    
You are totally right, it should be updated. It works now. –  Daniel Lopez Nov 27 '11 at 0:59
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.