게임 개발에서의 디자인 패턴 적용
최근에 게임 개발 에 디자인 패턴을 적용하는 방법을 연구할 때 특히 나중에 코드 조정 및 유지 관리에서 개발 효율성을 실제로 향상시킬 수 있음을 발견했습니다. 그래서 이 글을 쓰게 되었고 저의 학습 경험을 간략하게 기록하여 나중에 리뷰할 때 영감을 받을 수 있도록 했습니다.
알아채다
- 이 기사는 책과 인터넷 자료를 기반으로 게임 개발에서 디자인 패턴의 가능한 응용 시나리오를 요약할 뿐이며 디자인 패턴의 원리에 대해서는 설명하지 않습니다.
- 실제 응용에서는 일반적으로 여러 디자인 패턴을 조합하여 사용하는 경우가 있습니다. 이 글은 디자인 패턴으로 분류되며, 여러 디자인 패턴에서 동일한 사용 시나리오가 나타나는 상황이 있을 것입니다.
- 실제 개발에서 일부 기능에는 다른 구현 방법이 있거나 일부 디자인 패턴에는 다른 응용 시나리오가 있을 수 있습니다.이 기사의 목록은 잘못되었거나 충분히 포괄적이지 않을 수 있습니다.수정 및 추가를 환영합니다.
창조적인 디자인 패턴
1. 싱글톤
싱글톤 패턴은 게임 개발에 널리 사용됩니다. 싱글톤 패턴은 클래스의 인스턴스가 하나만 있는지 확인하고 해당 인스턴스를 얻을 수 있는 전역 액세스 지점을 제공합니다.
사용되는 장면 | 설명하다 |
---|---|
게임 매니저 | 게임 상태, 레벨 진행 등 게임의 핵심 로직 처리를 담당하며, 외형 모드와 결합하여 사용할 수 있습니다. |
오디오 관리자 | 효과도 마찬가지 |
UI 관리자 | 같게 |
다양한 모듈 관리자 | 같게 |
데이터 지속성 | 같게 |
온라인 게임 클라이언트 | 싱글톤 모드를 사용하여 연결 수를 제한하고 오용으로 인해 너무 많은 연결이 생성되는 것을 방지하고 서버 측 오류를 방지합니다. |
로그 도구 | - |
싱글톤 모드는 편리하지만 가능한 한 적게 사용되어야 합니다
. 설계 변경 또는 요구 사항 증가, 프로그램 설계자는 다른 클래스로 대체할 수 없으며 원래 구현 클래스의 프로그램 코드만 변경할 수 있으므로 수정 종료 요구 사항을 충족할 수 없습니다." —— "Design
Patterns 그리고 완벽한 게임 개발"
싱글톤 패턴을 이용하여 코드를 모듈화할 수 있는데, 싱글톤 패턴(Singleton)을 그대로 사용하면 접근 제한이 없어 코드 혼동 및 유지보수에 어려움이 있을 수 있습니다.
전체 싱글톤 패턴은 액세스 제한을 증가시켜야 합니다. 예를 들어 사전을 쿼리하여 액세스 제한이 있는 싱글톤 모드의 효과를 달성하기 위해 IOC(Inversion of Control) 컨테이너가 도입되었습니다.
게임 코드 프레임워크를 설치에, 단일 인스턴스를 여러 중요한 모듈의 연결 라인에 비교하면 IOC 컨테이너를 도입하는 것은 "케이블 관리자"를 추가하는 것과 같습니다(다른 많은 디자인 패턴에도 이 기능이 있음).
IOC 컨테이너를 사용하면 종속성 반전(D) 및 단일 책임(S) 원칙을 준수하는 코드를 쉽게 작성할 수 있습니다.
2. 팩토리 메소드 패턴(팩토리 메소드)
팩토리 메소드 패턴은 객체의 생성과 사용을 분리하는 방법을 제공합니다.팩토리 인터페이스를 정의함으로써 하위 클래스는 생성할 특정 객체를 결정할 수 있습니다.
사용되는 장면 | 설명하다 |
---|---|
캐릭터 생성 | 팩토리 메소드 패턴을 사용하여 역할 팩토리 인터페이스를 정의한 후 빌더 패턴과 함께 사용할 수 있는 각 역할 유형(예: 플레이어, 적, NPC 등)에 대한 특정 팩토리 클래스를 구현할 수 있습니다. |
도구 생성 | 소품 팩토리 인터페이스를 정의한 다음 각 소품 유형(예: 무기, 갑옷, 소모품 등)에 대한 특정 팩토리 클래스를 구현할 수 있습니다. |
3. 추상 팩토리 패턴(추상 팩토리)
추상 팩토리 패턴은 구체적인 클래스를 지정하지 않고 일련의 관련 객체 또는 종속 객체를 생성하기 위한 인터페이스를 제공합니다. 시스템은 현재 실행 환경에 따라 생성할 하위 클래스 그룹을 결정할 수 있습니다.
사용되는 장면 | 설명하다 |
---|---|
리소스 로딩 | 추상 팩토리 패턴을 사용하여 서로 다른 유형의 리소스에 해당하는 팩토리 클래스를 생성하여 통일된 리소스 로딩 인터페이스를 달성할 수 있습니다. |
UI 생성 | UI 구성 요소의 재사용 및 사용자 지정을 실현하는 데 도움이 되는 다양한 인터페이스 팩토리 클래스를 제공할 수 있습니다. |
레벨 생성 | 다양한 수준 유형(예: 숲, 사막, 도시 등)에 대해 서로 다른 생성 콘텐츠 및 요소를 포함하는 팩토리 클래스를 생성할 수 있으며 새 수준 유형을 추가할 때 추상 팩토리 패턴을 사용할 수 있습니다. |
도구 생성 | 효과도 마찬가지 |
추상팩토리 패턴과 팩토리 메소드 패턴
추상 팩토리 패턴:
- 추상 팩토리 클래스 - *팩토리 인터페이스 - *팩토리 구현 클래스 - *제품 생산
- 확장하기 쉽고 수정하기 쉽지 않음
팩토리 메소드 패턴:
- 팩토리 인터페이스 - 팩토리 구현 클래스 - *제품 생산
- 신제품이 너무 많아 공장이 폭발하기 쉽습니다.
(*는 하나 이상 있을 수 있음을 나타냅니다.)
4. 빌더 모드(빌더)
빌더 패턴은 복잡한 객체의 구성 프로세스를 표현에서 분리하므로 동일한 구성 프로세스가 다른 객체 표현을 만들 수 있습니다. (단계별 조립)
사용되는 장면 | 설명하다 |
---|---|
캐릭터 생성 | 캐릭터는 단계적으로 생성할 수 있으며 다양한 조합(예: 속성, 스킬, 특수 효과, AI 동작 등)을 제공하여 유연한 캐릭터 생성이 가능합니다. |
레벨 생성 | 지도 작성 프로세스는 여러 단계로 나눌 수 있으며, 각 단계는 특정 지도 요소(예: 지형, 건물, 소품 등)를 처리하는 역할을 합니다. |
도구 생성 | 소품과 장비를 단계적으로 생성할 수 있어(공격력, 방어력, 내구도 등) 유연한 조합 제공 |
5. 프로토타입
프로토타입 패턴은 기존의 구성 방법이 아닌 기존 객체(프로토타입)를 복사하여 새로운 객체를 생성합니다.
사용되는 장면 | 설명하다 |
---|---|
게임 리소스 로딩 | Unity의 GameObject.Instance는 프로토타입 패턴입니다. |
행동 디자인 패턴
6. 상태 모드(State)
상태 패턴을 사용하면 개체의 내부 상태가 변경될 때 개체의 동작을 변경할 수 있습니다.
사용되는 장면 | 설명하다 |
---|---|
역할 상태 관리 | 역할 상태를 관리합니다. 서기, 달리기, 점프, 순찰, 공격 등의 상태에 대해서는 상태 패턴을 사용하여 각 상태의 논리와 동작을 별도의 클래스에 캡슐화하여 캐릭터 상태 간의 전환 논리를 보다 명확하게 만듭니다. |
게임 레벨 또는 장면 전환 | 레벨 및 장면 전환, 논리 동작 관리 |
게임 메뉴 및 UI 상태 관리 | 메인 메뉴, 설정 인터페이스, 일시 정지 메뉴 등 상태 모드는 이러한 인터페이스 간의 전환 논리를 단순화하여 UI 시스템을 모듈화하고 유지 관리하기 쉽게 만듭니다. |
상태 모드 및 유한 상태 기계(Finite State Machine, FSM)
상태 패턴은 유한 상태 기계의 객체 지향 구현으로 볼 수 있습니다. 유한 상태 기계의 상태 전이 및 상태 동작은 상태 패턴을 사용하여 보다 명확하게 나타낼 수 있습니다.
게임 개발에서 상태 패턴은 객체의 상태 전환 및 동작을 관리하기 위해 유한 상태 머신을 구현하는 데 사용할 수 있습니다.
7. 중재자 모드(Mediator)
중간 모드는 여러 개체 간의 결합을 줄이고 처리를 위해 개체 간의 상호 작용을 하나의 "중개 개체"로 집중시키는 데 사용됩니다. (여러 하위 시스템 간의 상호 작용 허브)
사용되는 장면 | 설명하다 |
---|---|
하위 시스템 간의 상호 작용 | 게임에서 하위 시스템 간의 상호 작용 허브로 사용할 수 있습니다. |
UI계 묘 | 중간 모드는 각 UI 요소에서 복잡한 UI 상호 작용 관계를 추출하고 처리를 위해 하나의 중간 개체에 집중하는 데 사용할 수 있습니다. |
캐릭터 간의 상호 작용 | 역할 간 대화, 트랜잭션 등의 상호작용 로직은 역할 개체와 분리할 수 있으며, 중간 개체를 도입하여 처리할 수 있습니다. |
이벤트 시스템 | 이벤트 게시 및 구독 프로세스를 단순화하기 위해 플레이어 패배 및 아이템 수집과 같은 이벤트 처리 논리를 중간 개체에 집중합니다(관찰자 모드 권장). |
8. 전략
전략 패턴을 사용하면 런타임에 개체의 동작을 동적으로 변경할 수 있습니다. 전략 패턴을 사용하면 상호 교환 가능한 알고리즘 집합을 독립적인 클래스 집합으로 캡슐화하여 코드를 단순화하고 유지 관리 및 확장성을 개선할 수 있습니다.
사용되는 장면 | 설명하다 |
---|---|
캐릭터 속성 계산 | 전략 패턴을 사용하여 쉽게 수정하고 사용할 수 있도록 다양한 속성과 계산 방법을 분리할 수 있습니다. |
레벨 생성 | 서로 다른 레벨 생성 알고리즘을 독립적인 클래스 세트로 캡슐화할 수 있으며 런타임 시 필요에 따라 레벨 생성 전략을 동적으로 전환할 수 있습니다. |
게임 난이도 조정 | 같게 |
전략 패턴 대 상태 패턴
"상태는 상태 그룹 사이를 전환하는 것이며 상태 간에는 대응하고 연결된 관계가 있습니다. 전략은 관계가 없고 서로의 존재를 알지 못하는 클래스 그룹으로 구성됩니다. 상태는 다음에 의해 제한됩니다. 상태 기계의 스위칭 규칙, 디자인에서
가능한 모든 상태는 초기 단계에서 정의되며 나중에 추가되더라도 원하는 즉시 추가하는 대신 기존 상태와 관련되어야 합니다. 전략은 컴퓨팅 알고리즘을 캡슐화하여 형성된 디자인 패턴이며, 알고리즘 사이에는 관계가 없습니다. 종속성, 새로운 알고리즘을 즉시 추가하거나 교체할 수 있습니다." ——
"디자인 패턴과 완벽한 게임 개발"
9. 템플릿 방법
템플릿 메서드 패턴은 메서드에서 알고리즘의 골격을 정의하고 서브클래스에서 슈퍼클래스로 반복되는 일부 단계를 추상화합니다. 이러한 방식으로 템플릿 메서드를 사용하면 하위 클래스에서 알고리즘의 구조를 변경하지 않고 알고리즘의 특정 단계를 재정의할 수 있습니다. (일반 공정)
사용되는 장면 | 설명하다 |
---|---|
레벨 로딩 | 레벨 로딩의 기본 구조(예: 리소스 미리 로드, 장면 초기화, 캐릭터 로드 등)는 추상 기본 클래스에서 정의할 수 있으며 특정 로드 단계는 하위 클래스로 지연될 수 있습니다. |
업적 시스템 | 템플릿 메서드 패턴을 사용하여 기본 성취 확인 스켈레톤 메서드를 포함하고 서브클래스에서 특정 성취 확인 논리를 구현하는 추상 성취 클래스를 정의할 수 있습니다. |
온라인 게임 로그인 | 로그인 화면 표시, 로그인 방법 선택, 계정 암호 입력, 서버에 요청 전송 등과 같은 로그인 프로세스는 템플릿 방법 모드를 통해 고정되어 로그인 기능 하위 클래스가 특정 작업을 실현할 수 있습니다. |
10. 커맨드 모드(Command)
命令模式将请求封装为对象,将客户端的不同请求参数化,并配合队列、记录、复原等方式来执行请求操作。
使用场景 | 说明 |
---|---|
交互逻辑 | 在MVC框架中,可以用于分担 Controller 层的交互逻辑,让很多混乱的交互逻辑代码从 Controller 迁移到 Command 中 |
操作记录 | 通过存储已执行的命令对象,可以轻松实现撤销和重做功能(如移动单位、放置建筑等)。可用于实时策略游戏和编辑器等场景 |
事件系统 | 可以将一系列事件通过命令模式封装起来,使其可以更灵活的调用 |
在凉鞋老师的框架中:
- 事件由 系统层 向 表现层 发送
- 表现层 只能用 Command 改变底层系统层的状态(数据)
- 表现层 可以直接查询数据
11. 责任链模式(Chain of Responsibility)
责任链模式为请求创建了一个接收者对象链。这些接收者对象按顺序处理请求,直到其中一个处理了该请求为止。
使用场景 | 说明 |
---|---|
关卡切换 | 可以设置各关卡切换条件,当条件达成时跳转到对应关卡。在通关判断上,可以配合策略模式,让通关规则具有其他形式变化 |
AI决策 | 将不同的AI行为链接在一起,让AI根据当前情况处理决策请求,从而实现灵活的AI行为控制 |
12. 观察者模式(Observer)
观察者模式定义了一种一对多的依赖关系,当一个对象(主题)的状态发生变化时,所有依赖于它的对象(观察者)都将得到通知并自动更新。
使用场景 | 说明 |
---|---|
事件系统 | 可以实现一个全局的游戏事件系统,当某个事件触发时,所有订阅了该事件的对象都会收到通知并作出相应处理 |
成就系统 | 监测游戏中的各种事件(如角色升级、任务完成、特定敌人击败等),当满足成就条件时,自动解锁相应的成就并通知玩家 |
观察者模式 与 中介者模式
两者结构相同,但使用场景不同。
观察者模式可以理解为了使业务逻辑更加清晰,从中介者模式中分离出一种专门处理事件订阅与分发的设计模式(笔者的粗浅理解)。
13. 备忘录模式(Memento)
备忘录模式在不破坏对象封装的前提下,捕获对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
使用场景 | 说明 |
---|---|
游戏存档 | 可以利用备忘录模式保存玩家的角色状态、关卡进度、游戏设置等信息 |
状态回滚 | 在角色受到负面效果或需要恢复到之前状态时,可以使用备忘录模式回滚角色属性 |
撤销操作 | 在游戏编辑器或游戏中的一些可撤销操作,可以通过备忘录模式记录并恢复对象的状态 |
14. 访问者模式(Visitor)
访问者模式可以定义一个能够在一个对象结构中对于所有元素执行的操作。访问者可以让你定义一个新的操作,而不必要更改到被操作元素的类接口。被访问者需要开放足够的操作方法和信息。
使用场景 | 说明 |
---|---|
统计数据 | 在对游戏中的各种对象(如角色、敌人、道具等)进行统计时,可以使用访问者模式来实现,避免修改原有类定义 |
辅助管理类 | 当需要对各种对象(如角色、敌人、道具等)的“管理容器”类添加功能时,可以通过访问者模式减少对原有代码的更改 |
15. 迭代器模式(Iterator)
在不知道集合内部细节的情况下,提供一个按序方法存取一个对象集合体的每一个单元。(遍历)
使用场景 | 说明 |
---|---|
遍历对象 | 循环语句(如 for 循环)就可以实现迭代器模式 |
16. 解释器模式(Interpreter)
定义一个程序设计语言所需要的语句,并提供解释来解析(执行)该语言。(翻译)
使用场景 | 说明 |
---|---|
表达式计算 | 可以使用解释器模式来解析和计算游戏中的各种表达式 |
结构型 设计模式
17. 外观模式(Facade)
在游戏开发中,外观模式常被用于简化复杂系统的交互。通过为多个子系统提供一个统一的接口,将复杂的内部逻辑抽象为简单的调用。(高级封装)
使用场景 | 说明 |
---|---|
音频管理器 | 创建一个音频管理器类,可以简化音频播放、暂停、停止等操作的调用。只需通过音频管理器接口来控制音频播放,无需关注音频资源的加载和播放器的创建 |
UI管理器 | 将UI系统中的交互逻辑,如按钮点击事件、文本显示等操作,封装在一个UI管理器类中,简化UI组件的访问和修改,同时降低UI系统与其他系统之间的耦合度 |
数据持久化 | 创建一个保存管理器类,可以简化保存和加载过程,同时方便后期扩展更多的存储功能 |
18. 桥接模式(Bridge)
桥接模式用于将抽象与实现分离,使它们可以独立地变化。使抽象类作为不同实现类间的桥梁。
使用场景 | 说明 |
---|---|
角色与装备 | 可以将角色、装备的抽象与具体实现分离,使不同种类的角色可以搭配和使用不同种类的装备 |
输入系统 | 可以将输入设备(如键盘、鼠标、游戏手柄等)的抽象与具体实现分离,从而简化输入设备的管理和扩展,同时保持游戏逻辑的独立性 |
游戏资源管理 | 游戏资源(如纹理、模型、声音等)可能需要支持多种格式和来源(如本地文件、网络下载、内存中的数据等)。可以将资源的抽象与具体实现分离 |
网络系统 | 可以将网络协议(如TCP、UDP、Websockets等)的抽象与具体实现分离,从而简化网络协议的管理和扩展 |
19. 享元模式(Flyweight)
享元模式的主要目标是通过共享相同的对象,来减少内存占用和提高性能。
使用场景 | 说明 |
---|---|
游戏对象属性共享 | 将游戏中大量具有相同属性的游戏物体中的相同部分提取出来,进行统一管理 |
20. 组合模式(Composite)
组合模式将对象组合成树形结构以表示层次结构。组合模式使得客户端可以以一致的方式处理单个对象和对象组合。
使用场景 | 说明 |
---|---|
UI层次结构 | 通过使用组合模式,可以轻松地组织和管理树型UI菜单,实现事件传递和布局调整等功能 |
游戏任务逻辑 | 可以将任务、子任务和条件等逻辑元素组织成树形结构,实现逻辑的判断和执行等功能 |
21. 装饰模式(Decorator)
装饰模式允许在不改变原始对象结构的情况下,动态地向对象添加新功能,从而实现功能的组合和扩展。
使用场景 | 说明 |
---|---|
角色属性修改 | 可以通过装饰模式增加角色的属性(如生命值、攻击力、防御力等) |
游戏界面扩展 | 可以游戏界面添加额外的功能(如特效、动画、音效等),这样实现起来比较灵活,修改也方便 |
数据加密解密 | - |
装饰模式已有目标增加功能非常方便,但是要避免盲目使用导致系统过于混乱,应将可能需要的功能列在早期的开发计划中。
22. 适配器模式(Adapter)
适配器模式将一个类的接口转换成另一个类所期望的接口,使得原本接口不兼容的类可以一起工作,提高组件的复用性和扩展性。(转接口)
使用场景 | 说明 |
---|---|
第三方库集成 | 当需要集成不同的第三方库(如广告、支付、社交等)时,可以使用适配器模式统一接口,方便切换和扩展不同的第三方库 |
输入设备兼容 | 可以统一不同输入设备(如键盘、鼠标、手柄等)的接口,实现多种输入设备的兼容和扩展 |
游戏引擎升级 | 当游戏引擎升级后,一些接口可能发生变化,使用适配器模式可以降低升级带来的影响 |
网络通信协议适配 | 在多人在线游戏中,可能需要支持多种网络通信协议(如TCP、UDP、WebSocket等),可以使用适配器模式统一接口,方便扩展和切换不同的通信协议 |
23. 代理模式(Proxy)
代理模式为其他对象提供一种代理以控制对这个对象的访问。代理模式可以用于延迟加载、安全控制、日志记录等功能。
使用场景 | 说明 |
---|---|
优化测试 | 可以使用代理模式测试游戏优化的效果,以免去修改原始类的接口及实现 |
网络代理 | 在多人在线游戏中,可以使用代理模式处理与服务器的通信,方便进行数据加密、压缩、缓存等操作 |
在学习设计模式的过程中,我发现设计模式其实是面向对象的数据结构。
一个由0和1组成的系统,通过各种各样的数据结构和算法,层层编织出能够模拟现实的游戏世界,这实在是太美妙了!