• Advertisement
Sign in to follow this  

Please help me fix my Mono class.

This topic is 967 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

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() -> List<Obstacle> _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); }
        }
    }
}

Share this post


Link to post
Share on other sites
Advertisement

You haven't implemented continuous collision detection as was recommended to you in your previous post 

I can see that you're moving in the right direction with using Minkowski sums. But you are still doing discrete collision detection :

(obstacle.BoundRectangle.Intersects(this.BoundingRect))

With regard to colliding two non-rotating axis aligned boxes, you construct the Minkowski sum in order to simplify the collision system of the two boxes, transforming the system to one containing a box and a point. You should also transform the velocities to make the the Minkowski sum the stationary object, and the point the moving object. This is a 'relative frame of reference' in order to simplify the problem to a line-box intersection test. 

Look into swept volumes as phil_t recommended, in the previous thread.

Edit : You're CheckMinkowskiSum method is actually not representative of the way Minkowski sums are used in continuous collision detection.

Edited by Gavin Williams

Share this post


Link to post
Share on other sites

Ok I read it and also did understand it. One thing I have to ask, though.

It is pretty clear that in the example posted by phil_t Box contains all variables a Rectangle (XNA) also contains. But what is the Box's velocity supposed to be? Is it the offset between the last and the new position? This I do not fully understand.

Edited by Prot

Share this post


Link to post
Share on other sites

If you are talking about the box that you are dragging with the mouse there are a couple of ways you can assign it's velocity. And you can also just use it's offset directly as you say.

If you use the offset between the last and new positions then you are skipping the velocity step for that object (and that's ok), by plugging the displacement vector of the mouse-driven object directly into the problem, you don't have to worry about the velocity, it's inherent to the movement. And you can just compute the displacement vector of the other object, from it's velocity (0 if it's stationary). It's then a geometric problem alone. But the velocity is actually v = s / t (where v = velocity, s = displacement, t = time). In this case you may still need to compute the velocity of the mouse-driven object if you want any kind of inertial response. But you don't have to if you're not worrying about inertia. 

Another way that I've seen mouse movement done, such as in Farseer Physics is to use springs. So a spring between the mouse and the object is set up and it can be set to be quite rigid, then the object will fly to the mouse position as though it were tied to it with a tight rubber band. In this system, the mouse-driven object's velocity is used normally by the physics engine. And it looks just like any other object in the system. But it's movement will not fit to the mouse-movement curve quite as tightly. But it is an effective technique.

Edited by Gavin Williams

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement