[Guide] AStarPathModifier

  ... tutorials on how to use AndEngine.

[Guide] AStarPathModifier

Postby CaptnIgnit » Thu Aug 25, 2011 4:52 am

So I finally got off my lazy ass and implemented this. This can replace the old path code altogether so you only need to deal with the A* based paths.

I took Nicholas' PathModifier code and just updated it to use A* Paths so it should work fairly decently. I also added a few methods to IPathModifierListener, turning it into the IAStarPathModifierListener. The new methods deal with which direction your next step will be (mostly useful for setting which animation you should use).

Here's the code:
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. package korkd.tower;
  2.  
  3. import java.util.ArrayList;
  4.  
  5. import org.anddev.andengine.entity.IEntity;
  6. import org.anddev.andengine.entity.layer.tiled.tmx.TMXTiledMap;
  7. import org.anddev.andengine.entity.modifier.EntityModifier;
  8. import org.anddev.andengine.entity.modifier.MoveModifier;
  9. import org.anddev.andengine.util.modifier.IModifier;
  10. import org.anddev.andengine.util.modifier.SequenceModifier;
  11. import org.anddev.andengine.util.modifier.SequenceModifier.ISubSequenceModifierListener;
  12. import org.anddev.andengine.util.modifier.ease.IEaseFunction;
  13. import org.anddev.andengine.util.path.Path;
  14. import org.anddev.andengine.util.path.Path.Step;
  15.  
  16. import android.util.FloatMath;
  17.  
  18. public class AStarPathModifier extends EntityModifier {
  19.         // ===========================================================
  20.         // Constants
  21.         // ===========================================================
  22.  
  23.         // ===========================================================
  24.         // Fields
  25.         // ===========================================================
  26.  
  27.         private final SequenceModifier<IEntity> mSequenceModifier;
  28.  
  29.         private IAStarPathModifierListener mPathModifierListener;
  30.  
  31.         private final Path mPath;
  32.        
  33.         private TMXTiledMap mTMXTiledMap;
  34.  
  35.         // ===========================================================
  36.         // Constructors
  37.         // ===========================================================
  38.  
  39.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap) {
  40.                 this(pDuration, pPath, pTMXTiledMap, null, null, IEaseFunction.DEFAULT);
  41.         }
  42.  
  43.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IEaseFunction pEaseFunction) {
  44.                 this(pDuration, pPath, pTMXTiledMap, null, null, pEaseFunction);
  45.         }
  46.  
  47.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IEntityModifierListener pEntityModiferListener) {
  48.                 this(pDuration, pPath, pTMXTiledMap, pEntityModiferListener, null, IEaseFunction.DEFAULT);
  49.         }
  50.  
  51.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IAStarPathModifierListener pPathModifierListener) {
  52.                 this(pDuration, pPath, pTMXTiledMap, null, pPathModifierListener, IEaseFunction.DEFAULT);
  53.         }
  54.  
  55.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IAStarPathModifierListener pPathModifierListener, final IEaseFunction pEaseFunction) {
  56.                 this(pDuration, pPath, pTMXTiledMap, null, pPathModifierListener, pEaseFunction);
  57.         }
  58.  
  59.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IEntityModifierListener pEntityModiferListener, final IEaseFunction pEaseFunction) {
  60.                 this(pDuration, pPath, pTMXTiledMap, pEntityModiferListener, null, pEaseFunction);
  61.         }
  62.  
  63.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IEntityModifierListener pEntityModiferListener, final IAStarPathModifierListener pPathModifierListener) throws IllegalArgumentException {
  64.                 this(pDuration, pPath, pTMXTiledMap, pEntityModiferListener, pPathModifierListener, IEaseFunction.DEFAULT);
  65.         }
  66.  
  67.         public AStarPathModifier(final float pDuration, final Path pPath, final TMXTiledMap pTMXTiledMap, final IEntityModifierListener pEntityModiferListener, final IAStarPathModifierListener pPathModifierListener, final IEaseFunction pEaseFunction) throws IllegalArgumentException {
  68.                 super(pEntityModiferListener);
  69.                 final int pathSize = pPath.getLength();
  70.  
  71.                 if (pathSize < 2) {
  72.                         throw new IllegalArgumentException("Path needs at least 2 waypoints!");
  73.                 }
  74.  
  75.                 this.mTMXTiledMap = pTMXTiledMap;
  76.                 this.mPath = pPath;
  77.                 this.mPathModifierListener = pPathModifierListener;
  78.  
  79.                 final MoveModifier[] moveModifiers = new MoveModifier[pathSize - 1];
  80.  
  81.                 final float velocity = (pPath.getLength() * mTMXTiledMap.getTileWidth()) / pDuration;
  82.  
  83.                 final int modifierCount = moveModifiers.length;
  84.                 for(int i = 0; i < modifierCount; i++) {
  85.                         final float duration = getSegmentLength(i) / velocity;
  86.                         moveModifiers[i] = new MoveModifier(duration, getXCoordinates(i), getXCoordinates(i + 1), getYCoordinates(i), getYCoordinates(i + 1), null, pEaseFunction);
  87.                 }
  88.  
  89.                 /* Create a new SequenceModifier and register the listeners that
  90.                  * call through to mEntityModifierListener and mPathModifierListener. */
  91.                 this.mSequenceModifier = new SequenceModifier<IEntity>(
  92.                                 new ISubSequenceModifierListener<IEntity>() {
  93.                                         @Override
  94.                                         public void onSubSequenceStarted(final IModifier<IEntity> pModifier, final IEntity pEntity, final int pIndex) {
  95.                                                 if(pIndex < pathSize)
  96.                                 {
  97.                                         switch(pPath.getDirectionToNextStep(pIndex)) {
  98.                                             case DOWN:
  99.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  100.                                                                                 AStarPathModifier.this.mPathModifierListener.onNextMoveDown(AStarPathModifier.this, pEntity, pIndex);
  101.                                                                         }
  102.                                                 break;
  103.                                             case RIGHT:
  104.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  105.                                                                                 AStarPathModifier.this.mPathModifierListener.onNextMoveRight(AStarPathModifier.this, pEntity, pIndex);
  106.                                                                         }
  107.                                             break;
  108.                                             case UP:
  109.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  110.                                                                                 AStarPathModifier.this.mPathModifierListener.onNextMoveUp(AStarPathModifier.this, pEntity, pIndex);
  111.                                                                         }
  112.                                             break;
  113.                                             case LEFT:
  114.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  115.                                                                                 AStarPathModifier.this.mPathModifierListener.onNextMoveLeft(AStarPathModifier.this, pEntity, pIndex);
  116.                                                                         }
  117.                                                 break;
  118.                                                 default:
  119.                                                                
  120.                                     }
  121.                                 }
  122.                                                
  123.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  124.                                                         AStarPathModifier.this.mPathModifierListener.onPathWaypointStarted(AStarPathModifier.this, pEntity, pIndex);
  125.                                                 }
  126.                                         }
  127.  
  128.                                         @Override
  129.                                         public void onSubSequenceFinished(final IModifier<IEntity> pEntityModifier, final IEntity pEntity, final int pIndex) {
  130.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  131.                                                         AStarPathModifier.this.mPathModifierListener.onPathWaypointFinished(AStarPathModifier.this, pEntity, pIndex);
  132.                                                 }
  133.                                         }
  134.                                 },
  135.                                 new IEntityModifierListener() {
  136.                                         @Override
  137.                                         public void onModifierStarted(final IModifier<IEntity> pModifier, final IEntity pEntity) {
  138.                                                 AStarPathModifier.this.onModifierStarted(pEntity);
  139.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  140.                                                         AStarPathModifier.this.mPathModifierListener.onPathStarted(AStarPathModifier.this, pEntity);
  141.                                                 }
  142.                                         }
  143.  
  144.                                         @Override
  145.                                         public void onModifierFinished(final IModifier<IEntity> pEntityModifier, final IEntity pEntity) {
  146.                                                 AStarPathModifier.this.onModifierFinished(pEntity);
  147.                                                 if(AStarPathModifier.this.mPathModifierListener != null) {
  148.                                                         AStarPathModifier.this.mPathModifierListener.onPathFinished(AStarPathModifier.this, pEntity);
  149.                                                 }
  150.                                         }
  151.                                 },
  152.                                 moveModifiers
  153.                 );
  154.         }
  155.  
  156.         private float getXCoordinates(int pIndex) {
  157.                 return mPath.getStep(pIndex).getTileColumn() * mTMXTiledMap.getTileWidth();
  158.         }
  159.  
  160.         private float getYCoordinates(int pIndex) {
  161.                 return mPath.getStep(pIndex).getTileRow() * mTMXTiledMap.getTileHeight();
  162.         }
  163.        
  164.         private float getSegmentLength(int pIndex) {
  165.  
  166.         final int nextSegmentIndex = pIndex + 1;
  167.  
  168.         final float dx = getXCoordinates(pIndex) - getXCoordinates(nextSegmentIndex);
  169.         final float dy = getYCoordinates(pIndex) - getYCoordinates(nextSegmentIndex);
  170.  
  171.         return FloatMath.sqrt(dx * dx + dy * dy);
  172.         }
  173.  
  174.         @Override
  175.         public AStarPathModifier clone() throws CloneNotSupportedException {
  176.                 // TODO: deepCopy still needs to be implemented on AStarPath's
  177.                 return null;
  178.         }
  179.  
  180.         // ===========================================================
  181.         // Getter & Setter
  182.         // ===========================================================
  183.  
  184.         public Path getPath() {
  185.                 return this.mPath;
  186.         }
  187.  
  188.         // ===========================================================
  189.         // Methods for/from SuperClass/Interfaces
  190.         // ===========================================================
  191.  
  192.         @Override
  193.         public boolean isFinished() {
  194.                 return this.mSequenceModifier.isFinished();
  195.         }
  196.  
  197.         @Override
  198.         public float getSecondsElapsed() {
  199.                 return this.mSequenceModifier.getSecondsElapsed();
  200.         }
  201.  
  202.         @Override
  203.         public float getDuration() {
  204.                 return this.mSequenceModifier.getDuration();
  205.         }
  206.  
  207.         public IAStarPathModifierListener getPathModifierListener() {
  208.                 return this.mPathModifierListener;
  209.         }
  210.  
  211.         public void setPathModifierListener(final IAStarPathModifierListener pPathModifierListener) {
  212.                 this.mPathModifierListener = pPathModifierListener;
  213.         }
  214.  
  215.         @Override
  216.         public void reset() {
  217.                 this.mSequenceModifier.reset();
  218.         }
  219.  
  220.         @Override
  221.         public float onUpdate(final float pSecondsElapsed, final IEntity pEntity) {
  222.                 return this.mSequenceModifier.onUpdate(pSecondsElapsed, pEntity);
  223.         }
  224.  
  225.         // ===========================================================
  226.         // Methods
  227.         // ===========================================================
  228.  
  229.         // ===========================================================
  230.         // Inner and Anonymous Classes
  231.         // ===========================================================
  232.  
  233.         public static interface IAStarPathModifierListener {
  234.                 // ===========================================================
  235.                 // Constants
  236.                 // ===========================================================
  237.  
  238.                 // ===========================================================
  239.                 // Fields
  240.                 // ===========================================================
  241.  
  242.                 public void onPathStarted(final AStarPathModifier pPathModifier, final IEntity pEntity);
  243.                 public void onNextMoveLeft(AStarPathModifier aStarPathModifier, IEntity pEntity, int pIndex);
  244.                 public void onNextMoveUp(AStarPathModifier aStarPathModifier, IEntity pEntity, int pIndex);
  245.                 public void onNextMoveRight(AStarPathModifier aStarPathModifier, IEntity pEntity, int pIndex);
  246.                 public void onNextMoveDown(AStarPathModifier aStarPathModifier, IEntity pEntity, int pIndex);
  247.                 public void onPathWaypointStarted(final AStarPathModifier pPathModifier, final IEntity pEntity, final int pWaypointIndex);
  248.                 public void onPathWaypointFinished(final AStarPathModifier pPathModifier, final IEntity pEntity, final int pWaypointIndex);
  249.                 public void onPathFinished(final AStarPathModifier pPathModifier, final IEntity pEntity);
  250.         }
  251. }
  252.  
