14、游戏手感与视觉打磨

第14章 游戏手感与视觉打磨

游戏手感(Juice)要素总览

复制代码
┌─────────────────────────────────────────────────────────┐
│                    游戏手感要素                          │
├──────────┬──────────┬──────────┬──────────┬──────────────┤
│  视觉反馈  │  音效反馈  │  触觉反馈  │  动画节奏  │  屏幕效果    │
├──────────┼──────────┼──────────┼──────────┼──────────────┤
│ 受击闪白  │ 随机音高  │ 手柄震动  │ 预备动作  │ 屏幕震动      │
│ 粒子特效  │ 打击音效  │ 顿帧     │ 跟随动作  │ 相机 Zoom     │
│ 击退动画  │ 环境音效  │          │ 弹性动画  │ 屏幕闪烁      │
│ 伤害数字  │          │          │          │ 暗角变化      │
└──────────┴──────────┴──────────┴──────────┴──────────────┘

打击感综合方案(执行顺序):

  攻击命中 → 顿帧(0.05s) → 屏幕震动 → 相机Zoom脉冲
       ↓
  受击闪白 → 伤害数字弹出 → 击退 → 粒子特效 → 音效

14.1 缓动曲线

gdscript 复制代码
# ease() 内置函数
var value := ease(progress, 0.5)  # ease_out
# 参数:
# < 0: 先慢后快(ease_in)
# = 0: 线性
# > 0: 先快后慢(ease_out)
# 2.0: 二次方 ease_out
# -2.0: 二次方 ease_in

# Tween 的 Trans 类型
# TRANS_LINEAR    线性
# TRANS_SINE      正弦
# TRANS_QUINT     五次方
# TRANS_QUART     四次方
# TRANS_QUAD      二次方
# TRANS_EXPO      指数
# TRANS_ELASTIC   弹性
# TRANS_CUBIC     三次方
# TRANS_CIRC      圆形
# TRANS_BOUNCE    弹跳
# TRANS_BACK      回弹

# 使用
var tween := create_tween()
tween.tween_property(self, "position", target_pos, 0.5) \
    .set_trans(Tween.TRANS_QUAD) \
    .set_ease(Tween.EASE_OUT)

14.2 屏幕过渡效果

gdscript 复制代码
# 淡入淡出
extends CanvasLayer

@onready var color_rect: ColorRect = $ColorRect

func fade_in(duration: float = 0.5) -> void:
    color_rect.color.a = 1.0
    var tween := create_tween()
    tween.tween_property(color_rect, "color:a", 0.0, duration)

func fade_out(duration: float = 0.5) -> void:
    color_rect.color.a = 0.0
    var tween := create_tween()
    tween.tween_property(color_rect, "color:a", 1.0, duration)
    await tween.finished

# 场景切换带过渡
func change_scene_with_fade(scene_path: String) -> void:
    await fade_out(0.5)
    get_tree().change_scene_to_file(scene_path)
    await get_tree().process_frame
    fade_in(0.5)

14.3 屏幕闪烁

gdscript 复制代码
extends CanvasLayer

@onready var flash_rect: ColorRect = $FlashRect

func flash(color: Color, duration: float = 0.1) -> void:
    flash_rect.color = color
    flash_rect.color.a = 0.7
    var tween := create_tween()
    tween.tween_property(flash_rect, "color:a", 0.0, duration)

# 受伤红闪
func damage_flash() -> void:
    flash(Color(1, 0, 0, 1), 0.15)

# 治疗绿闪
func heal_flash() -> void:
    flash(Color(0, 1, 0, 1), 0.2)

14.4 全屏后处理(Shader)

gdscript 复制代码
# 暗角效果
# 场景结构:
#   CanvasLayer
#     ColorRect (全屏,Mouse Filter=Ignore)
#       Material: ShaderMaterial

# Shader 代码(在 ShaderMaterial 中):
# shader_type canvas_item;
# uniform float vignette_strength : hint_range(0, 1) = 0.5;
# uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
# 
# void fragment() {
#     vec4 color = texture(screen_texture, UV);
#     float dist = distance(UV, vec2(0.5));
#     float vignette = smoothstep(0.4, 0.8, dist);
#     color.rgb *= 1.0 - vignette * vignette_strength;
#     COLOR = color;
# }

# 代码控制强度
func set_vignette_strength(strength: float) -> void:
    $VignetteRect.material.set_shader_parameter("vignette_strength", strength)

# 受伤时增强暗角
func _on_hurt() -> void:
    var tween := create_tween()
    tween.tween_method(set_vignette_strength, 0.8, 0.3, 0.5)

14.5 音效与视觉节奏同步

gdscript 复制代码
# 打击感综合方案
func on_attack_hit() -> void:
    # 1. 顿帧
    hitstop(0.05)
    
    # 2. 屏幕震动
    $Camera2D.shake(8.0, 0.15)
    
    # 3. 相机 zoom 脉冲
    $Camera2D.zoom_pulse(1.1, 0.1)
    
    # 4. 屏幕白闪
    $ScreenEffects.damage_flash()
    
    # 5. 受击闪白
    target.flash_white(0.1)
    
    # 6. 伤害数字
    show_damage_popup(damage, is_critical)
    
    # 7. 击退
    target.apply_knockback(direction, force)
    
    # 8. 音效(随机音高变化)
    $HitSound.pitch_scale = randf_range(0.8, 1.2)
    $HitSound.play()
    
    # 9. 粒子特效
    spawn_hit_particles(hit_position)

14.6 环境反馈

gdscript 复制代码
# 风粒子
extends GPUParticles2D

@export var wind_direction: Vector2 = Vector2(1, 0)
@export var wind_strength: float = 100.0

func _process(delta: float) -> void:
    var material: ParticleProcessMaterial = process_material
    material.direction = Vector3(wind_direction.x, wind_direction.y, 0)
    material.initial_velocity_min = wind_strength
    material.initial_velocity_max = wind_strength * 1.5

# 物体摆动(受风影响)
extends Sprite2D

@export var sway_amount: float = 3.0
@export var sway_speed: float = 2.0

func _process(delta: float) -> void:
    rotation_degrees = sin(Time.get_ticks_msec() * 0.001 * sway_speed) * sway_amount

实操练习

练习:打击感测试场景

gdscript 复制代码
# 创建一个测试场景,包含:
# 1. 一个可以攻击的假人
# 2. 完整的打击反馈(顿帧+震动+闪白+粒子+音效)
# 3. 伤害数字弹出
# 4. 连击系统
# 5. 屏幕后处理效果
相关推荐
狂人开飞机7 小时前
15、音频系统
游戏引擎·godot
狂人开飞机8 小时前
16、粒子线条与视觉特效
游戏引擎·godot
心前阳光19 小时前
Unity发布PC软件图标不能改变
unity·游戏引擎
笨鸟先飞的橘猫1 天前
系统设计第十七天决策卡
学习·游戏
一孤程1 天前
游戏测试专题第二篇:游戏功能测试与用例设计实战
功能测试·游戏·测试·测试覆盖率
科技泡泡堂1 天前
想玩《黎明行者之血》?2026年这4款适合玩3A的游戏本值得一看
游戏
an86950011 天前
unity如何在visual studio中打断点debug
unity·游戏引擎·visual studio
梦想平凡1 天前
百游棋牌源代码开发搭建教程(二):PostgreSQL安装、业务表创建与版本化迁移
数据库·游戏·postgresql
xcLeigh1 天前
Unity基础:使用Transform控制物体移动——Translate与position详解
unity·游戏引擎