10、相机系统

第10章 相机系统

10.1 Camera2D 基础

gdscript 复制代码
extends Camera2D

@onready var target: Node2D = get_parent()  # 跟随目标

func _ready() -> void:
    # 设置为当前相机
    make_current()

# 方式1:使用内置平滑(推荐,简单)
# 在检查器中设置:
#   Position Smoothing → Enabled ✅
#   Position Smoothing → Speed = 8.0
# 然后在 _physics_process 中直接设置 global_position 即可
# Camera2D 会自动平滑插值

func _physics_process(delta: float) -> void:
    # 跟随目标(配合 Position Smoothing 使用)
    global_position = target.global_position

# 方式2:手动平滑(更灵活,可以添加前瞻/偏移)
# func _physics_process(delta: float) -> void:
#     var target_pos := target.global_position
#     global_position = global_position.lerp(target_pos, 10.0 * delta)

10.2 相机边界限制

gdscript 复制代码
# 限制相机不超出关卡边界
func set_camera_limits(level_rect: Rect2) -> void:
    limit_left = int(level_rect.position.x)
    limit_top = int(level_rect.position.y)
    limit_right = int(level_rect.end.x)
    limit_bottom = int(level_rect.end.y)
    
    # 也可以从 TileMap 获取边界
    # var used_rect := tilemap.get_used_rect()
    # var cell_size := tilemap.tile_set.tile_size
    # limit_left = int(used_rect.position.x * cell_size.x)
    # ...

10.3 屏幕震动

gdscript 复制代码
extends Camera2D

@export var shake_decay: float = 5.0

var shake_intensity: float = 0.0
var shake_offset: Vector2 = Vector2.ZERO

func shake(intensity: float, duration: float = 0.2) -> void:
    shake_intensity = intensity
    var tween := create_tween()
    tween.tween_property(self, "shake_intensity", 0.0, duration)

func _process(delta: float) -> void:
    if shake_intensity > 0:
        shake_offset = Vector2(
            randf_range(-1, 1) * shake_intensity,
            randf_range(-1, 1) * shake_intensity
        )
    else:
        shake_offset = Vector2.ZERO
    
    offset = shake_offset

# 使用
# 受伤时震动
$Camera2D.shake(10.0, 0.3)
# 爆炸时强烈震动
$Camera2D.shake(20.0, 0.5)

10.4 相机 Zoom 脉冲

gdscript 复制代码
# 打击感增强:攻击时短暂放大再恢复
func zoom_pulse(intensity: float = 1.1, duration: float = 0.1) -> void:
    var tween := create_tween()
    tween.tween_property(self, "zoom", Vector2.ONE * intensity, duration * 0.3)
    tween.tween_property(self, "zoom", Vector2.ONE, duration * 0.7)

# 使用
func on_attack_hit() -> void:
    $Camera2D.zoom_pulse(1.15, 0.15)
    $Camera2D.shake(8.0, 0.1)

10.5 相机区域切换

gdscript 复制代码
# 进入房间时切换相机边界
extends Area2D

@export var camera_limits: Rect2

func _ready() -> void:
    body_entered.connect(_on_body_entered)

func _on_body_entered(body: Node2D) -> void:
    if body.is_in_group("player"):
        var camera: Camera2D = body.get_node("Camera2D")
        var tween := create_tween()
        tween.tween_property(camera, "limit_left", int(camera_limits.position.x), 0.5)
        tween.parallel().tween_property(camera, "limit_top", int(camera_limits.position.y), 0.5)
        tween.parallel().tween_property(camera, "limit_right", int(camera_limits.end.x), 0.5)
        tween.parallel().tween_property(camera, "limit_bottom", int(camera_limits.end.y), 0.5)

10.6 小地图(SubViewport 方案)

gdscript 复制代码
# 场景结构:
# SubViewportContainer
#   SubViewport
#     MiniMapCamera (Camera2D) - zoom 很大,俯瞰全局
#     MiniMapPlayerDot (ColorRect) - 玩家位置标记
#     MiniMapEnemyDot (ColorRect) - 敌人位置标记

extends SubViewportContainer

@onready var camera: Camera2D = $SubViewport/MiniMapCamera
@onready var player_dot: Control = $SubViewport/MiniMapPlayerDot

func _process(delta: float) -> void:
    # 相机跟随玩家
    camera.global_position = player.global_position
    
    # 更新玩家点位置
    player_dot.position = Vector2(50, 50)  # 小地图中心

实操练习

练习:智能相机

gdscript 复制代码
extends Camera2D

@export var target: Node2D
@export var look_ahead: float = 50.0  # 前瞻距离
@export var vertical_offset: float = -30.0  # 垂直偏移

func _process(delta: float) -> void:
    var target_pos := target.global_position
    
    # 前瞻:根据移动方向偏移
    if target is CharacterBody2D:
        var vel: Vector2 = target.velocity
        target_pos.x += vel.x * look_ahead / 300.0
    
    # 垂直偏移
    target_pos.y += vertical_offset
    
    # 平滑跟随
    global_position = global_position.lerp(target_pos, 10.0 * delta)
相关推荐
郝学胜-神的一滴6 小时前
游戏设计:原型与开发 08:我们到底在为谁做游戏
程序人生·游戏·游戏引擎·游戏开发·游戏策划
Wanda12141 天前
机器人与机电一体化3D数字孪生机器-Day5
人工智能·unity·游戏引擎·数字孪生
淡海水2 天前
05-02-源码-Boehm GC标记阶段
算法·unity·c#·游戏引擎·gc
淡海水3 天前
05-03-源码-Boehm GC分配与碎片管理
开发语言·算法·unity·c#·游戏引擎·gc
xiaogai_gai6 天前
BOM 物料清单同步实战:金蝶云星空 → 四化智造 MES 修改场景深度拆解
unity·游戏引擎
/**书香门第*/7 天前
Cocos Creator 打螺丝游戏的实现
游戏引擎·cocos2d·螺丝·打螺丝
mxwin8 天前
Unity Shader 光线追踪原理与实战案例
unity·游戏引擎
xcLeigh9 天前
Unity基础:Instantiate实例化——在运行时动态创建游戏物体
游戏·unity·游戏引擎·教程·instantiate
辻弋20115 天前
五年前的旅行视频糊成马赛克?Video2X用Real-ESRGAN逐帧重建细节,但只支持Windows、集显用户建议直接放弃
服务器·数据库·windows·游戏引擎·电脑
狂野小白兔16 天前
AI游戏制作04——Codex 搭配 Godot MCP 全流程教程
人工智能·游戏·godot