Parsed in 0.067 seconds, using GeSHi 1.0.8.4


and here's an example of a register call to it:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. this.registerEntityModifier(new AStarPathModifier(path.getPathLength()/2, path.getAStarPath(), mTMXTiledMap, new AStarPathModifier.IAStarPathModifierListener()
  2.                 {
  3.                 @Override
  4.                 public void onPathWaypointStarted(AStarPathModifier pPathModifier, final IEntity pEntity, int pWaypointIndex) {
  5.                 }
  6.  
  7.                         @Override
  8.                         public void onPathStarted(AStarPathModifier pPathModifier,
  9.                                         IEntity pEntity) {
  10.                                
  11.                         }
  12.  
  13.                         @Override
  14.                         public void onPathWaypointFinished(AStarPathModifier pPathModifier,
  15.                                         IEntity pEntity, int pWaypointIndex) {
  16.                                
  17.                         }
  18.  
  19.                         @Override
  20.                         public void onPathFinished(AStarPathModifier pPathModifier,
  21.                                         IEntity pEntity) {
  22.                                
  23.                                 mArmyPool.recyclePoolItem(mArmy);
  24.                         mPlayer.Reached(mDestCastle);
  25.                         mSourceCastle = null;
  26.                         mDestCastle = null;
  27.                                
  28.                         }
  29.  
  30.                         @Override
  31.                         public void onNextMoveLeft(AStarPathModifier aStarPathModifier,
  32.                                         IEntity pEntity, int pIndex) {
  33.                 mArmy.animate(new long[]{200, 200, 200}, 9, 11, true);
  34.                         }
  35.  
  36.                         @Override
  37.                         public void onNextMoveUp(AStarPathModifier aStarPathModifier,
  38.                                         IEntity pEntity, int pIndex) {
  39.                 mArmy.animate(new long[]{200, 200, 200}, 0, 2, true);
  40.                         }
  41.  
  42.                         @Override
  43.                         public void onNextMoveRight(AStarPathModifier aStarPathModifier,
  44.                                         IEntity pEntity, int pIndex) {
  45.                 mArmy.animate(new long[]{200, 200, 200}, 3, 5, true);
  46.                         }
  47.  
  48.                         @Override
  49.                         public void onNextMoveDown(AStarPathModifier aStarPathModifier,
  50.                                         IEntity pEntity, int pIndex) {
  51.                                 mArmy.animate(new long[]{200, 200, 200}, 6, 8, true);
  52.                         }
  53.                 }));
  54.         }
