I have this class
package net.omnosis.mazegame.components;
import net.omnosis.mazegame.SlicedBitmap;
import android.graphics.Bitmap;
public class PlayerLayer extends DrawableLayer {
private Player player;
private XY tileImageSize;
private int[] move = new int[] { 1, 2, 3, 4, 3, 2, 1, 6, 7, 8, 7, 6 };
//private int[] move = new int[] { 8 };
private int moveCount;
private int moveCountMax = move.length;
private Bitmap playerBitmap;
public SlicedBitmap playerTiles;
private int line;
private static final int VERTICAL = 0;
private static final int HORIZONTAL = 8;
public PlayerLayer(Player player, Bitmap playerBitmap, XY tileImageSize) {
this.playerBitmap = playerBitmap;
this.tileImageSize = tileImageSize;
playerTiles = new SlicedBitmap(playerBitmap, tileImageSize.x(), tileImageSize.y());
setPlayer(player);
update();
}
public final void setPlayer(Player player) {
if (this.player != null) {
this.player.removeListener(this);
}
this.player = player;
player.addListener(this);
update();
}
public void updateDirection() {
Direction dir = player.getHeading();
if (dir == Direction.LEFT || dir == Direction.RIGHT) {
line = HORIZONTAL;
} else if (dir == Direction.TOP || dir == Direction.BOTTOM) {
line = VERTICAL;
}
}
public synchronized void animate() {
if (player.isMoving()) {
moveCount++;
if (moveCount >= moveCountMax) {
player.finishMove();
moveCount = 0;
}
} else {
}
updateDirection();
super.update();
}
public void update() {
updateDirection();
super.update();
}
public XY getSpritePos() {
XY playerPos = new XY(player.getCurrentPosition().x() * tileImageSize.x() + (tileImageSize.x() / 2), player.getCurrentPosition().y() * tileImageSize.y() + (tileImageSize.y() / 2));
XY animationPos = getAnimationPos();
return playerPos.add(animationPos);
}
public XY getAnimationPos() {
double step = (double) tileImageSize.x() / moveCountMax * moveCount;
return player.getHeading().multiply((int) step);
}
public Bitmap getBitmap() {
if (moveCount >= moveCountMax) {
System.out.println("BUG! MORE: " + moveCount + " max: " + moveCountMax);
moveCount = 0;
}
return playerTiles.getTile(move[moveCount] + line);
}
}
A thread calls the animate method every 10msec. Sometimes I get this output: BUG! MORE: 12 max: 12 This is because I check the value AGAIN in the getBitmap() method. Why?
I dont understand that if the animate is synchronized, how can the moveCount be more than 11?
This happens more frequently if the emulator laggs.
You are incrementing and resetting
moveCountin asynchronizedblock, but you are not synchronizing on the same lock when you access themoveCountvariable in thegetBitmap()method.This means that Thread A could be in the middle of the
animate()method, and has incrementedmoveCountto be equal tomoveCountMax. Thread B then entersgetBitmap()and reads the value ofmoveCountbefore Thread A resetsmoveCountto 0.In general, you need to synchronize not just when you write to the value of the variable, but also when you read from it (on the same lock), especially if one of the operations on that variable (like your
animate()method) involves compound operations (increment, then maybe reset to 0)BTW, if
moveCountMaxis a constant value (= moves.length), mark it asfinal.