Unity游戏设计模式(一)命令模式(Command Pattern)

思考并回答以下问题:

我想大部分的新人跟我一样刚开始学习Unity的时候,控制人物行的写法是这样的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
using UnityEngine;
using System.Collections;

public class Test : MonoBehaviour
{

void Update ()
{
        if (Input.GetKeyDown(KeyCode.Q))
        {
            Skill1();
        }


        if (Input.GetKeyDown(KeyCode.W))
        {
            Skill2();
        }

        if (Input.GetKeyDown(KeyCode.E))
        {
            Skill3();
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            Skill4();
        }
    }

    void Skill1() { }
    void Skill2() { }
    void Skill3() { }
    void Skill4() { }
}

这样的写法会存在重大大的缺陷耦合性太高,按键被定死了,玩家无法根据自己的喜好来设置键位,实际上大部分游戏也不是这么做的,例如我们熟悉的MOBA类游戏DOTA、LOL等游戏来说,他们是可以根据玩家的喜好自定义按键,你可以用QWER放技能,也可以改成1234键释放技能。

这个时候就要使用命令模式了,使用命令模式解耦,实际上就是在按键和命令之间再加了一层,如图:

这样我们我们就完成了中间层对技能的绑定,我们要更改键位时只要将键位绑定到想使用技能的中间层就完成了解耦合了。

我们在玩一些策略类游戏例如三国志之类的会发现,当你下达命令后这些命令并不会立即执行,而是当你确认执行以后才能够真正开始执行,同时在未真正执行命令前,你是可以取消一些命令,然后再执行的。

具体代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public abstract class Command
{
public abstract void Excute();
public abstract void Undo();
}

public class JumpCommand : Command
{
public override void Excute() { Debug.Log("Jump"); }
public override void Undo() { Debug.Log("Undo Jump"); }
}

public class WalkCommand : Command
{
public override void Excute() { Debug.Log("Walk"); }
public override void Undo() { Debug.Log("Undo Walk"); }
}

public class CommandPattern : MonoBehaviour
{
public KeyCode[] keyCodes= {
KeyCode.A,
KeyCode.B,
KeyCode.Space,
KeyCode.Z
};

private List<Command> CommandList = new List<Command>();
Command jump = new JumpCommand();
Command walkup = new WalkCommand();

void Start()
{

}

void Update()
{
if (Input.GetKeyDown(keyCodes[0]))
{
CommandList.Add(jump);
}

if (Input.GetKeyDown(keyCodes[1]))
{
CommandList.Add(walkup);
}

if (Input.GetKeyDown(keyCodes[2]))
{
foreach (Command cmd in CommandList)
{
cmd.Excute();
}

CommandList.Clear();
}

if (Input.GetKeyDown(keyCodes[3]))
{
CommandList[CommandList.Count - 1].Undo();
CommandList.RemoveAt(CommandList.Count - 1);
}
}
}

首先我们定义抽象类Command,Command中有两个抽象方法Excute和Undo,他们并不具体实现什么功能。然后定义Jump类继承自Command类。在Jump类中的Excute和Undo才是真正实现的方法。然后我们定义一个Command的List,我们每次执行一个方法就将方法放入队列中,当最后确认要真正执行时,才遍历List列表执行各个功能。同时我们在未执行前,可通过Undo实现功能的撤销,再通过RemoveAt方法移除表中最后一个执行方法,这样就实现了功能的撤销了。如果要重做也可以通过类似的方法实现Redo功能,这里就不细讲了。

0%