예제 #1
0
    public bool HasCollision(ChunkInfo ci, int x, int y)
    {
        Vector2 worldPos = WorldMap.Chunk2World(ci, x, y);

        Box2D worldBox = new Box2D(worldPos, 0.5f, 0.5f);

        // Check against any player
        Box2D playerBox = GameManager.Instance.MainPlayer.Box;

        return(CollisionCode.TestBox2DBox2D(worldBox, playerBox));
    }
예제 #2
0
 public ItemInstance GetItemInstanceFromWorldPos(Vector2 worldPos)
 {
     // (O(n)) - No spatial partitioning, will probably be slow when many items are present.
     foreach (ItemInstance item in ItemManager.Instance)
     {
         if (CollisionCode.TestPointBox2D(worldPos, item.Box))
         {
             return(item);
         }
     }
     return(null);
 }
예제 #3
0
 public Enemy GetEnemyFromWorldPos(Vector2 worldPos)
 {
     foreach (Entity entity in EntityManager.Instance.Entities)
     {
         Enemy enemy = entity as Enemy;
         if (enemy && CollisionCode.TestPointBox2D(worldPos, enemy.Box))
         {
             return(enemy);
         }
     }
     return(null);
 }
예제 #4
0
    private void UpdatePositionInternal(Entity entity, Vector3 oldPosition, ref Vector3 newPosition, int step)
    {
        // Figure out sweep area
        Vector2 oldPosition2D = new Vector2(oldPosition.x, oldPosition.y);
        Vector2 newPosition2D = new Vector2(newPosition.x, newPosition.y);

        float mostLeft  = Math.Min(oldPosition2D.x, newPosition2D.x) - 0.5f;
        float mostRight = Math.Max(oldPosition2D.x, newPosition2D.x) + 0.5f;
        float mostUp    = Math.Max(oldPosition2D.y, newPosition2D.y) + 0.5f;
        float mostDown  = Math.Min(oldPosition2D.y, newPosition2D.y) - 0.5f;

        Vector2 topLeft     = new Vector2(mostLeft, mostUp);
        Vector2 bottomRight = new Vector2(mostRight, mostDown);

        Box2D sweep = new Box2D(topLeft, bottomRight);

        Box2D originalBox = new Box2D(oldPosition2D, 0.5f, 0.5f);
        Box2D endBox      = new Box2D(newPosition2D, 0.5f, 0.5f);

        Vector2 displacement = endBox.Center - originalBox.Center;

        // now get the list of tiles that we may have encountered during this sweep and return their boxes
        CollisionInfo[] broadPhase = CollisionCode.BroadPhase(entity, sweep);

        float bestT = 1.0f; // no collision

        foreach (CollisionInfo ci in broadPhase)
        {
            // now for each collision potential collision, figure out at which 't' we hit the box, return the shortest t in case of multiple collision
            float tFirst, tLast;
            bool  collide = CollisionCode.IntersectMovingBox2DBox2D(originalBox, ci.Box, displacement, new Vector2(0, 0), out tFirst, out tLast);

            if (collide)
            {
                // Are we allowed to go through ?
                if ((ci.Flags & CollisionFlags.Wall) == CollisionFlags.Wall)
                {
                    // hard collision, prevent movement
                    bestT = Mathf.Min(tFirst, bestT);
                }
                else
                {
                    // send OnTouchEvent on Entity
                    // Note: This will probably send multiple Touch events to the same pair. We should accumulate these TouchEvent and then sweep them if we get the bug.
                    Entity entity2 = ci.Entity;

                    // TODO - Since UpdateCollisionInternal is called multiple times per frame, also when checking potential collision detection, we need a way to turn it on and off
                    // to avoid sending false positive, also to avoid sending multiple touches on the same frame
                    if (entity2 != null)
                    {
                        entity.OnTouch(entity2);
                        entity2.OnTouch(entity);
                    }
                }
            }
        }

        if (bestT < 1.0f) // got at least one collision, reduce wanted velocity
        {
            displacement *= bestT;
            newPosition2D = oldPosition2D + displacement;
        }

        if (bestT >= 0.999)
        {
            newPosition.x = newPosition2D.x;
            newPosition.y = newPosition2D.y;
        }
        else if (step < 5)
        {
            // we were at oldPosition, we wanted to go at newPosition, we are currently stuck at newPosition2D

            // if displacement was on a single-axis, forget it, there's nothing we do can
            Vector3 wantedDisplacement = newPosition - oldPosition;
            if (Mathf.Abs(wantedDisplacement.x) <= 0.001 || Mathf.Abs(wantedDisplacement.y) <= 0.001)
            //if (true)
            {
                newPosition.x = newPosition2D.x;
                newPosition.y = newPosition2D.y;
            }
            else
            {
                Vector3 subOldPosition = new Vector3(newPosition2D.x, newPosition2D.y, 0.0f);

                Vector3 subNewPositionInX = newPosition;
                subNewPositionInX.y = subOldPosition.y;

                Vector3 subNewPositionInY = newPosition;
                subNewPositionInY.x = subOldPosition.x;

                // Try X-Axis only
                UpdatePositionInternal(entity, subOldPosition, ref subNewPositionInX, step + 1);

                // Try Y-Axis only
                UpdatePositionInternal(entity, subOldPosition, ref subNewPositionInY, step + 1);

                // Which one got us closer to our goal ?
                if ((subNewPositionInX - newPosition).sqrMagnitude < (subNewPositionInY - newPosition).sqrMagnitude)
                {
                    // TODO - Recurse again ?

                    // it was better to go in X only
                    newPosition.x = subNewPositionInX.x;
                    newPosition.y = subNewPositionInX.y;
                }
                else
                {
                    newPosition.x = subNewPositionInY.x;
                    newPosition.y = subNewPositionInY.y;
                }
            }
        }
    }