Use a simple observer pattern:
- The player input (mouse clicks/button presses) manipulates the model (abstract representation of chess board with pieces on it).
- Your graphics component responsible for animating and rendering gets notified when the model's state changes and plays the according animation.
There are two ways to "sync" both modules:
- Prevent any player input while an animation is running.
- Maintain a queue in which you insert animations that are then being played one after another, thus giving your players the possibility to "play ahead" (for example choosing a piece that isn't involved in the current animation and moving it after realizing what the enemy just did)
Don't forget that your model contains all the game logic and follow this rule strictly. The graphics system just acts like an UI, while the model decides whether moves are actually allowed or not. This clear separation answers many questions (like: "What if someone commands a piece to do X, when it's currently doing Y?") and avoids logic problems along the course of the game implementation.
Edit: Example Implementation
Logic should be separated from the graphical representation.
class LogicalPiece {
Type _type; //enum: "Pawn", "Knight", ...
int _owner; //player index
}
class GraphicalPiece : LogicalPiece {
SpriteBatch _sprite;
Vector2 position;
}
The board can then store the logic aspects of all pieces while at the same time providing access to graphical information for the graphics system:
LogicalPiece[] _pieces = new GraphicalPiece[64];
Example move:
//graphics system asks:
if (game.board.isMoveVald(startPos, endPos, player)) {
Move m = game.board.makeMove(startPos, endPos, player);
//process m
} else {
//output error msg
}
where the internal structure of m could look something like that:
m = {
action: "move",
piece: board[34], //the actual GraphicalPiece provided by the board
startPos: {2, 5},
endPos: {1, 7},
effects : [
{ effect: "death",
piece: board[57] //some GraphicalPiece },
{ effect: "promotion",
callback: someFunc }
]
}
The graphics system updates itself with a fixed timestep (for example 60 times per second) and in the course of that includes animations of pieces. The game, when asked to do a move, not only updates itself(/the model), but collects all the changes that this move will cause and provides that information to the graphics system which parses and visualizes it. There are many implementation details to figure out, like:
- What kind of notification to use: Events, callbacks or return values?
- Should there be one central draw method or should every piece know how to draw (and animate) itself, so that the graphics system just dispatches animations?
- etc.
My advice is to start coding! Set yourself very easy goals at first and only add new goals after reaching the current one. The details will crystalize out over the course of programming. By trying to plan everything ahead all you'll accomplish is a headache.
Possible roadmap:
- Be able to draw a game situation with the simplest imaginable implementation: Pieces' graphical representations are updated instantly just like the abstract model (they vanish at one place and pop out at another one)
- With the system in (1) implement all rules of the game so that players can play it with the correct outcome.
- Add moving animations: Pieces shall slide smoothly from origins to destinations.
- Add fighting animations.
...