Improving the collision system

Discuss suggestions to improve the Axel library.

Improving the collision system

Postby Yorwba » Fri Aug 10, 2012 8:18 am

I just tested a simple demo featuring two sprites and a tilemap. Everything collides with everything but whatever order I choose, I just get odd behavior. When the two sprites collide first and then with the tilemap, they randomly push around or even bypass each other. When they collide with the tilemap first and afterwards with each other, they even get pushed into the tilemap.

I think the last behavior could be fixed by adding a blocked variable to the sprites, similar to touching and touched, that indicates the directions the sprite cannot be pushed into because a tilemap or another blocked sprite is in it's way.
Yorwba
Private
 
Posts: 3
Joined: Wed Aug 08, 2012 6:52 am

Re: Improving the collision system

Postby Yorwba » Mon Aug 13, 2012 9:14 am

OK, I dug a bit in the source and found out that not only this improvement would be good, but that the whole collision handling code was just correcting the position of the entity given as the first parameter to Ax.collide. So only collisions between entities and tilemaps were handled correctly. After a quick look over to flixel I rewrote the methods ( solveXCollision and solveYCollision in AxCollisionGroup).
That's the result:
AxCollisionGroup.as
Code: Select all
package org.axgl.collision {
   import org.axgl.Ax;
   import org.axgl.AxCloud;
   import org.axgl.AxEntity;
   import org.axgl.AxGroup;
   import org.axgl.AxPoint;
   import org.axgl.AxRect;
   import org.axgl.AxSprite;
   import org.axgl.AxU;
   import org.axgl.tilemap.AxTilemap;

   /**
    * A collision group that defines how two AxEntities should collide. This is an abtract class that shouldn't be used
    * itself, instead you should use one of its implementing subclasses.
    */
   public class AxCollisionGroup {
      /**
       * The frame of the source object used to detect collisions.
       */
      protected var sourceFrame:AxRect;
      /**
       * The frame of the target object used to detect collisions.
       */
      protected var targetFrame:AxRect;
      /**
       * The frame of the source object used to detect single axis collisions.
       */
      protected var sourceAxisFrame:AxRect;
      /**
       * The frame of the target object used to detect single axis collisions.
       */
      protected var targetAxisFrame:AxRect;
      /**
       * The callback function to call when a collision is detected.
       */
      protected var callback:Function;
      /**
       * The number of comparisons done between objects on the current frame.
       */
      public var comparisons:uint;

      /**
       * Sets up the basic variables used for the collision group upon instantiation. You should not use this constructor
       * directly, but rather one of the subclasses's constructors.
       */
      public function AxCollisionGroup() {
         this.sourceFrame = new AxRect;
         this.targetFrame = new AxRect;
         this.sourceAxisFrame = new AxRect;
         this.targetAxisFrame = new AxRect;
         comparisons = 0;
      }

      /**
       * The implementation of this function should set up the data structures needed to collide by populating them with all
       * subentities of the passed entities, taking into account that they may be recursively nested AxGroups.
       *
       * @param source The source entities to collide.
       * @param target The target entities to collide.
       *
       */
      public function build(source:AxEntity, target:AxEntity):void {
         // Override as needed
      }

      /**
       * Overlaps the two groups of entities, separating any overlapping entities that are solid and executing the callback for
       * any overlapping pair. This method simply uses overlap(), with the added step of separating objects.
       *
       * @return Whether any overlaps were detected.
       */
      public function collide():Boolean {
         // Override as needed
         return false;
      }

      /**
       * Overlaps the two groups of entities, executing the callback for any overlapping pair.
       *
       * @return Whether any overlaps were detected.
       */
      public function overlap():Boolean {
         // Override as needed
         return false;
      }
      
      /**
       * Resets the group, clearing all entities, so that it can be recycled each frame. This saves performance if you can recycle
       * a group without recreating all the required objects.
       */
      public function reset():void {
         // Override as needed
      }

      /**
       * Sets the callback to be executing upon any two entities overlapping.
       *
       * @param callback The callback to execute upon overlap.
       */
      public function setCallback(callback:Function):void {
         this.callback = callback;
      }

      /**
       * Adds all entities and subentities of the passed object to the passed group.
       *
       * @param object The entity to add. If it's a group, recursively adds all members.
       * @param group The group to add all entities to.
       */
      protected function addAll(object:AxEntity, group:Vector.<AxEntity>):void {
         if (object is AxGroup) {
            var objects:Vector.<AxEntity> = (object as AxGroup).members;
            for each (var o:AxEntity in objects) {
               if (o.active && o.exists) {
                  addAll(o, group);
               }
            }
         } else if (object is AxCloud) {
            var sprites:Vector.<AxSprite> = (object as AxCloud).members;
            for each (var s:AxSprite in sprites) {
               if (s.active && s.exists) {
                  addAll(s, group);
               }
            }
         } else if (object != null) {
            group.push(object);
         }
      }

      /**
       * Given two entities, checks to see if they overlap (only taking into account their movement on the x axis), and if they do,
       * separate them upon that axis.
       *
       * @param source The source entity to check.
       * @param target The target entity to check.
       *
       * @return Whether or not an overlap was detected.
       */
      protected function solveXCollision(source:AxEntity, target:AxEntity):Boolean {
         if (source is AxTilemap) {
            return (source as AxTilemap).overlap(target, solveXCollision, true);
         } else if (target is AxTilemap) {
            return (target as AxTilemap).overlap(source, solveXCollision, true);
         }

         var sfx:Number = source.x - source.previous.x;
         var tfx:Number = target.x - target.previous.x;

         if (sfx == tfx) return false;
         
         sourceAxisFrame.x = (source.x > source.previous.x ? source.previous.x : source.x);
         sourceAxisFrame.y = source.previous.y;
         sourceAxisFrame.width = source.width + AxU.abs(sfx);
         sourceAxisFrame.height = source.height;

         targetAxisFrame.x = (target.x > target.previous.x ? target.previous.x : target.x);
         targetAxisFrame.y = target.previous.y;
         targetAxisFrame.width = target.width + AxU.abs(tfx);
         targetAxisFrame.height = target.height;

         var overlap:Number = 0;
         if ((sourceAxisFrame.x + sourceAxisFrame.width - AxU.EPSILON > targetAxisFrame.x) && (sourceAxisFrame.x + AxU.EPSILON < targetAxisFrame.x + targetAxisFrame.width) && (sourceAxisFrame.y + sourceAxisFrame.height - AxU.EPSILON > targetAxisFrame.y) && (sourceAxisFrame.y + AxU.EPSILON < targetAxisFrame.y + targetAxisFrame.height)) {
            var maxOverlap:Number = AxU.abs(sfx) + AxU.abs(tfx) + 120 * Ax.dt//OVERLAP_BIAS = 4 in flixel, made it framerate independent
            if (sfx > tfx) {
               overlap = source.x + source.width - target.x;
               if (overlap > maxOverlap) {
                  overlap = 0;
               }else{
                  source.touching |= AxEntity.RIGHT;
                  target.touching |= AxEntity.LEFT;
               }
            }
            if (sfx < tfx) {
               overlap = source.x - target.width - target.x;
               if (-overlap > maxOverlap) {
                  overlap = 0;
               }else{
                  target.touching |= AxEntity.RIGHT;
                  source.touching |= AxEntity.LEFT;
               }
            }
         }         
         
         var sourceImmovable:Boolean = source.stationary || ((sfx > tfx)? (source.blocked & AxEntity.LEFT) : (source.blocked & AxEntity.RIGHT));
         var targetImmovable:Boolean = target.stationary || ((tfx > sfx)? (target.blocked & AxEntity.LEFT) : (target.blocked & AxEntity.RIGHT));
         if (overlap != 0) {
            if (!sourceImmovable && !targetImmovable) {
               source.x -= overlap / 2;
               target.x += overlap / 2;
               var average:Number = (source.velocity.x + target.velocity.x) / 2;
               source.velocity.x = average;
               target.velocity.x = average;
            }else if (!sourceImmovable) {
               source.x -= overlap;
               source.velocity.x = 0;
            }else if (!targetImmovable) {
               target.x += overlap;
               target.velocity.x = 0;
            }
            if (sourceImmovable) {
               target.blocked |= (sfx > tfx)? AxEntity.LEFT : AxEntity.RIGHT;
            }
            if (targetImmovable) {
               source.blocked |= (tfx > sfx)? AxEntity.LEFT : AxEntity.RIGHT;
            }
            return true;
         }

         return false;
      }

      /**
       * Given two entities, checks to see if they overlap (only taking into account their movement on the y axis), and if they do,
       * separate them upon that axis.
       *
       * @param source The source entity to check.
       * @param target The target entity to check.
       *
       * @return Whether or not an overlap was detected.
       */
      protected function solveYCollision(source:AxEntity, target:AxEntity):Boolean {
         if (source is AxTilemap) {
            return (source as AxTilemap).overlap(target, solveYCollision, true);
         } else if (target is AxTilemap) {
            return (target as AxTilemap).overlap(source, solveYCollision, true);
         }

         var sfy:Number = source.y - source.previous.y;
         var tfy:Number = target.y - target.previous.y;

         if (sfy == tfy) return false;
         
         sourceAxisFrame.x = source.x;
         sourceAxisFrame.y = (source.y > source.previous.y ? source.previous.y : source.y);
         sourceAxisFrame.width = source.width;
         sourceAxisFrame.height = source.height + AxU.abs(sfy);

         targetAxisFrame.x = target.x;
         targetAxisFrame.y = (target.y > target.previous.y ? target.previous.y : target.y);
         targetAxisFrame.width = target.width;
         targetAxisFrame.height = target.height + AxU.abs(tfy);

         var overlap:Number = 0;
         if ((sourceAxisFrame.x + sourceAxisFrame.width - AxU.EPSILON > targetAxisFrame.x) && (sourceAxisFrame.x + AxU.EPSILON < targetAxisFrame.x + targetAxisFrame.width) && (sourceAxisFrame.y + sourceAxisFrame.height - AxU.EPSILON > targetAxisFrame.y) && (sourceAxisFrame.y + AxU.EPSILON < targetAxisFrame.y + targetAxisFrame.height)) {
            var maxOverlap:Number = AxU.abs(sfy) + AxU.abs(tfy) + 120 * Ax.dt;//OVERLAP_BIAS = 4 in flixel, made it framerate independent
            if (sfy > tfy) {
               overlap = source.y + source.height - target.y;
               if (overlap > maxOverlap) {
                  overlap = 0;
               }else{
                  source.touching |= AxEntity.DOWN;
                  target.touching |= AxEntity.UP;
               }
               
            }
            if (sfy < tfy) {
               overlap = source.y - target.height - target.y;
               if (-overlap > maxOverlap) {
                  overlap = 0;
               }else{
                  target.touching |= AxEntity.DOWN;
                  source.touching |= AxEntity.UP;
               }
            }
         }

         var sourceImmovable:Boolean = source.stationary || ((sfy > tfy)? (source.blocked & AxEntity.UP) : (source.blocked & AxEntity.DOWN));
         var targetImmovable:Boolean = target.stationary || ((tfy > sfy)? (target.blocked & AxEntity.UP) : (target.blocked & AxEntity.DOWN));
         if (overlap != 0) {
            if (!sourceImmovable && !targetImmovable) {
               source.y -= overlap / 2;
               target.y += overlap / 2;
               var average:Number = (source.velocity.y + target.velocity.y) / 2;
               source.velocity.y = average;
               target.velocity.y = average;
            }else if (!sourceImmovable) {
               source.y -= overlap;
               source.velocity.y = 0;
            }else if (!targetImmovable) {
               target.y += overlap;
               target.velocity.y = 0;
            }
            if (sourceImmovable) {
               target.blocked |= (sfy > tfy)? AxEntity.UP : AxEntity.DOWN;
            }
            if (targetImmovable) {
               source.blocked |= (tfy > sfy)? AxEntity.UP : AxEntity.DOWN;
            }
            return true;
         }

         return false;
      }
}

AxEntity.as
Code: Select all
package org.axgl {
   /**
    * A basic game entity. AxEntities do not render on the screen, but they can have velocities, accelerations, etc.
    * Most classes extend this class, as only instances of this class can be collided and added to groups.
    */
   public class AxEntity extends AxRect {
      /** Constant value for LEFT. */
      public static const LEFT:uint = 1;
      /** Constant value for RIGHT. */
      public static const RIGHT:uint = 2;
      /** Constant value for UP. */
      public static const UP:uint = 4;
      /** Constant value for DOWN. */
      public static const DOWN:uint = 8;
      /** Constant value meaning no directions. */
      public static const NONE:uint = 0;
      /** Constant value meaning all directions. */
      public static const ANY:uint = LEFT | RIGHT | UP | DOWN;

      /**
       * Determines whether or not this object should be drawn. If this is false, the draw method will
       * not be called.
       *
       * @default true
       */
      public var visible:Boolean;
      /**
       * Determines whether or not this entity should be updated. If this is false, both the update and
       * the systemUpdate methods will not be called. Inactive entities are not collided against.
       *
       * @default true
       */
      public var active:Boolean;
      /**
       * Determines whether or not this object should be collided against. If you call collide and an entity
       * collides against another entity, and either of them are not solid, the collision will not happen
       * (when called with <code>Ax.collide</code>). When calling overlap (via <code>Ax.overlap</code>), callbacks
       * will still happen on non-solid entities.
       *
       * @default true
       */
      public var solid:Boolean;
      /**
       * Determines whether or not this object exists. If an object doesn't exists, it won't be updated, drawn, and it
       * is able to be recycled through the recycle method on an AxGroup. When you destroy() an object, this is set
       * to false.
       */
      public var exists:Boolean;

      /**
       * The velocity of this object. Contains the x, y, and angular velocities. Every frame, if this entity
       * is <code>active</code> and is not <code>stationary</code>, this object will be moved at the rate contained
       * in this vector.
       *
       * @default (0, 0, 0)
       */
      public var velocity:AxVector;
      /**
       * The acceleration of this object. Contains the x, y, and angular accelerations. Every frame, if this entity
       * is <code>active</code> and is not <code>stationary</code>, this entity's velocity will be adjusted at
       * the rate contained in this vector.
       *
       * @default (0, 0, 0)
       */
      public var acceleration:AxVector;

      /**
       * The current rotation, in degrees, of how the entity will be drawn. A rotation of 0 means the entity will be
       * drawn in the same position as the image that was loaded. Positive rotations go clockwise.
       *
       * @default 0
       */
      public var angle:Number;
      /**
       * The terminal (or maximum) velocity of this object. If an entity has acceleration, that acceleration will only
       * increase the objects velocity up until it reaches its terminal velocity. A terminal velocity of 10 means the
       * terminal velocity in the opposite direction will be -10.
       *
       * @default INFINITY
       */
      public var maxVelocity:AxVector;
      /**
       * Drag is the amount that the object will slow down when not accelerating. If an object is accelerating, drag will
       * have no effect on the object. However, once an object stops accelerating, drag will slow the velocity of an
       * entity down until it reaches 0.
       *
       * @default (0, 0, 0)
       */
      public var drag:AxVector;
      /**
       * The offset of the bounding box of this entity.
       * <p>If an entity is loaded with an image that is 100x100, you can use <code>offset, width, and height</code> to
       * change the bounding box that will affect collisions. The width and height determine the size of the bounding box,
       * and offset determines how far to the right and down the upper left corner of the bounding box is.</p>
       */
      public var offset:AxPoint;
      /**
       * Read-only. Contains the position that this entity had during the previous frame.
       */
      public var previous:AxPoint;
      /**
       * A phased entity will trigger collisions, but will act as if it is not solid. Set this to true if you must use
       * <code>Ax.collide</code> instead of overlap, but you don't want the entities to be affected by colliding.
       *
       * @default false
       */
      public var phased:Boolean;
      /**
       * Contains which sides this entity is touching on, or'd together. For example, if an entity is standing on the floor
       * and is moving against a wall to his right, the value of this entity will be DOWN | RIGHT. You can find if an entity
       * is touching a side using either <code>if (touching &amp; LEFT)</code> or <code>if (isTouching(LEFT))</code>.
       *
       * @default NONE
       */
      public var touching:uint;
      /**
       * Contains the sides this object was touching the previous frame. See <code>touching</code> for more details.
       *
       * @default NONE
       */
      public var touched:uint;
      /**
       * Contains the sides this entity cannot move to because it's blocked by a wall or another blocked entity.
       * See <code>touching</code> for more details.
       */
      public var blocked:uint;
      /**
       * For entities that should not move, set this to true in order to skip the calculations for movement. This can be a performance
       * gain if you have a lot of entities that do not move.
       *
       * @default false
       */
      public var stationary:Boolean;
      /**
       * Read-only. Contains the midpoint of this entity, updated every frame.
       */
      public var center:AxPoint;
      /**
       * Read-only. Contains the velocity that this entity had during the previous frame.
       */
      public var pvelocity:AxVector;
      /**
       * The bounds limiting where this entity can move. If null, there are no bounds.
       */
      public var worldBounds:AxRect;
      /** Counter that allow you to disable counting this function's update for the debugger */
      public var countUpdate:Boolean = true;
      /** Counter that allow you to disable counting this function's draw for the debugger */
      public var countDraw:Boolean = true;

      /**
       * Creates a new AxEntity at the position passed.
       *
       * @param x The initial x value of this entity.
       * @param y The initial y value of this entity.
       */
      public function AxEntity(x:Number = 0, y:Number = 0) {
         super(x, y);

         visible = true;
         active = true;
         solid = true;
         exists = true;
         
         center = new AxPoint(x + width / 2, y + height / 2);
         previous = new AxPoint(x, y);
         velocity = new AxVector;
         pvelocity = new AxVector;
         acceleration = new AxVector;
         maxVelocity = new AxVector(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE);
         angle = 0;
         drag = new AxVector;
         offset = new AxRect;
         phased = false;
         stationary = false;
         worldBounds = null;
      }

      /**
       * Every frame update is called once on every object. This method should be overriden by your objects, and should
       * contain the game logic that the object should execute every frame. If you want the object to move and execute
       * its main game logic, *be sure* to call super.update(). When you call super.update(), the state of the object
       * flips (touching becomes touched, etc), so typically you should call super.update() at the *end* of your object's
       * update function.
       */
      public function update():void {
         touched = touching;
         touching = NONE;
         blocked = NONE;
         
         previous.x = x;
         previous.y = y;
         pvelocity.x = velocity.x;
         pvelocity.y = velocity.y;
         
         if (stationary || (velocity.x == 0 && velocity.y == 0 && velocity.a == 0 && acceleration.x == 0 && acceleration.y == 0 && acceleration.a == 0)) {
            return;
         }
         
         velocity.x = calculateVelocity(velocity.x, acceleration.x, drag.x, maxVelocity.x);
         velocity.y = calculateVelocity(velocity.y, acceleration.y, drag.y, maxVelocity.y);
         velocity.a = calculateVelocity(velocity.a, acceleration.a, drag.a, maxVelocity.a);

         x += (velocity.x * Ax.dt) + ((pvelocity.x - velocity.x) * Ax.dt / 2);
         y += (velocity.y * Ax.dt) + ((pvelocity.y - velocity.y) * Ax.dt / 2);
         angle += velocity.a * Ax.dt;
         
         center.x = x + width / 2;
         center.y = y + height / 2;
         
         if (worldBounds != null) {
            if (x < worldBounds.x) {
               velocity.x = 0;
               acceleration.x = Math.max(0, acceleration.x);
               x = worldBounds.x;
            } else if (x + width > worldBounds.width) {
               velocity.x = 0;
               acceleration.x = Math.min(0, acceleration.x);
               x = worldBounds.width - width;
            }
            
            if (y < worldBounds.y) {
               velocity.y = 0;
               acceleration.y = Math.max(0, acceleration.y);
               y = worldBounds.y;
            } else if (y + height > worldBounds.height) {
               velocity.y = 0;
               acceleration.y = Math.min(0, acceleration.y);
               y = worldBounds.height - height;
            }
         }
      }

      /**
       * Every frame, draw is called once on every object in order to render it to the screen. <code>AxEntity</code> is never drawn
       * to the screen, so this method must be override by any object that wants to be drawn.
       */
      public function draw():void {
         // override as needed
      }
      
      /**
       * Calculates the velocity for a single axis using the current velocity, acceleration, drag, and terminal velocity.
       *
       * @param velocity The current velocity of this axis.
       * @param acceleration The current acceleration of this axis.
       * @param drag The current drag of this axis.
       * @param terminal The current terminal velocity of this axis.
       *
       * @return The new velocity based on the inputs and the timestep.
       */
      private function calculateVelocity(velocity:Number, acceleration:Number, drag:Number, terminal:Number):Number {
         if (acceleration != 0) {
            velocity += acceleration * Ax.dt;
         } else {
            var dragEffect:Number = drag * Ax.dt;
            if (velocity - dragEffect > 0) {
               velocity -= dragEffect;
            } else if (velocity + dragEffect < 0) {
               velocity += dragEffect;
            } else {
               velocity = 0;
            }
         }
         
         if (velocity > terminal) {
            velocity = terminal;
         } else if (velocity < -terminal) {
            velocity = -terminal;
         }
         
         return velocity;
      }

      /**
       * Destroys this object, setting it not to be updated or drawn. Does not remove the object from memory,
       * you can reuse any objects you destroy.
       */
      public function destroy():void {
         exists = false;
      }

      /**
       * Returns whether or not this object is touching a solid object in the direction(s) passed. You can test
       * a single direction (<code>isTouching(LEFT)</code>) or multiple at once (<code>isTouching(LEFT | DOWN)</code>).
       *
       * @param directions The direction flag(s) to test.
       *
       * @return True if this object is touching any of the directions passed.
       *
       * @see #wasTouching()
       */
      public function isTouching(directions:uint):Boolean {
         return (touching & directions) > NONE;
      }

      /**
       * Returns whether or not this object was touching a solid object in the direction(s) passed during the previous
       * frame.
       *
       * @param directions The direction flag(s) to test.
       *
       * @return True if this object was touching any of the directions passed.
       *
       * @see #isTouching()
       */
      public function wasTouching(directions:uint):Boolean {
         return (touched & directions) > NONE;
      }
      
      /**
       * @inheritDoc
       */
      override public function overlaps(other:AxRect):Boolean {
         if (!exists || (other is AxEntity && !(other as AxEntity).exists)) {
            return false;
         }
         return super.overlaps(other);
      }
      
      /**
       * Any class that holds onto external resources that should be cleaned up upon deletion should delete those
       * resources in the dispose method. Be sure to call <code>super.dispose()</code> for parent classes to do their cleanup.
       */
      public function dispose():void {
         velocity = null;
         pvelocity = null;
         acceleration = null;
         maxVelocity = null;
         previous = null;
         previous = null;
         offset = null;
         drag = null;
         worldBounds = null;
      }
   }
}

AxTile.as
Code: Select all
package org.axgl.tilemap {
   import org.axgl.AxEntity;

   /**
    * A class describing a single tile in a tilemap. Each tilemap will have one of these for each different
    * type of tile in the map, not for each actual tile.
    */
   public class AxTile extends AxEntity {
      /**
       * The tilemap this tile type belongs to.
       */
      public var map:AxTilemap;
      /**
       * The possible collision directions for this tile.
       * TODO: Currently if you set it to NONE it is not solid, anything else is fully solid. Must support partially solid
       * in the future.
       */
      public var collision:uint;
      /**
       * The callback function that should be called if this tile is collided against.
       */
      public var callback:Function;
      /**
       * The tile type index that this tile represents.
       */
      public var index:uint;

      /**
       * Creates a new AxTile.
       *
       * @param map The tilemap this tile type belongs to.
       * @param index The tile type index that this tile represents.
       * @param width The width of this tile.
       * @param height The height of this tile.
       */
      public function AxTile(map:AxTilemap, index:uint, width:uint, height:uint) {
         super();
         this.map = map;
         this.index = index;
         this.width = width;
         this.height = height;
         this.collision = NONE;
         this.callback = null;
         this.stationary = true;
      }
   }
}
Yorwba
Private
 
Posts: 3
Joined: Wed Aug 08, 2012 6:52 am

Re: Improving the collision system

Postby Arkeus » Mon Aug 13, 2012 8:09 pm

Yorwba wrote:So only collisions between entities and tilemaps were handled correctly.


It really depends on what is "correct" for your game. For example, I don't think I've ever made something where the "share overlap separation equally" has been sufficient. However, I do wish to make it more configurable than only moving one object (I just haven't gotten around to it). But rather than doing what flixel does with sharing the separation, I'd rather add a "mass" property that determines how they are separated. By default everything would have the same mass, and would share it equally (for familiarity), but you could easily tweak something such that if you push against a small box it moves faster than pushing against a large box (by setting mass accordingly).

I do like the idea you have of immovable objects setting blocked traits on specific directions. I'll probably try it out to see how well it works, but then it really makes the behavior of your game dependent on the ordering of objects. For example, if something pushes you into a wall before you collide with the wall (due to collision happening in order of the objects in the group) it will behave differently than if the immovable object came earlier in the list (at least from briefly looking through the code it looks like that would be the case). I'll play around with it a bit when I have time though, and see if it's something that makes sense to have in by default.
Image
User avatar
Arkeus
Site Admin
 
Posts: 363
Joined: Mon Mar 26, 2012 12:43 am

Re: Improving the collision system

Postby EMebane » Wed Mar 06, 2013 3:10 pm

An old version of Flixel had a _fixed_ property for objects. The newest version has an _immovable_ property. They prevent an object from budging when a collision happens. The mass-based option is also an interesting way of handling it. It's just nomenclature, but since you don't plan to implement collision-reaction that would separate the objects, but rather just collision-reaction that prevents overlaps, using the term mass may be misleading. collisionBias may be better to be more accurate in the function of the property and to avoid naming conflicts.
EMebane
Private
 
Posts: 3
Joined: Wed Mar 06, 2013 2:30 pm

Re: Improving the collision system

Postby raniadoll » Mon Aug 12, 2013 8:45 pm

If you pass a map to Tilemap.build that only contains 0 indexies, you get pretty weird buffer overlow issues at runtime.
Thad made me almost NUTS o.O Atm I quick-patched it by taking care of it in line 184 by setting a boolean and later returning zero.
I dont think that this is the best solution .. but well...
Buy trendy dresses http://www.thetrendystyle.com/, pakistani bridal dresses http://www.thetrendystyle.com/bridal_dresses/bd.htm and new indian dresses http://www.thetrendystyle.com/new_arrival/na.htm. You can buy maxi dresses, shalwar kameez, formal dresses, frocks, long gowns and for kurtis and sarees.
raniadoll
Private
 
Posts: 1
Joined: Mon Aug 12, 2013 8:39 pm


Return to Suggestions

Who is online

Users browsing this forum: No registered users and 1 guest

cron