2017-01-14 2 views
0

Ich schreibe ein Spiel in Unity, wo man Spielmodi hat, aber schließlich das gleiche Niveau verwendet, ist es nur, dass die Dinge anders verhalten. Der Unterschied besteht nur darin, wie der Spieler zum Beispiel zielen muss, also muss er/sie schnell die gleichen Plätze für die Ziele finden (die Ziele erscheinen in der gleichen Reihenfolge) oder sie erscheinen zufällig. Es ist die gleiche Bühne, aber mit anderen Regeln, so dachte ich, eine interface wäre von Vorteil - die GameManager Klasse implementiert es basierend auf dem Spielmodus. Natürlich könnte ich verschiedene Game Manager s schreiben oder eine switch in einem verwenden, aber ich möchte Dinge für eine Änderung organisiert halten. Frage ist, wie es geht?Implementieren Funktionen basierend auf verschiedenen Spielmodi

+0

Sie benötigen einen Zustand Maschinen für den Spielstatus. Verwalten Sie dann levelspezifische Details, indem Sie die Reihenfolge und/oder die Elemente des Methodenarrays in Ihrer Statusmaschine ändern. – Bijan

+0

Ich habe ein Hinch, was du meinst, aber könntest du etwas weiter erklären? – agiro

+0

sicher, werfen Sie einen Blick unter – Bijan

Antwort

2

Dies ist, wie Sie Setup eine einfache Zustandsmaschine:

//state 
public enum GameMode { Normal, Endless, Campaign, Idle, Count } 
private GameMode gameMode; 

//state machine array 
private delegate void UpdateDelegate(); 
private UpdateDelegate[] UpdateDelegates; 

void Awake() 
{ 
    //setup all UpdateDelegates here to avoid runtime memory allocation 
    UpdateDelegates = new UpdateDelegate[(int)GameMode.Count]; 

    //and then each UpdateDelegate 
    UpdateDelegates[(int)GameMode.Normal] = UpdateNormalState; 
    UpdateDelegates[(int)GameMode.Endless] = UpdateEndlessState; 
    UpdateDelegates[(int)GameMode.Campaign] = UpdateCampaignState; 
    UpdateDelegates[(int)GameMode.Idle] = UpdateIdleState 

    gameMode = GameMode.Idle; 
} 

void Update() 
{ 
    //call the update method of current state 
    if(UpdateDelegates[(int)gameMode]!=null) 
     UpdateDelegates[(int)gameMode](); 
} 

Jetzt können Sie die Logik eines jeden Staates trennen:

void UpdateNormalState() { 
    //... 
    //write logic for normal state 
} 
//... 
//same for other states 

diese Weise, wenn Sie Spielmodus, die Update-Methode neuer ändern Der Status wird iterativ nach dem Ende des aktuellen Rahmens aufgerufen.

für weitere Informationen können Sie watch this video


Die gute Sache über State-Maschinen ist, dass sie leicht (im Vergleich mit switch-case oder viele ifs) zu handhaben. Sie haben eine Reihe von Methoden und können mit ihnen alles tun, was Sie wollen und trotzdem sicher sein, dass nur einer von ihnen gleichzeitig ausgeführt werden kann. die maximale Verzögerung für die Änderung Staaten ist immer so kurz wie Time.deltaTime (wenn Update-Methode wird verwendet, Zustandsmaschine Methoden aufrufen)


Sie können sogar die Zustandsmaschine 2D machen. aber stellen Sie sicher, dass Sie alle


UpdateDelegates

public enum GameMode { Normal, Endless, Campaign, Idle, Count } 
public enum GameState { Playing, Paused, GameOver, Idle, Count } 
private UpdateDelegate[,] UpdateDelegates; 
UpdateDelegates = new UpdateDelegate[(int)GameMode.Count, (int)GameState.Count]; 
zuweisen Wenn es für Ihr Spiel ist nicht genug, können Sie eine erweiterte Zustandsmaschine verwenden. Hier ist ein Beispielcode, den ich irgendwo kopiert und noch nicht getestet habe:

