Reputation: 57
I have an almost compete game on AndEngine. The only issue is animating a sprite on contact, counting the score once, then ignoring any further updates. When my player entity contacts the object, I can get AndEngine to count the score and animate, but then it keeps counting until the objects aren't touching. This is fixed with setIgnoreUpdates ();, but then it won't animate the object. Any ideas how to fix this?
This is my code so far:
private int score = 0;
AnimatedSprite wooden_crate = new AnimatedSprite(0, 0, resourceManager.wooden_crate_region, vbom);
private void animateCrate()
{
final long[] CRATE_ANIMATE = new long[] {0, 25, 25, 25, 25, 15000};
wooden_crate.animate(CRATE_ANIMATE, 0, 5, true);
}
private void addToScore(int i)
{
score += i;
scoreText.setText("Score: " + score);
}
private PhysicsWorld physicsWorld;
private void createPhysics()
{
physicsWorld = new FixedStepPhysicsWorld(60, new Vector2(0, -24), false);
physicsWorld.setContactListener(contactListener());
registerUpdateHandler(physicsWorld);
}
private static final String TAG_ENTITY = "entity";
private static final String TAG_ENTITY_ATTRIBUTE_X = "x";
private static final String TAG_ENTITY_ATTRIBUTE_Y = "y";
private static final String TAG_ENTITY_ATTRIBUTE_TYPE = "type";
private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_FLOOR = "floor";
private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLAYER = "player";
private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_STEEL_CRATE = "steelCrate";
private static final Object TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_WOODEN_CRATE = "woodenCrate";
private Player player;
private void loadLevel(int levelID)
{
final SimpleLevelLoader levelLoader = new SimpleLevelLoader(vbom);
final FixtureDef FIXTURE_DEF = PhysicsFactory.createFixtureDef(0, 0.01f, 0.5f);
levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(LevelConstants.TAG_LEVEL)
{
public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException
{
final int width = SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_WIDTH);
final int height = SAXUtils.getIntAttributeOrThrow(pAttributes, LevelConstants.TAG_LEVEL_ATTRIBUTE_HEIGHT);
// TODO later we will specify camera BOUNDS and create invisible walls
// on the beginning and on the end of the level.
camera.setBounds(0, 0, width, height); // here we set camera bounds
camera.setBoundsEnabled(true);
return GameScene.this;
}
});
levelLoader.registerEntityLoader(new EntityLoader<SimpleLevelEntityLoaderData>(TAG_ENTITY)
{
public IEntity onLoadEntity(final String pEntityName, final IEntity pParent, final Attributes pAttributes, final SimpleLevelEntityLoaderData pSimpleLevelEntityLoaderData) throws IOException
{
final int x = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_X);
final int y = SAXUtils.getIntAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_Y);
final String type = SAXUtils.getAttributeOrThrow(pAttributes, TAG_ENTITY_ATTRIBUTE_TYPE);
final Sprite levelObject;
if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_FLOOR))
{
levelObject = new Sprite(x, y, resourceManager.platform1_region, vbom);
PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF).setUserData("floor");
}
else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_STEEL_CRATE))
{
levelObject = new Sprite(x, y, resourceManager.steel_crate_region, vbom);
PhysicsFactory.createBoxBody(physicsWorld, levelObject, BodyType.StaticBody, FIXTURE_DEF).setUserData("steelCrate");
}
else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_WOODEN_CRATE))
{
levelObject = new AnimatedSprite(x, y, resourceManager.wooden_crate_region, vbom)
{
@Override
protected void onManagedUpdate(float pSecondsElapsed)
{
super.onManagedUpdate(pSecondsElapsed);
if (player.collidesWith(this))
{
addToScore(1);
animateCrate();
setIgnoreUpdate(true);
};}};
}
else if (type.equals(TAG_ENTITY_ATTRIBUTE_TYPE_VALUE_PLAYER))
{
player = new Player(x, y, vbom, camera, physicsWorld)
{
@Override
public void onDie()
{
// TODO Latter we will handle it.
if (!gameOverDisplayed)
{
displayGameOverText();
this.setIgnoreUpdate(true);
}
}
};
levelObject = player;
}
else
{
throw new IllegalArgumentException();
}
levelObject.setCullingEnabled(true);
return levelObject;
}
});
levelLoader.loadLevelFromAsset(activity.getAssets(), "level/" + levelID + ".lvl");
}
private boolean firstTouch = false;
public boolean onSceneTouchEvent(Scene pScene, TouchEvent pSceneTouchEvent)
{
if (pSceneTouchEvent.isActionDown())
{
if (!firstTouch)
{
player.setRunning();
firstTouch = true;
}
else
{
player.jump();
}
}
return false;
}
private ContactListener contactListener()
{
ContactListener contactListener = new ContactListener()
{
public void beginContact(Contact contact)
{
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
{
if (x2.getBody().getUserData().equals("player"))
{
player.increaseFootContacts();
}
}
}
public void endContact(Contact contact)
{
final Fixture x1 = contact.getFixtureA();
final Fixture x2 = contact.getFixtureB();
if (x1.getBody().getUserData() != null && x2.getBody().getUserData() != null)
{
if (x2.getBody().getUserData().equals("player"))
{
player.decreaseFootContacts();
}
if (x1.getBody().getUserData().equals("steelCrate") && x2.getBody().getUserData().equals("player"))
{
player.onDie();
}
}
}
public void preSolve(Contact contact, Manifold oldManifold)
{
}
public void postSolve(Contact contact, ContactImpulse impulse)
{
}
};
return contactListener;
}
Note that I have added the animateCrate() method as a stab in the dark at another fix. Still only counting score then ignoring animation.
I have tried to implement the example in the first answer, but am not sure given the above code.
Upvotes: 0
Views: 106
Reputation: 6038
How about this solution: Have a boolean flag which is set when contact occurs and reset when contact is finished. Something like this:
public class MyContactListener implements ContactListener {
boolean mContactFlag;
public MyContactListener() {
mContactFlag = false;
}
@Override
public void beginContact(Contact arg0) {
if (mContactFlag){
// Don't animate...
}
else{
// Animate and add score...
mContactFlag = true;
}
}
@Override
public void endContact(Contact arg0) {
mContactFlag = false; // Reset the flag here
}
@Override
public void postSolve(Contact arg0, ContactImpulse arg1) {}
@Override
public void preSolve(Contact arg0, Manifold arg1) {}
}
Upvotes: 1