OOP Practice/Structure for AS3 Game
I'm a bit of a newb to as3 game development but I want to create a somewhat flexible base for a Connect Four game. I'd like to be able to skin the game board and game pieces. Here's what I'm thinking so far. If anyone has suggestions I'd really appreciate it:
GameController extends EventDispatcher - Contains all game grid manipulation methods. - Includes 2D array to keep track of GamePiece loc开发者_StackOverflow中文版ations - Dispatches events after validation when methods are invoked
GameClass extends Sprite: - Holds visual elements of the board - MouseEvent Listeners attached to visual elements, which invoke controller methods - (Custom) ControllerEvent Listeners to update visual look when GameController dispatches
GamePiece Class extend Sprite: - Holds piece's column/row location - Holds currentPlayer index - Loads PNG URL as skin
That's the rough outline. Any red flags or other suggestions are very much appreciated.
It sounds like the GridController is going to suffer from mixed responsibilities; in MVC architectures the Controller's responsibility is to shuffle data back and forth from the Model to the View. Personally I would consider having a GridModel which would hold the underlying multidimensional Array which represents the grid and methods for adding pieces, eg:
public class GridModel extends EventDispatcher {
private var _grid : Array;
public function GridModel(rows : uint, cols : uint) : void {
// Create the data structure which represents the Grid.
_grid = initialiseGrid(rows, cols);
}
public function addPiece(player : uint, col : uint) : void {
if (isValidMove(col)) {
// Update the datastructure, determine which row the piece ended
// up residing in.
const row : uint = // method omitted
// Notify the rest of the system that a move has been made.
dispatchEvent(new GridUpdateEvent(GridUpdateEvent.MOVE, player, col, row, _grid.concat());
}
else {
// Illegal Move, datastructure stays the same, notify the rest
// of the system.
dispatchEvent(new IllegalMoveEvent(IllegalMoveEvent.COLUMN_FULL, player, col, _grid.concat()));
}
}
}
The primary role of your Controller would now be to listen to the events dispatched by the model and then update the View (DisplayList) accordingly. Like-wise, your View should dispatch Events based on user interaction (eg: Player one has indicated that they wish to drop a piece into the 2nd column); the Controller can then call the relevant method on the Model.
The following snippet should give you some indication as to what the responsibilties of the Controller are; don't forget that you can (and should!) break your responsibilities down by making use of multiple Models, Views and, if required Controllers.
public class GameController {
private var _gridModel : GridModel;
private var _stateModel : GameStateModel;
private var _gridView : GridView;
public function GameController(gridModel : GridModel, gameStateModel : GameStateModel, gridView : GridView) {
_gridModel = gridModel;
_gameStateModel : gameStateModel;
_gridView = gridView;
addEventListeners();
}
private function addEventListeners() : void {
_gridModel.addEventListener(GridUpdateEvent.MOVE, onGridUpdateMoveEvent);
_gridView.addEventListener(ColumnSelectionEvent.SELECTED, onColumnSelectedEvent);
}
private function onColumnSelectedEvent(event : ColumnSelectionEvent) : void {
// Query the GameStateModel to find out whos turn it currently is.
const activePlayer : uint = _gameStateModel.activePlayer;
// Ask the GridModel to update.
_gridModel.addPiece(activePlayer, event.column);
}
private function onGridUpdateMoveEvent(event : GridUpdateEvent) : void {
// Update the view.
_gridView.insertPiece(event.player, event.row, event.col);
// Update the GameState to indicate it's the next player turns.
_gameSate.completeTurn();
}
}
精彩评论