Dieser Ansatz verwendet Übergänge zwischen Zuständen. z.B. Rufen Sie MoveNext mit einem gegebenen Command und es ändert den Zustand zu nächsten ProcessState unter Berücksichtigung der aktuellen ProcessState der Zustandsmaschine und den gegebenen Befehl.

using System; 
using System.Collections.Generic; 

namespace Juliet 
{ 
    public enum ProcessState 
    { 
     Inactive, 
     Active, 
     Paused, 
     Terminated 
    } 

    public enum Command 
    { 
     Begin, 
     End, 
     Pause, 
     Resume, 
     Exit 
    } 

    public class Process 
    { 
     class StateTransition 
     { 
      readonly ProcessState CurrentState; 
      readonly Command Command; 

      public StateTransition(ProcessState currentState, Command command) 
      { 
       CurrentState = currentState; 
       Command = command; 
      } 

      public override int GetHashCode() 
      { 
       return 17 + 31 * CurrentState.GetHashCode() + 31 * Command.GetHashCode(); 
      } 

      public override bool Equals(object obj) 
      { 
       StateTransition other = obj as StateTransition; 
       return other != null && this.CurrentState == other.CurrentState && this.Command == other.Command; 
      } 
     } 

     Dictionary<StateTransition, ProcessState> transitions; 
     public ProcessState CurrentState { get; private set; } 

     public Process() 
     { 
      CurrentState = ProcessState.Inactive; 
      transitions = new Dictionary<StateTransition, ProcessState> 
      { 
       { new StateTransition(ProcessState.Inactive, Command.Exit), ProcessState.Terminated }, 
       { new StateTransition(ProcessState.Inactive, Command.Begin), ProcessState.Active }, 
       { new StateTransition(ProcessState.Active, Command.End), ProcessState.Inactive }, 
       { new StateTransition(ProcessState.Active, Command.Pause), ProcessState.Paused }, 
       { new StateTransition(ProcessState.Paused, Command.End), ProcessState.Inactive }, 
       { new StateTransition(ProcessState.Paused, Command.Resume), ProcessState.Active } 
      }; 
     } 

     public ProcessState GetNext(Command command) 
     { 
      StateTransition transition = new StateTransition(CurrentState, command); 
      ProcessState nextState; 
      if (!transitions.TryGetValue(transition, out nextState)) 
       throw new Exception("Invalid transition: " + CurrentState + " -> " + command); 
      return nextState; 
     } 

     public ProcessState MoveNext(Command command) 
     { 
      CurrentState = GetNext(command); 
      return CurrentState; 
     } 
    } 


    public class Program 
    { 
     static void Main(string[] args) 
     { 
      Process p = new Process(); 
      Console.WriteLine("Current State = " + p.CurrentState); 
      Console.WriteLine("Command.Begin: Current State = " + p.MoveNext(Command.Begin)); 
      Console.WriteLine("Command.Pause: Current State = " + p.MoveNext(Command.Pause)); 
      Console.WriteLine("Command.End: Current State = " + p.MoveNext(Command.End)); 
      Console.WriteLine("Command.Exit: Current State = " + p.MoveNext(Command.Exit)); 
      Console.ReadLine(); 
     } 
    } 
} 
+0

Detailliert und klar, auf jeden Fall was ich gesucht habe. Vielen Dank! Ich gebe zu, auf dem Weg habe ich eine 'Schnittstelle' erstellt und wenn der _game-Modus_ in tritt und ich würde die verschiedenen Funktionen verwenden müssen, so habe ich 3 Klassen die gleiche Schnittstelle implementieren. Der Game-Manager ruft nur die Funktion auf und teilt dem "IRules" -Objekt mit, was passiert ist. Ihre Lösung ist besser und sauberer. – agiro

Verwandte Themen