Wir laden zukünftige Studenten des Kurses " Unity Game Developer. Professional " ein , die offene Lektion zum Thema "Fortgeschrittene künstliche Intelligenz von Feinden in Schützen" zu sehen.
Und jetzt teilen wir die traditionelle Übersetzung von nützlichem Material.
In diesem Tutorial werden wir das Befehlsentwurfsmuster beherrschen und es in Unity als Teil eines Spielobjekt-Bewegungssystems implementieren.
Einführung in das Befehlsmuster
Anfragen, Befehle und Befehle : Wir alle kennen sie im wirklichen Leben. Eine Person sendet eine Anfrage (oder einen Befehl oder einen Befehl) an eine andere Person, um einige der ihr zugewiesenen Aufgaben auszuführen (oder nicht auszuführen). Bei der Entwicklung und Entwicklung von Software funktioniert dies auf ähnliche Weise: Eine Anforderung von einer Komponente wird an eine andere übergeben, um bestimmte Aufgaben innerhalb des Teammusters auszuführen.
: — , , () , . , / .
. , ( ). — : (GUI), , (logic handler), -.
GUI , . , GUI -.
UML . , , .
Command
, (ConcreteCommandN
) Invoker
, Client
Receiver
.
Command
Command (Execute) (Undo) . Execute , , Undo.
public interface ICommand
{
void Execute();
void ExecuteUndo();
}
Invoker
Invoker
( Sender
) . , . , . . , . .
Client
(Client) . , (Receiver), . . , .
Receiver ( )
Receiver () — , -. . , , .
Command . , - ( ). .
, , . (immutable), .
Unity
, Unity . . (Undo), .
, !
3D Unity
3D Unity. CommandDesignPattern
.
Plane, . Hierarchy Plane. «Ground» 20 X 20 z. , .
Player
. Capsule
. Hierarchy Capsule
. Player
.
GameManager.cs
Ground
. GameManager.cs
.
Player
.
public GameObject
player
.
public GameObject mPlayer;
Player
Hierarchy
Player
.
(Up, Down, Left Right).
. Update
. 1 .
void Update()
{
Vector3 dir = Vector3.zero;
if (Input.GetKeyDown(KeyCode.UpArrow))
dir.z = 1.0f;
else if (Input.GetKeyDown(KeyCode.DownArrow))
dir.z = -1.0f;
else if (Input.GetKeyDown(KeyCode.LeftArrow))
dir.x = -1.0f;
else if (Input.GetKeyDown(KeyCode.RightArrow))
dir.x = 1.0f;
if (dir != Vector3.zero)
{
_player.transform.position += dir;
}
}
Play
, . (Up, Down, Left Right), .
— Player
Ground
, . ?
, Ground
, .
public Vector3? GetClickPosition()
{
if(Input.GetMouseButtonDown(1))
{
RaycastHit hitInfo;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if(Physics.Raycast(ray, out hitInfo))
{
//Debug.Log("Tag = " + hitInfo.collider.gameObject.tag);
return hitInfo.point;
}
}
return null;
}
Vector3?
?
C#,
public int? myProperty { get; set; }
, nullable
Nullable
,System.Nullable
. ,NULL
,NULL
. ,Nullable<Int32>
,«Nullable of Int32»
, -2147483648 2147483647,null
.Nullable<bool>
true
,false
null
.null
, , , . ,true
false
, .
, , MoveTo
. MoveTo
. .
public IEnumerator MoveToInSeconds(GameObject objectToMove, Vector3 end, float seconds)
{
float elapsedTime = 0;
Vector3 startingPos = objectToMove.transform.position;
end.y = startingPos.y;
while (elapsedTime < seconds)
{
objectToMove.transform.position = Vector3.Lerp(startingPos, end, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return null;
}
objectToMove.transform.position = end;
}
, , , .
Update
, .
****
var clickPoint = GetClickPosition();
if (clickPoint != null)
{
IEnumerator moveto = MoveToInSeconds(_player, clickPoint.Value, 0.5f);
StartCoroutine(moveto);
}
****
Play
, . (Up, Down, Left Right) Ground
, Player
.
(Undo
)? ? .
Unity
Undo
, , .
Undo
— , Unity.
. Command
.
Command
public interface ICommand { void Execute(); void ExecuteUndo(); }
Command
. — Execute
, — ExecuteUndo
, . ( , ).
.
CommandMove
public class CommandMove : ICommand
{
public CommandMove(GameObject obj, Vector3 direction)
{
mGameObject = obj;
mDirection = direction;
}
public void Execute()
{
mGameObject.transform.position += mDirection;
}
public void ExecuteUndo()
{
mGameObject.transform.position -= mDirection;
}
GameObject mGameObject;
Vector3 mDirection;
}
CommandMoveTo
public class CommandMoveTo : ICommand
{
public CommandMoveTo(GameManager manager, Vector3 startPos, Vector3 destPos)
{
mGameManager = manager;
mDestination = destPos;
mStartPosition = startPos;
}
public void Execute()
{
mGameManager.MoveTo(mDestination);
}
public void ExecuteUndo()
{
mGameManager.MoveTo(mStartPosition);
}
GameManager mGameManager;
Vector3 mDestination;
Vector3 mStartPosition;
}
, ExecuteUndo
. , Execute
.
Invoker
Invoker
. , Invoker
— , . , Undo
Last In First Out (LIFO)
.
LIFO? LIFO? Stack
.
C# , LIFO (Last In First Out). . Push()
( ), Pop()
( ) Peek()
.
Invoker
, .
public class Invoker
{
public Invoker()
{
mCommands = new Stack<ICommand>();
}
public void Execute(ICommand command)
{
if (command != null)
{
mCommands.Push(command);
mCommands.Peek().Execute();
}
}
public void Undo()
{
if(mCommands.Count > 0)
{
mCommands.Peek().ExecuteUndo();
mCommands.Pop();
}
}
Stack<ICommand> mCommands;
}
, Execute
Undo
. Execute
, Push
Execute
. Peek
.
Undo ExecuteUndo
, ( Peek
). Invoker
, Pop
.
Invoker
. Invoker
GameManager
.
private Invoker mInvoker;
mInvoker
Start
GameManager.
mInvoker = new Invoker();
Undo
U
. Update
.
// Undo
if (Input.GetKeyDown(KeyCode.U))
{
mInvoker.Undo();
}
Update
.
void Update()
{
Vector3 dir = Vector3.zero;
if (Input.GetKeyDown(KeyCode.UpArrow))
dir.z = 1.0f;
else if (Input.GetKeyDown(KeyCode.DownArrow))
dir.z = -1.0f;
else if (Input.GetKeyDown(KeyCode.LeftArrow))
dir.x = -1.0f;
else if (Input.GetKeyDown(KeyCode.RightArrow))
dir.x = 1.0f;
if (dir != Vector3.zero)
{
//Using command pattern implementation.
ICommand move = new CommandMove(mPlayer, dir);
mInvoker.Execute(move);
}
var clickPoint = GetClickPosition();
//Using command pattern right click moveto.
if (clickPoint != null)
{
CommandMoveTo moveto = new CommandMoveTo(
this,
mPlayer.transform.position,
clickPoint.Value);
mInvoker.Execute(moveto);
}
// Undo
if (Input.GetKeyDown(KeyCode.U))
{
mInvoker.Undo();
}
}
Play
, . (Up, Down, Left Right), , «u» .
— GoF, , - , , , , , .
Unity
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class GameManager : MonoBehaviour
{
public interface ICommand
{
void Execute();
void ExecuteUndo();
}
public class CommandMove : ICommand
{
public CommandMove(GameObject obj, Vector3 direction)
{
mGameObject = obj;
mDirection = direction;
}
public void Execute()
{
mGameObject.transform.position += mDirection;
}
public void ExecuteUndo()
{
mGameObject.transform.position -= mDirection;
}
GameObject mGameObject;
Vector3 mDirection;
}
public class Invoker
{
public Invoker()
{
mCommands = new Stack<ICommand>();
}
public void Execute(ICommand command)
{
if (command != null)
{
mCommands.Push(command);
mCommands.Peek().Execute();
}
}
public void Undo()
{
if (mCommands.Count > 0)
{
mCommands.Peek().ExecuteUndo();
mCommands.Pop();
}
}
Stack<ICommand> mCommands;
}
public GameObject mPlayer;
private Invoker mInvoker;
public class CommandMoveTo : ICommand
{
public CommandMoveTo(GameManager manager, Vector3 startPos, Vector3 destPos)
{
mGameManager = manager;
mDestination = destPos;
mStartPosition = startPos;
}
public void Execute()
{
mGameManager.MoveTo(mDestination);
}
public void ExecuteUndo()
{
mGameManager.MoveTo(mStartPosition);
}
GameManager mGameManager;
Vector3 mDestination;
Vector3 mStartPosition;
}
public IEnumerator MoveToInSeconds(GameObject objectToMove, Vector3 end, float seconds)
{
float elapsedTime = 0;
Vector3 startingPos = objectToMove.transform.position;
end.y = startingPos.y;
while (elapsedTime < seconds)
{
objectToMove.transform.position = Vector3.Lerp(startingPos, end, (elapsedTime / seconds));
elapsedTime += Time.deltaTime;
yield return null;
}
objectToMove.transform.position = end;
}
public Vector3? GetClickPosition()
{
if (Input.GetMouseButtonDown(1))
{
RaycastHit hitInfo;
Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hitInfo))
{
//Debug.Log("Tag = " + hitInfo.collider.gameObject.tag);
return hitInfo.point;
}
}
return null;
}
// Start is called before the first frame update
void Start()
{
mInvoker = new Invoker();
}
// Update is called once per frame
void Update()
{
Vector3 dir = Vector3.zero;
if (Input.GetKeyDown(KeyCode.UpArrow))
dir.z = 1.0f;
else if (Input.GetKeyDown(KeyCode.DownArrow))
dir.z = -1.0f;
else if (Input.GetKeyDown(KeyCode.LeftArrow))
dir.x = -1.0f;
else if (Input.GetKeyDown(KeyCode.RightArrow))
dir.x = 1.0f;
if (dir != Vector3.zero)
{
//----------------------------------------------------//
//Using normal implementation.
//mPlayer.transform.position += dir;
//----------------------------------------------------//
//----------------------------------------------------//
//Using command pattern implementation.
ICommand move = new CommandMove(mPlayer, dir);
mInvoker.Execute(move);
//----------------------------------------------------//
}
var clickPoint = GetClickPosition();
//----------------------------------------------------//
//Using normal implementation for right click moveto.
//if (clickPoint != null)
//{
// IEnumerator moveto = MoveToInSeconds(mPlayer, clickPoint.Value, 0.5f);
// StartCoroutine(moveto);
//}
//----------------------------------------------------//
//----------------------------------------------------//
//Using command pattern right click moveto.
if (clickPoint != null)
{
CommandMoveTo moveto = new CommandMoveTo(this, mPlayer.transform.position, clickPoint.Value);
mInvoker.Execute(moveto);
}
//----------------------------------------------------//
//----------------------------------------------------//
// Undo
if (Input.GetKeyDown(KeyCode.U))
{
mInvoker.Undo();
}
//----------------------------------------------------//
}
public void MoveTo(Vector3 pt)
{
IEnumerator moveto = MoveToInSeconds(mPlayer, pt, 0.5f);
StartCoroutine(moveto);
}
}
Wikipedia Command Design Pattern
Design Patterns in Game Programming
"Unity Game Developer. Professional".
" ".
