Twój gracz i twój troll są niczym innym jak zestawami danych, które nazywamy modelem danych opisującym twój świat. Życie, ekwipunek, możliwości ataku, a nawet ich znajomość świata - wszystko opiera się na modelu danych.
Zachowaj jeden główny obiekt modelu, który przechowuje wszystkie dane opisujące Twój świat. Będzie zawierał ogólne informacje o świecie, takie jak trudność, parametry fizyki itp. Będzie także zawierał listę / tablicę danych określonych bytów , jak to opisano powyżej. Ten główny model może składać się z wielu podobiektów w celu opisania twojego świata. Nigdzie w twoim modelu nie powinieneś mieć żadnych funkcji sterujących logiką gry lub logiką wyświetlania; gettery są jedynym wyjątkiem i byłyby używane tylko w celu umożliwienia łatwiejszego pobierania danych z modelu (jeśli członkowie publiczni jeszcze tego nie zrobią).
Następnie utwórz funkcje w jednej lub więcej klasach „kontrolerów”; możesz napisać je wszystkie jako funkcje pomocnicze w swojej klasie głównej, chociaż po pewnym czasie może to nieco wzrosnąć. Będą one nazywane każdą aktualizacją, aby działać na danych podmiotów w różnych celach (ruch, atak itp.). Trzymanie tych funkcji poza klasą encji jest bardziej zasobooszczędne, a gdy wiesz, co opisuje twoją encję, automatycznie wiesz, jakie funkcje muszą na nią działać.
class Main
{
//...members variables...
var model:GameModel = new GameModel();
//...member functions...
function realTimeUpdate() //called x times per second, on a timer.
{
for each (var entity in model.entities)
{
//command processing
if (entity == player)
decideActionsFromPlayerInput(entity);
else //everyone else is your enemy!
decideActionsThroughDeviousAI(entity);
act(entity);
}
}
//OR
function turnBasedUpdate()
{
if (model.whoseTurn == "player")
{
decideActionsFromInput(model.player); //may be some movement or none at all
act(player);
}
else
{
var enemy;
for each (var entity in model.entities)
{
if (entity != model.player)
{
enemy = entity;
decideActions(enemy);
act(enemy);
}
}
}
}
//AND THEN... (common to both turn-based and real-time)
function decideActionsThroughDeviousAI(enemy)
{
if (distanceBetween(enemy, player) <= enemy.maximumAttackDistance)
storeAttackCommand(enemy, "kidney punch", model.player);
else
storeMoveCommand(player, getVectorFromTo(enemy, model.player));
}
function decideActionsFromPlayerInput(player)
{
//store commands to your player data based on keyboard input
if (KeyManager.isKeyDown("A"))
storeMoveCommand(player, getForwardVector(player));
if (KeyManager.isKeyDown("space"))
storeAttackCommand(player, "groin slam", currentlyHighlightedEnemy);
}
function storeAttackCommand(entity, attackType, target)
{
entity.target = target;
entity.currentAttack = attackType;
//OR
entity.attackQueue.add(attackType);
}
function storeMoveCommand(entity, motionVector)
{
entity.motionVector = motionVector;
}
function act(entity)
{
entity.position += entity.motionVector;
attack(entity.target, entity.currentAttack);
}
}
class GameModel
{
var entities:Array = []; //or List<Entity> or whatever!
var player:Entity; //will often also appear in the entity list, above
var difficultyLevel:int;
var globalMaxAttackDamage:int;
var whoseTurn:Boolean; //if turnbased
//etc.
}
Ostatnia uwaga jest taka, że przydatne jest także oddzielenie logiki wyświetlania od logiki gry. Logika wyświetlania brzmiałaby: „Gdzie narysować to na ekranie i w jakim kolorze?” vs. logika gry jest tym, co zarysowałem w powyższym pseudokodzie.
(Nota dewelopera: Podczas korzystania z klas, to luźno podąża za funkcjonalnym podejściem programistycznym, które uznaje wszystkie metody za idealnie bezstanowe, pozwalając na czysty model danych i podejście do przetwarzania, które minimalizuje błędy spowodowane stanem zatrzymanym. FP jest ostatecznym MVC, ponieważ osiąga MVC cel wyraźnego rozdzielenia obaw. Zobacz to pytanie ).