Parsed in 0.041 seconds, using GeSHi 1.0.8.4
CaptnIgnit
 
Posts: 87
Joined: Tue Feb 01, 2011 5:10 am

Re: [Guide] AStarPathModifier

Postby Araqiel » Thu Aug 25, 2011 5:10 am

Now write an isometric TMX loader and I'll love you forever.

But seriously, this is pretty cool. I might find a use for it...
Araqiel
 
Posts: 63
Joined: Fri Jan 14, 2011 4:14 am

Re: [Guide] AStarPathModifier

Postby kblood » Thu Aug 25, 2011 8:42 pm

This looks really useful. Seems like it is not specific to one sprite, but could be used for several paths at once, for several sprites.

Would be nice with a link to a complete project, since the AndEngine has a way of changing fast, and it is such a mess trying to figure out if the problem is conflicts between versions of the author and mine, or me implementing it the wrong way.

I am focusing on something else at the moment, but I will definitely give this a try one day.
kblood
 
Posts: 333
Joined: Wed May 25, 2011 10:13 pm

Re: [Guide] AStarPathModifier

Postby rf1982 » Fri Aug 26, 2011 5:19 pm

Thread bookmarked!
rf1982
 
Posts: 30
Joined: Wed Jul 27, 2011 11:15 am

Re: [Guide] AStarPathModifier

Postby CaptnIgnit » Sat Aug 27, 2011 12:29 am

Here's an updated one that I submitted to features, it is more generic and doesn't rely on TMXTiledMaps.

features/astarpathmodifier-t4716.html
CaptnIgnit
 
Posts: 87
Joined: Tue Feb 01, 2011 5:10 am


Return to Tutorials

Who is online

Users browsing this forum: Yahoo [Bot] and 28 guests