Non 1:1 scaling and collision

Jun 20, 2012 at 9:42 AM
Edited Jun 20, 2012 at 9:46 AM

Hello, I am having what I think is an unintended issue.

When scaling a shape with a Vector2 where X and Y are not equal, collision detection becomes inaccurate.

Correct:

http://imageshack.us/photo/my-images/33/num1b.png/
http://imageshack.us/photo/my-images/163/num5q.png/
http://imageshack.us/photo/my-images/201/num6.png/

Incorrect:

http://imageshack.us/photo/my-images/822/num2v.png/
http://imageshack.us/photo/my-images/560/num3i.png/
http://imageshack.us/photo/my-images/100/num4.png/

 

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;

using Shapes;
using Shapes.Geometry;
using Shapes.Misc;
using Shapes.Misc.Appearance;

using ShapesExtensions;

namespace ShapesTest
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager _graphics;
        SpriteBatch _batch;
        TextureGenerator _textureGenerator;
        CollisionDetector2D _collisionDetector;
        GeometrySprite _circle1;
        GeometrySprite _circle2;
        SpriteFont _segoe;
        string _status;
 
        public Game1()
        {            
            _graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }

        protected override void Initialize()
        {
            _collisionDetector = new CollisionDetector2D();
            ShapeTexturePool.Initialize(Content);
            base.Initialize();
        }

        protected override void LoadContent()
        {
            _batch = new SpriteBatch(GraphicsDevice);
            _textureGenerator = new TextureGenerator(GraphicsDevice);

            _segoe = Content.Load<SpriteFont>("Segoe UI Mono");

            FillColor f1 = new FillColor(Color.RoyalBlue);
            FillColor f2 = new FillColor(Color.SlateGray);
       
            _circle1 = new GeometrySprite(new Ellipse(Vector2.Zero, 40, 40), _textureGenerator, f1);
            _circle1.Geometry.Origin = new Vector2(_circle1.Geometry.Width / 2, _circle1.Geometry.Height / 2);
            _circle1.Geometry.Position = new Vector2(GraphicsDevice.Viewport.Width / 2, GraphicsDevice.Viewport.Height / 2);


            _circle2 = new GeometrySprite(new Ellipse(40, 40), _textureGenerator, f2);
            _circle2.Geometry.Origin = new Vector2(_circle2.Geometry.Width / 2, _circle2.Geometry.Height / 2);
            _circle2.Geometry.Position = _circle1.Position + new Vector2(-100, 0);

            _collisionDetector.SetupGeometry(_circle1.Geometry, true, false);
            _collisionDetector.SetupGeometry(_circle2.Geometry, false, true);

            _collisionDetector.CollisionDetected += DeclareDetection;

        }

        public void DeclareDetection(object obj, CollisionEventArgs args)
        {
            _status = "Collision Detected";
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
            KeyboardState key = Keyboard.GetState();

            if (key.IsKeyDown(Keys.PageUp)) { _circle1.Scale += new Vector2(0.05f, 0); }
            if (key.IsKeyDown(Keys.PageDown)) { _circle1.Scale += new Vector2(-0.05f, 0); }
            if (key.IsKeyDown(Keys.Insert)) { _circle1.Scale += new Vector2(0, 0.05f); }
            if (key.IsKeyDown(Keys.Delete)) { _circle1.Scale += new Vector2(0, -0.05f); }
            if (key.IsKeyDown(Keys.Home)) { _circle1.Scale = Vector2.One; }
            if (key.IsKeyDown(Keys.End)) { _circle1.Scale += Vector2.One * 0.05f; }
            if (key.IsKeyDown(Keys.Space)) { _circle1.Scale += Vector2.One * -0.05f; }
            

            if (key.IsKeyDown(Keys.Left)) { _circle1.Position += new Vector2(-0.5f, 0); }
            if (key.IsKeyDown(Keys.Right)){ _circle1.Position += new Vector2(0.5f, 0); }
            if (key.IsKeyDown(Keys.Up)) { _circle1.Position += new Vector2(0, -0.5f); }
            if (key.IsKeyDown(Keys.Down)) { _circle1.Geometry.Position += new Vector2(0, 0.5f); }

            _status = "No Detection";

            _collisionDetector.CheckCollision();

            base.Update(gameTime);
        }


        protected override void Draw(GameTime gameTime)
        {
            string drstr =
                _status
                + "\nCircle 1 Position: "
                + _circle1.Position
                + "\nCircle 1 Scale: "
                + _circle1.Scale
                + "\nCircle 2 Position: "
                + _circle2.Position
                + "\nCircle 2 Scale: "
                + _circle2.Scale;                 

            GraphicsDevice.Clear(Color.DarkOrange);
            _batch.Begin();
            _batch.DrawString(_segoe, drstr, Vector2.Zero, Color.White);
            _circle1.Draw(_batch);
            _circle2.Draw(_batch);
            _batch.End();
             base.Draw(gameTime);
        }
    }
}

 

Jun 21, 2012 at 8:22 AM
Edited Jun 21, 2012 at 8:23 AM

After some further testing I have come to the conclusion that the issue is actually somewhere in the CircleCircleIntersection methods. Testing these two circle shapes against ShapeShapeIntersecting methods produces correct results.

I assume this is a bit slower but as I am not very good at this kind of math, I have chosen to reroute circle to circle intersections to ShapeShape for the time being.

Coordinator
Jun 21, 2012 at 10:45 PM

hi bicycleclops,

thanks for pointing out this issue. This is indeed a bug in Shapes. It will be fixed with the next version.

You are doing right in calling the ShapeShapeIntersecting() method. I think there is no real fast way to check two ellipses for collision.