今天还是继续完成游戏练习, 上次我们已经在场景中生成敌人, 但是没有一个战斗场地, 并且敌人不会动, 今天来完善这些内容
先看看效果
实现过程
添加战斗场地
这部分比较简单, 使用Sprite2D显示一张背景图
再到Main场景中新增4个StaticBody2D, 覆盖战斗场地的四周, 防止敌人或者玩家跑出场地之外
敌人生成整理
上一节中我们在Main场景中直接生成, 但是将所有逻辑都糅杂在一个场景中并不是一个好习惯, 最好使用组件化思路, 拆分逻辑
这里我们使用一个EnemySpawnComponent组件, 专门负责敌人生成逻辑
class_name EnemySpawnComponent
extends Node
const ENEMY = preload("uid://pu2c45uixpy0")
@export var spawn_root: Node2D
@export var spawn_rect: ReferenceRect
@onready var spawn_timer: Timer = $SpawnTimer
func _ready() -> void:
if is_multiplayer_authority():
spawn_timer.timeout.connect(_on_spawn_timer_timeout)
else:
spawn_timer.process_mode = Node.PROCESS_MODE_DISABLED
func _get_random_position() -> Vector2:
var pos := Vector2(
randf_range(0, spawn_rect.size.x),
randf_range(0, spawn_rect.size.y),
)
pos += spawn_rect.global_position
return pos
func _on_spawn_timer_timeout() -> void:
var enemy := ENEMY.instantiate() as Node2D
enemy.global_position = _get_random_position()
#print("[peer %s] enemy spawn pos: %s" % [multiplayer.get_unique_id(), enemy.global_position])
spawn_root.add_child(enemy, true)
spawn_timer.start(randf_range(1.0, 5.0))
核心功能一个是获取一个随机的位置, 一个是生成敌人, 通过Timer控制生成频率, 并增加一些随机生成间隔
通过Main场景传入的ReferenceRect来确定敌人随机生成的范围, 也就是上面Main场景截图中的红色边框范围
注意: 敌人生成应当仅在服务端执行, 其余peer通过MultiplayerSpawner同步
敌人的自动跟踪
先将Player场景添加分组"player"
修改Enemy脚本逻辑
var track_target: Vector2
var has_track_target: bool = false
func _ready() -> void:
if is_multiplayer_authority():
area_2d.area_entered.connect(_on_area_entered)
track_timer.timeout.connect(_on_track_timer_timeout)
_update_track_target()
else:
track_timer.process_mode = Node.PROCESS_MODE_DISABLED
func _process(_delta: float) -> void:
if is_multiplayer_authority():
if has_track_target:
velocity = global_position.direction_to(track_target) * 40
move_and_slide()
func _update_track_target() -> void:
var players := get_tree().get_nodes_in_group("player")
var min_squared_distance: float
var track_player: Node2D = null
for player in players:
if track_player == null:
track_player = player
min_squared_distance = track_player.global_position.distance_squared_to(global_position)
var squared_distance = player.global_position.distance_squared_to(global_position)
if squared_distance < min_squared_distance:
min_squared_distance = squared_distance
track_player = player
if track_player != null:
track_target = track_player.global_position
has_track_target = true
else:
has_track_target = false
增加一个track_timer, 每0.2秒更新一次跟踪目标
跟踪目标的选择是通过group分组取得所有Player实例, 并找到距离最近的作为追踪目标
在process中朝着跟踪目标移动
调整MultiplayerSynchronizer中的global_position同步为"OnChange"
再次提醒: 多人游戏中, 关键的逻辑处理都在服务端, 其余peer仅同步显示
一些想法
看着自己的学习练习的小项目一点点完善, 还是挺有成就感的, 坚持下来总会逐步成长, 多做一些这样的练习, 后面开发自己的独立游戏也不会太难
现在AI发展迅猛, 小龙虾OpenClaw的消息铺天盖地, 到处都是AI颠覆世界的消息, 我也时常被这些消息淹没, 甚至弄得心烦, 总有一种FOMO情绪, 但我知道, 现在的很多消息其实是资本叙事和媒体夸大, 还有很多卖课机构
我们在日常生活中可以尝试用AI辅助开发, 辅助工作, 提高效率, 但是一旦发现自己过于追求新技术新消息, 投入的时间和精力完全超出预期, 甚至影响自己正常安排的时候, 就应该警惕起来, 想想自己最初的目标, AI是提效工具, 项目的把控和兜底必须得自己来, 不能落后时代, 但也不要过分追新