Forum Libraries, Components, and Plugins

CCDrawNode and BoundBox trouble

@Flippy @kjpou1 I am trying to determine a collision between 2 CCDrawNodes using the simple BoundBoxTransformedToWorld rectangle intersection technique. It is giving me a collision when there shouldn't be one.

I am wondering how BoundingBoxTransformedToWorld works for a CCDrawNode? The Position of a CCDrawNode just seems to set the origin used by the Draw commands on the node. The Draw commands could draw shapes far away from the Position of the CCDrawNode itself. Therefore, I would expect the BoundingBox to only look at the shapes/verticies used in the Draw commands used on the node and completely ignore the node's Position.

Also, one of my 2 CCDrawNodes that I am trying to detect collisions between is Rotated.

I am very familiar with the concept of Coordinate Systems and multiple frames of reference and converting coordinates from 1 frame to the other. Therefore, I am expecting BoundingBoxTransformedToWorld to handle all of that for me so that I can do my rectangle intersection testing in world coordinates.

Answers

  • ShawnCastrianni.5092ShawnCastrianni.5092 US ✭✭✭
    edited April 2016

    @Flippy @kjpou1 Here is an example of something I don't understand:

    public class TestGameLayer : CCLayerColor
    {
        private float _gameWidth;
        private float _gameHeight;
        private CCDrawNode _sq1 = null;
    
        public TestGameLayer (float gameWidth, float gameHeight) : base(CCColor4B.White)
        {
            _gameWidth = gameWidth;
            _gameHeight = gameHeight;
            _sq1 = new CCDrawNode ();
            _sq1.DrawRect (new CCRect (100, 300, 50, 50), CCColor4B.Red);
            AddChild (_sq1);
        }
    
        protected override void AddedToScene ()
        {
            base.AddedToScene ();
    
            // Register for touch events
            var touchListener = new CCEventListenerTouchAllAtOnce ();
            touchListener.OnTouchesEnded = OnTouchesEnded;
            AddEventListener (touchListener, this);
        }
    
        void OnTouchesEnded (List<CCTouch> touches, CCEvent touchEvent)
        {
            if (touches.Count > 0) {
                Console.WriteLine ("BoundingBox: " + _sq1.BoundingBox);
                Console.WriteLine ("BoundingBoxTransformedToWorld: " + _sq1.BoundingBoxTransformedToWorld);
                Console.WriteLine ("BoundingRect: " + _sq1.BoundingRect);
            }
        }
    }
    

    Will return the following output:

    BoundingBox: CCRect : (x=0, y=0, width=50, height=50)
    BoundingBoxTransformedToWorld: CCRect : (x=0, y=0, width=50, height=50)
    BoundingRect: CCRect : (x=100, y=300, width=50, height=50)
    

    I can understand the output for BoundingBox, but I can NOT understand the output for BoundingBoxTransformedToWorld. World coordinates should be 100,300->50,50.

    Also, what is BoundingRect? I don't see it in the API docs.

  • ShawnCastrianni.5092ShawnCastrianni.5092 US ✭✭✭
    edited April 2016

    @Flippy @kjpou1 If I add some rotation and compare before and after, I am further confused:

    public class TestGameLayer : CCLayerColor
    {
        private float _gameWidth;
        private float _gameHeight;
        private CCDrawNode _sq1 = null;
    
        public TestGameLayer (float gameWidth, float gameHeight) : base(CCColor4B.White)
        {
            _gameWidth = gameWidth;
            _gameHeight = gameHeight;
            _sq1 = new CCDrawNode ();
            _sq1.DrawRect (new CCRect (100, 300, 50, 50), CCColor4B.Red);
            AddChild (_sq1);
        }
    
        protected override void AddedToScene ()
        {
            base.AddedToScene ();
    
            // Register for touch events
            var touchListener = new CCEventListenerTouchAllAtOnce ();
            touchListener.OnTouchesEnded = OnTouchesEnded;
            AddEventListener (touchListener, this);
        }
    
        private async void OnTouchesEnded (List<CCTouch> touches, CCEvent touchEvent)
        {
            if (touches.Count > 0) {
                Console.WriteLine ("BEFORE ROTATION:");
                Console.WriteLine ("BoundingBox: " + _sq1.BoundingBox);
                Console.WriteLine ("BoundingBoxTransformedToWorld: " + _sq1.BoundingBoxTransformedToWorld);
                Console.WriteLine ("BoundingRect: " + _sq1.BoundingRect);
                CCRotateBy ra = new CCRotateBy (1, 45);
                await _sq1.RunActionAsync(ra);
                Console.WriteLine ("AFTER ROTATION:");
                Console.WriteLine ("BoundingBox: " + _sq1.BoundingBox);
                Console.WriteLine ("BoundingBoxTransformedToWorld: " + _sq1.BoundingBoxTransformedToWorld);
                Console.WriteLine ("BoundingRect: " + _sq1.BoundingRect);
            }
        }
    

    Will return the following output:

    BEFORE ROTATION:
    BoundingBox: CCRect : (x=0, y=0, width=50, height=50)
    BoundingBoxTransformedToWorld: CCRect : (x=0, y=0, width=50, height=50)
    BoundingRect: CCRect : (x=100, y=300, width=50, height=50)
    AFTER ROTATION:
    BoundingBox: CCRect : (x=0, y=0, width=50, height=50)
    BoundingBoxTransformedToWorld: CCRect : (x=0, y=-35.35534, width=70.71068, height=70.71068)
    BoundingRect: CCRect : (x=100, y=300, width=50, height=50)
    

    Looking at the after rotation TransformedToWorld, it shows a negative Y value. That would put it below the screen, but I can clearly see the red rectangle on the screen where it should be. So could a negative Y value be world coordinates? I can see that the width and height changed correctly since 50 * rad 2 = 70.7 since I rotated 45 deg. So the TransformedToWorld sort of works with rotation in terms of width and height, but I am boggled by X and Y.

  • IlledanIlledan NOMember ✭✭
    edited April 2016

    Try something like:

            _sq1 = new CCDrawNode ();
            _sq1.DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Red);
            _sq1.AnchorPoint = CCPoint.AnchorMiddle;
            _sq1.Position = new CCPoint (300, 100);
            AddChild (_sq1);
    

    The size of a CCDrawNode is determined by it's childs: Github source , check line 115 public override CCSize ContentSize{...}.

    If you add more elements to your CCDrawNode, you would see the size become bigger, but the position would still be the same for the parent CCDrawNode.

  • kjpou1kjpou1 LUMember, Xamarin Team Xamurai

    A CCDrawNode does not have a size and is basically just a way to draw simple primitives to the screen. A CCSprite has something tangible to calculate it’s size being the backing texture.

        public class DrawNodeTestRotate : BaseDrawNodeTest
        {
            #region Setup content
    
            private CCDrawNode _sq1 = null;
    
            public DrawNodeTestRotate()
            {
                _sq1 = new CCDrawNode ();
                _sq1.DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Red);
                _sq1.ContentSize = new CCSize (50, 50);
                _sq1.PositionX = 100;
                _sq1.PositionY = 300;
                AddChild (_sq1);
    
            }
    
            public override string Subtitle
            {
                get
                {
                    return "DrawNodeTestRotate";
                }
            }
    
            public override void OnEnter()
            {
                base.OnEnter(); 
    
                var origin = VisibleBoundsWorldspace.Origin;
                var size = VisibleBoundsWorldspace.Size;
    
                var sprite1 = new TouchableNode (30);
                sprite1.DrawMe = () => {
                    sprite1.Clear ();
                    sprite1.DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Blue);
                };
                sprite1.ContentSize = new CCSize (50, 50);
                sprite1.Position = origin + size.Center + new CCPoint (-80, 80);
                AddChild(sprite1, 10);
    
                var sprite2 = new TouchableNode (20);
                sprite2.Position = origin + size.Center;
                sprite2.DrawMe = () => {
                    sprite2.Clear ();
                    sprite2.DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Red);
                };
                sprite2.ContentSize = new CCSize (50, 50);
                AddChild(sprite2, 20);
    
                var sprite3 = new TouchableNode(10);
                sprite3.DrawMe = () => {
                    sprite3.Clear ();
                    sprite3.DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Yellow);
                };
                sprite3.ContentSize = new CCSize (50, 50);
                sprite3.PositionX -= 25;
                sprite3.PositionY -= 25;
                sprite2.AddChild(sprite3, 1);
            }
    
            protected override void AddedToScene ()
            {
                base.AddedToScene ();
    
                // Register for touch events
                var touchListener = new CCEventListenerTouchAllAtOnce ();
                touchListener.OnTouchesEnded = OnTouchesEnded;
                AddEventListener (touchListener, this);
            }
    
            private async void OnTouchesEnded (List<CCTouch> touches, CCEvent touchEvent)
            {
                if (touches.Count > 0) {
                    if (_sq1.BoundingBoxTransformedToWorld.ContainsPoint (touches [0].Location)) {
                        CCRotateBy ra = new CCRotateBy (1, 45);
                        await _sq1.RunActionAsync (ra);
    
                    } else {
                        Console.WriteLine ("Location: " + touches [0].Location);
                        Console.WriteLine ("BoundingBox: " + _sq1.BoundingBox);
                        Console.WriteLine ("BoundingBoxTransformedToWorld: " + _sq1.BoundingBoxTransformedToWorld);
                        Console.WriteLine ("BoundingRect: " + _sq1.BoundingRect);
                    }
                }
            }
    
            #endregion Setup content
        } 
    
    
    
        class TouchableNode : CCDrawNode
        {
    
            CCEventListenerTouchOneByOne Listener { get; set; }
            int FixedPriority { get; set; }
            bool IsRemoveListenerOnTouchEnded { get; set; }
            public Action DrawMe { get; set; }
    
            public TouchableNode(int priority = 0)
            {
                FixedPriority = priority;
                IsRemoveListenerOnTouchEnded = false;
            }
    
            protected override void AddedToScene ()
            {
                base.AddedToScene ();
                if (DrawMe != null)
                    DrawMe ();
            }
            public override void OnEnter ()
            {
                base.OnEnter ();
                var listener = new CCEventListenerTouchOneByOne();
                listener.IsSwallowTouches = true;
    
                listener.OnTouchBegan = (CCTouch touch, CCEvent touchEvent) => 
                {
    
                    var locationInNode = touch.Location;
                    var s = ContentSize;
                    CCRect rect = BoundingBoxTransformedToWorld;
    
                    if (rect.ContainsPoint(locationInNode))
                    {
                        DrawRect (new CCRect (0, 0, 50, 50), CCColor4B.Green);
                        return true;
    
                    }
                    return false;
                };
    
                listener.OnTouchEnded = (CCTouch touch, CCEvent rouchEvent) =>
                {
                    if (DrawMe != null)
                        DrawMe();
    
                    if (IsRemoveListenerOnTouchEnded)
                    {
                        RemoveEventListener(Listener);
                    }
                };
    
                if (FixedPriority != 0)
                {
                    AddEventListener(listener, FixedPriority);
                }
                else
                {
                    AddEventListener(listener);
                }
    
                Listener = listener;
            }
    
            public override void OnExit ()
            {
                RemoveEventListener(Listener);
                base.OnExit();
            }
        }
    
Sign In or Register to comment.