Dein Spieler und dein Troll sind nichts als Datensätze, was wir das Datenmodell nennen, das deine Welt beschreibt. Leben, Inventar, Angriffsmöglichkeiten, sogar ihr Wissen über die Welt - alles besteht im Datenmodell.
Behalten Sie ein einzelnes Hauptmodellobjekt bei, das alle Daten enthält, die Ihre Welt beschreiben. Es wird allgemeine Weltinformationen wie Schwierigkeitsgrad, physikalische Parameter usw. enthalten. Es wird auch eine Liste / ein Array von Daten bestimmter Entitäten enthalten , wie ich oben beschrieben habe. Dieses Hauptmodell kann aus vielen Unterobjekten bestehen, um Ihre Welt zu beschreiben. Nirgendwo in Ihrem Modell sollten Sie Funktionen haben, die die Spiel- oder Anzeigelogik steuern. Getter sind die einzige Ausnahme und werden nur verwendet, um Ihnen den einfacheren Abruf von Daten aus dem Modell zu ermöglichen (wenn öffentliche Mitglieder dies nicht bereits tun).
Als nächstes erstellen Sie Funktionen in einer oder mehreren "Controller" -Klassen. Sie können sie alle als Hilfsfunktionen in Ihre Hauptklasse schreiben, obwohl dies nach einer Weile ein bisschen groß werden kann. Diese werden als jedes Update bezeichnet, um auf die Daten der Entitäten für verschiedene Zwecke (Bewegung, Angriff usw.) zu reagieren. Das Aufbewahren dieser Funktionen außerhalb einer Entitätsklasse ist ressourceneffizienter. Wenn Sie wissen, was Ihre Entität beschreibt, wissen Sie automatisch, welche Funktionen darauf reagieren müssen.
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.
}
Ein letzter Hinweis ist, dass es auch nützlich ist, die Anzeigelogik von der Spielelogik zu trennen. Die Anzeigelogik würde lauten: "Wo und in welcher Farbe zeichne ich das auf dem Bildschirm?" Spiellogik ist das, was ich oben im Pseudocode umrissen habe.
(Anmerkung von Dev: Während der Verwendung von Klassen folgt dies locker einem funktionalen Programmieransatz, der alle Methoden als ideal zustandslos ansieht, was ein sauberes Datenmodell und einen Verarbeitungsansatz ermöglicht, der Fehler minimiert, die durch den beibehaltenen Zustand verursacht werden. FP ist die ultimative MVC, da sie MVCs erreicht Ziel der Trennung von Anliegen explizit. Siehe diese Frage .)