游戏开发中常用的设计模式
### 一、创建型模式
#### 1. 单例模式 (Singleton)
确保一个类只有一个实例,提供全局访问点。
代码示例:
```lua
local GameManager = {}
GameManager.__index = GameManager
local instance = nil
function GameManager.GetInstance()
if not instance then
instance = setmetatable({}, GameManager)
instance.score = 0
instance.level = 1
end
return instance
end
local gm = GameManager.GetInstance()
```
应用场景:游戏状态管理、资源管理器、音频管理器、配置管理
#### 2. 对象池模式 (Object Pool)
重用对象,避免频繁创建和销毁。
代码示例:
```lua
local BulletPool = {}
BulletPool.__index = BulletPool
function BulletPool.new(size)
local self = setmetatable({}, BulletPool)
self.pool = {}
for i = 1, size do
table.insert(self.pool, {active = false, x = 0, y = 0})
end
return self
end
function BulletPool:acquire(x, y)
for _, bullet in ipairs(self.pool) do
if not bullet.active then
bullet.active = true
bullet.x = x
bullet.y = y
return bullet
end
end
return nil
end
function BulletPool:release(bullet)
bullet.active = false
end
```
应用场景:子弹、粒子效果、敌人对象、特效对象、连接池
#### 3. 原型模式 (Prototype)
通过克隆来创建对象。
代码示例:
```lua
local Enemy = {}
Enemy.__index = Enemy
function Enemy:clone()
local new_enemy = {}
for k, v in pairs(self) do
new_enemy[k] = v
end
setmetatable(new_enemy, Enemy)
return new_enemy
end
local goblin_prototype = setmetatable({
health = 100,
damage = 10,
speed = 5
}, Enemy)
local goblin1 = goblin_prototype:clone()
local goblin2 = goblin_prototype:clone()
```
### 二、结构型模式
#### 4. 组件模式 (Component)
将功能拆分成独立组件,动态组合。
代码示例:
```lua
local Component = {}
Component.__index = Component
function Component.new(name)
local self = setmetatable({}, Component)
self.name = name
return self
end
local HealthComponent = Component.new("Health")
function HealthComponent:update(dt)
if self.health <= 0 then
self.parent:destroy()
end
end
local MovementComponent = Component.new("Movement")
function MovementComponent:update(dt)
self.parent.x = self.parent.x + self.parent.vx * dt
self.parent.y = self.parent.y + self.parent.vy * dt
end
local GameObject = {}
GameObject.__index = GameObject
function GameObject.new()
local self = setmetatable({}, GameObject)
self.components = {}
return self
end
function GameObject:addComponent(component)
component.parent = self
self.components[component.name] = component
end
function GameObject:update(dt)
for _, component in pairs(self.components) do
if component.update then
component:update(dt)
end
end
end
```
#### 5. 外观模式 (Facade)
为复杂子系统提供简单接口。
代码示例:
```lua
local GameAPI = {}
function GameAPI.startGame()
AudioManager:playBGM("main_theme")
SceneManager:loadScene("level1")
UIManager:showHUD()
InputManager:enableInput()
end
function GameAPI.pauseGame()
TimeManager:pause()
AudioManager:pauseBGM()
UIManager:showPauseMenu()
end
GameAPI.startGame()
```
### 三、行为型模式
#### 6. 观察者模式 (Observer)
对象状态变化时通知所有依赖者。
代码示例:
```lua
local EventSystem = {}
EventSystem.listeners = {}
function EventSystem.register(event, callback)
if not EventSystem.listeners[event] then
EventSystem.listeners[event] = {}
end
table.insert(EventSystem.listeners[event], callback)
end
function EventSystem.emit(event, data)
if EventSystem.listeners[event] then
for _, callback in ipairs(EventSystem.listeners[event]) do
callback(data)
end
end
end
EventSystem.register("onEnemyKilled", function(data)
print("击杀敌人: " .. data.enemy_type)
AchievementSystem:checkAchievement("killer", data)
end)
EventSystem.register("onHealthChanged", function(data)
UIManager:updateHealthBar(data.current, data.max)
end)
function onEnemyDeath(enemy)
EventSystem.emit("onEnemyKilled", {
enemy_type = enemy.type,
position = {x = enemy.x, y = enemy.y}
})
end
```
#### 7. 状态模式 (State)
对象行为随状态改变而改变。
代码示例:
```lua
local PlayerState = {}
PlayerState.__index = PlayerState
function PlayerState:enter(player) end
function PlayerState:exit(player) end
function PlayerState:update(player, dt) end
function PlayerState:handleInput(player, input) end
local IdleState = setmetatable({}, PlayerState)
function IdleState:enter(player)
player.animation:play("idle")
end
function IdleState:handleInput(player, input)
if input == "move" then
player:changeState(RunState)
elseif input == "jump" then
player:changeState(JumpState)
end
end
local RunState = setmetatable({}, PlayerState)
function RunState:enter(player)
player.animation:play("run")
player.speed = 200
end
function RunState:handleInput(player, input)
if input == "stop" then
player:changeState(IdleState)
elseif input == "jump" then
player:changeState(JumpState)
end
end
local Player = {}
Player.__index = Player
function Player.new()
local self = setmetatable({}, Player)
self.state = nil
self.states = {idle = IdleState, run = RunState, jump = JumpState}
return self
end
function Player:changeState(newState)
if self.state then
self.state:exit(self)
end
self.state = newState
self.state:enter(self)
end
```
#### 8. 命令模式 (Command)
将请求封装为对象,支持撤销、重做。
代码示例:
```lua
local Command = {}
Command.__index = Command
function Command:execute() end
function Command:undo() end
local MoveCommand = setmetatable({}, Command)
function MoveCommand.new(entity, dx, dy)
local self = setmetatable({}, MoveCommand)
self.entity = entity
self.dx = dx
self.dy = dy
self.old_x = entity.x
self.old_y = entity.y
return self
end
function MoveCommand:execute()
self.entity.x = self.entity.x + self.dx
self.entity.y = self.entity.y + self.dy
end
function MoveCommand:undo()
self.entity.x = self.old_x
self.entity.y = self.old_y
end
local InputSystem = {}
InputSystem.commands = {}
InputSystem.history = {}
function InputSystem:bind(key, command)
self.commands[key] = command
end
function InputSystem:handleInput(key)
local command = self.commands[key]
if command then
command:execute()
table.insert(self.history, command)
end
end
function InputSystem:undo()
local command = table.remove(self.history)
if command then
command:undo()
end
end
```
#### 9. 策略模式 (Strategy)
定义算法族,运行时选择算法。
代码示例:
```lua
local AttackStrategy = {}
AttackStrategy.__index = AttackStrategy
local MeleeStrategy = setmetatable({}, AttackStrategy)
function MeleeStrategy:attack(enemy)
print("近战攻击造成50伤害")
enemy:takeDamage(50)
end
local RangedStrategy = setmetatable({}, AttackStrategy)
function RangedStrategy:attack(enemy)
print("远程攻击造成30伤害")
enemy:takeDamage(30)
end
local MagicStrategy = setmetatable({}, AttackStrategy)
function MagicStrategy:attack(enemy)
print("魔法攻击造成80伤害,消耗20法力")
enemy:takeDamage(80)
end
local Player = {}
Player.__index = Player
function Player.new()
local self = setmetatable({}, Player)
self.attack_strategy = MeleeStrategy
return self
end
function Player:setAttackStrategy(strategy)
self.attack_strategy = strategy
end
function Player:attack(enemy)
self.attack_strategy:attack(enemy)
end
local player = Player.new()
player:attack(enemy)
player:setAttackStrategy(RangedStrategy)
player:attack(enemy)
player:setAttackStrategy(MagicStrategy)
player:attack(enemy)
```
### 四、优化型模式
#### 10. 数据驱动模式 (Data-Driven)
将游戏数据与逻辑分离。
代码示例:
```lua
local enemy_data = {
goblin = {health = 100, damage = 10, speed = 5, model = "goblin.obj", texture = "goblin.png"},
orc = {health = 200, damage = 20, speed = 3, model = "orc.obj", texture = "orc.png"},
dragon = {health = 1000, damage = 100, speed = 8, model = "dragon.obj", texture = "dragon.png", abilities = {"fire_breath", "fly"}}
}
local EnemyFactory = {}
function EnemyFactory.create(type)
local data = enemy_data[type]
if not data then return nil end
local enemy = {
health = data.health,
damage = data.damage,
speed = data.speed,
model = data.model,
texture = data.texture
}
return enemy
end
local goblin = EnemyFactory.create("goblin")
local dragon = EnemyFactory.create("dragon")
```
#### 11. 空间分区模式 (Spatial Partition)
优化空间查询性能。
代码示例:
```lua
local Grid = {}
Grid.__index = Grid
function Grid.new(width, height, cell_size)
local self = setmetatable({}, Grid)
self.cell_size = cell_size
self.cells = {}
self.width = width
self.height = height
return self
end
function Grid:getCellKey(x, y)
local cx = math.floor(x / self.cell_size)
local cy = math.floor(y / self.cell_size)
return cx .. "," .. cy
end
function Grid:addEntity(entity)
local key = self:getCellKey(entity.x, entity.y)
if not self.cells[key] then
self.cells[key] = {}
end
table.insert(self.cells[key], entity)
entity.cell_key = key
end
function Grid:getNearbyEntities(x, y, radius)
local nearby = {}
local cell_radius = math.ceil(radius / self.cell_size)
local cx = math.floor(x / self.cell_size)
local cy = math.floor(y / self.cell_size)
for dx = -cell_radius, cell_radius do
for dy = -cell_radius, cell_radius do
local key = (cx + dx) .. "," .. (cy + dy)
if self.cells[key] then
for _, entity in ipairs(self.cells[key]) do
local dist = math.sqrt((entity.x - x)^2 + (entity.y - y)^2)
if dist <= radius then
table.insert(nearby, entity)
end
end
end
end
end
return nearby
end
```
### 五、游戏特定模式
#### 12. 更新循环模式 (Update Loop)
驱动游戏逻辑的持续执行。
代码示例:
```lua
local GameLoop = {}
GameLoop.__index = GameLoop
function GameLoop.new()
local self = setmetatable({}, GameLoop)
self.last_time = 0
self.accumulator = 0
self.update_interval = 1 / 60
self.updatables = {}
return self
end
function GameLoop:addUpdatable(obj)
table.insert(self.updatables, obj)
end
function GameLoop:run()
local current_time = love.timer.getTime()
local delta_time = current_time - self.last_time
self.last_time = current_time
self.accumulator = self.accumulator + delta_time
while self.accumulator >= self.update_interval do
for _, obj in ipairs(self.updatables) do
obj:update(self.update_interval)
end
self.accumulator = self.accumulator - self.update_interval
end
for _, obj in ipairs(self.updatables) do
obj:draw()
end
end
```
#### 13. 双缓冲模式 (Double Buffer)
避免渲染撕裂,实现平滑动画。
代码示例:
```lua
local DoubleBuffer = {}
DoubleBuffer.__index = DoubleBuffer
function DoubleBuffer.new(initial_data)
local self = setmetatable({}, DoubleBuffer)
initial_data = initial_data or {x = 0, y = 0}
self.front = {x = initial_data.x, y = initial_data.y}
self.back = {x = initial_data.x, y = initial_data.y}
return self
end
function DoubleBuffer:write(data)
self.back.x = data.x
self.back.y = data.y
end
function DoubleBuffer:swap()
self.front, self.back = self.back, self.front
end
function DoubleBuffer:read()
return self.front
end
-- 游戏对象
local GameObject = {}
GameObject.__index = GameObject
function GameObject.new(x, y)
local self = setmetatable({}, GameObject)
self.position = DoubleBuffer.new({x = x or 0, y = y or 0})
self.velocity = {x = 1, y = 0} -- 向右移动
return self
end
function GameObject:update(dt)
-- 读取当前位置
local current = self.position:read()
-- 计算新位置
local new_x = current.x + self.velocity.x * dt
local new_y = current.y + self.velocity.y * dt
-- 写入后台缓冲
self.position:write({x = new_x, y = new_y})
-- 交换前后台
self.position:swap()
end
function GameObject:draw()
local pos = self.position:read()
print(string.format("绘制位置: (%.2f, %.2f)", pos.x, pos.y))
end
-- 模拟游戏循环
local obj = GameObject.new(0, 0)
local dt = 0.1
for i = 1, 5 do
print("\n--- 帧", i, "---")
obj:update(dt)
obj:draw()
end
-- 输出示例:
-- --- 帧 1 ---
-- 绘制位置: (0.10, 0.00)
-- --- 帧 2 ---
-- 绘制位置: (0.20, 0.00)
-- --- 帧 3 ---
-- 绘制位置: (0.30, 0.00)
```
#### 14. 游戏状态管理 (Game State)
代码示例:
```lua
-- 简化的状态管理器
local StateManager = {
states = {},
current = nil
}
function StateManager:add(name, state)
state.name = name
self.states[name] = state
end
function StateManager:switch(name, ...)
if self.current and self.current.onExit then
self.current:onExit()
end
self.current = self.states[name]
if not self.current then
error("State not found: " .. name)
end
if self.current.onEnter then
self.current:onEnter(...)
end
end
function StateManager:update(dt)
if self.current and self.current.onUpdate then
self.current:onUpdate(dt)
end
end
function StateManager:draw()
if self.current and self.current.onDraw then
self.current:onDraw()
end
end
-- 创建状态
local menuState = {
onEnter = function()
print("进入菜单")
end,
onUpdate = function(dt)
-- 检测输入
if love and love.keyboard.isDown("return") then
StateManager:switch("game")
end
end,
onDraw = function()
print("绘制菜单")
end
}
local gameState = {
player = {health = 100},
onEnter = function(level)
print("进入游戏,关卡: " .. level)
self.player.health = 100
end,
onUpdate = function(dt)
if self.player.health <= 0 then
StateManager:switch("gameover")
end
end,
onDraw = function()
print("绘制游戏,血量: " .. self.player.health)
end
}
local gameOverState = {
onEnter = function(score)
print("游戏结束,得分: " .. score)
end,
onUpdate = function(dt)
if love and love.keyboard.isDown("return") then
StateManager:switch("menu")
end
end,
onDraw = function()
print("绘制游戏结束画面")
end
}
-- 注册状态
StateManager:add("menu", menuState)
StateManager:add("game", gameState)
StateManager:add("gameover", gameOverState)
-- 启动游戏
StateManager:switch("menu")
```
### 六、设计模式选择指南
| 场景 | 推荐模式 |
|------|----------|
| 需要全局唯一实例 | 单例模式 |
| 频繁创建销毁对象 | 对象池模式 |
| 对象有多种状态 | 状态模式 |
| 需要撤销/重做功能 | 命令模式 |
| 系统间需要解耦 | 观察者模式 |
| 算法可互换 | 策略模式 |
| 优化空间查询 | 空间分区 |
| 动态组合功能 | 组件模式 |
| 游戏数据配置 | 数据驱动 |
### 七、最佳实践
1. 不要过度设计:简单场景用简单方案
2. 性能优先:游戏开发中性能是关键
3. 代码可读性:团队协作时尤为重要
4. 迭代优化:先实现功能,再优化性能
5. 选择合适模式:根据具体问题选择,不强行套用