Please help me fix my Mono class.

Hi,

I would like to ask you for a little help or advise with my class. In short, what is it supposed to do is to draw a texture which works well. Further it is supposed to follow the mouse position.

Also (here is the problem) it is supposed to check for collision with Rectangle objects (argument in Update() -> _obstacleList). Once it does collide with a rectangle it is supposed to ‘bounce’ in the other direction. Right now when bouncing back the mouse position is also changed via Mouse.SetPosition().

My problem is sometimes the collision checks simply do not work. It feels like collision checks fail if I move the mouse to fast. I am also not sure whether my CheckMinkowskiSum method does the calculations right. It would be great if somebody more experienced could have a look at my class. I know it is a mess right now but I guess it is still readable:

using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using System;
using System.Windows.Forms;
using MonoTest.Environment;
using ButtonState = Microsoft.Xna.Framework.Input.ButtonState;

namespace MonoTest
{
    public class Companion
    {
        private Texture2D texture;
        private Vector2 position;
        private MouseState oldMouseState;
        private GraphicsDevice graphics;

        private List<ITriggerObject> triggerObjList;
        private int xBounceVelocity = 0;
        private int yBounceVelocity = 0;
        private int maxBounceVelocity = 5;
        private bool isBouncing = false;
        private int maxBounceFactor = 15;
        private int currenBounceFactor = 0;

        public Companion(Texture2D _texture, Vector2 _position, GraphicsDevice _graphics, List<ITriggerObject> _triggerObjList)
        {
            this.texture = _texture;
            this.position = _position;
            this.graphics = _graphics;
            this.triggerObjList = _triggerObjList;
            Mouse.SetPosition(graphics.Viewport.Width / 2, graphics.Viewport.Height / 2); //Set the mouse to a position where no collision appears!
        }


        public void Update(List<Obstacle> _obstacleList)
        {
            MouseState mState = Mouse.GetState();

            if (!isBouncing)
            {
                CheckCollision(_obstacleList, mState);
            }
            else
            {
                Bounce();
            }  

            oldMouseState = mState;
        }
 
        //Called while still bouncing
        private void Bounce()
        {
            if (currenBounceFactor == maxBounceFactor)
            {
                isBouncing = false;
                currenBounceFactor = 0;
                xBounceVelocity = 0;
                yBounceVelocity = 0;
            }
            else
            {
                currenBounceFactor++;
                position = new Vector2(position.X+xBounceVelocity,position.Y+yBounceVelocity);
                Mouse.SetPosition((int)position.X + xBounceVelocity, (int)position.Y + yBounceVelocity);
            }
        }
        
        //Checks for collision with all Rectangles in the level
        private void CheckCollision(List<Obstacle> _obstacleList, MouseState mState)
        {
            position = new Vector2(mState.X,mState.Y);
            bool collides = false;
            string collisionFrom = string.Empty;
            Rectangle collisionRectangle = new Rectangle();

            foreach (Obstacle obstacle in _obstacleList)
            {
                if (obstacle.BoundRectangle.Intersects(this.BoundingRect))
                {
                    collides = true;
                    collisionFrom = CheckMinkowskiSum(this.BoundingRect, obstacle.BoundRectangle);
                    collisionRectangle = obstacle.BoundRectangle;
                    break;
                }
            }

            //If a collision occured mark bouncing = true
            if (collides) 
            {
                switch (collisionFrom)
                {
                    case "bottom":
                        yBounceVelocity = -maxBounceVelocity;
                            isBouncing = true;
                        break;
                    case "top":
                        yBounceVelocity = maxBounceVelocity;
                            isBouncing = true;
                        break;
                    case "left":
                    case "right":
                        if (collisionRectangle.Center.X < this.BoundingRect.Center.X) //Left
                        {
                            xBounceVelocity = maxBounceVelocity;
                            isBouncing = true;
                        }
                        else //right
                        {
                            xBounceVelocity = -maxBounceVelocity;
                            isBouncing = true;
                        }
                        break;
                }
            }

        }

        //Returns the direction from which the collision took place
        public string CheckMinkowskiSum(Rectangle pRectangle, Rectangle oRectangle)
        {
            //http://gamedev.stackexchange.com/questions/24078/which-side-was-hit/24091#24091

            float wy = ((pRectangle.Width + oRectangle.Width) * (pRectangle.Center.Y - oRectangle.Center.Y));
            float hx = ((pRectangle.Height + oRectangle.Height) * (pRectangle.Center.X - oRectangle.Center.X));

            if (wy > hx)
            {
                if (wy > (hx * -1))
                {
                    return "top";
                }
                else
                {
                    return "left";
                }
            }
            else
            {
                if (wy > (-1 * hx))
                {
                    return "right";
                }
                else
                {
                    return "bottom";
                }
            }
        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture,position,Color.White);
        }

        public Rectangle BoundingRect {
            get { return new Rectangle((int)position.X, (int)position.Y, texture.Width, texture.Height); }
        }
    }
}

Thanks in advance!

The problem with the collision detection the way you have it now (unless I’m horribly misunderstanding the .Intersects() method of Rectangle and the rest of your code) is that your collision detection currently only checks for the mouse’s position at any given frame. Frames are only drawn so fast, though.
When the mouse moves a certain distance in a certain frame, the line it travels isn’t checked, just its end point, which means that if the mouse is moving fast enough, it won’t collide with an obstacle because the mouse was never registered as having a position that collided with the obstacle.

In one frame:
Mouse A ------------- Object ---------------> Mouse B
No collision detection occurs here.

This is actually a problem I’ve been dealing with myself. I attempted to counter it by iterating a for loop for each step of the distance traveled and then checking for collision at each step (doing this all in one frame), and that works, but that’s a pretty dang expensive way to check for collision.

I havent checked your class, basically just answering to AJP, have you tried for instance raycast between previous and current position? (it depends on what kind geometry do you use)… obviously one per update / frame per object you are tracking.

Thanks for the suggestion. That’s what I was thinking of doing. Problem is, I don’t know how to implement it…

Try http://www.wildbunny.co.uk/blog/2011/04/20/collision-detection-for-dummies/ you are interested in continuous detection (sorry about article name, not my bad)

Thanks for the suggestions. I am using AABBs only.