9. 音效与特效
2026/4/14大约 5 分钟
9. 咸鱼之王——音效与特效
9.1 放置游戏的音效特点
放置游戏的音效和RPG不同——不需要紧张的战斗音乐,而是需要轻松、舒适的背景音乐,配合清脆的音效反馈。
| 特点 | 说明 |
|---|---|
| 背景音乐轻松 | 玩家可能长时间挂在后台,音乐不能太吵 |
| 音效简洁短促 | 收金币、升级等操作需要即时反馈 |
| 循环播放 | 背景音乐无缝循环,避免突兀的切换 |
| 音量可调 | 玩家可以随时关闭或调低音量 |
9.2 音频管理器
C
using Godot;
/// <summary>
/// 放置游戏音频管理器
/// </summary>
public partial class IdleAudioManager : Node
{
private AudioStreamPlayer _bgmPlayer;
private AudioStreamPlayer _sfxPlayer;
[Export] public float BgmVolume { get; set; } = -12.0f;
[Export] public float SfxVolume { get; set; } = -8.0f;
public override void _Ready()
{
_bgmPlayer = new AudioStreamPlayer();
_bgmPlayer.Name = "BgmPlayer";
AddChild(_bgmPlayer);
_sfxPlayer = new AudioStreamPlayer();
_sfxPlayer.Name = "SfxPlayer";
AddChild(_sfxPlayer);
// 播放默认背景音乐(轻松愉快的旋律)
PlayBgm("res://assets/audio/music/idle_main.ogg");
}
/// <summary>
/// 播放背景音乐(无缝循环)
/// </summary>
public void PlayBgm(string path)
{
var stream = GD.Load<AudioStream>(path);
if (stream == null) return;
_bgmPlayer.Stream = stream;
_bgmPlayer.VolumeDb = BgmVolume;
_bgmPlayer.Play();
}
/// <summary>
/// 播放音效
/// </summary>
public void PlaySfx(string path)
{
var stream = GD.Load<AudioStream>(path);
if (stream == null) return;
_sfxPlayer.Stream = stream;
_sfxPlayer.VolumeDb = SfxVolume;
_sfxPlayer.Play();
}
// ===== 快捷音效方法 =====
public void PlayCoinSound() =>
PlaySfx("res://assets/audio/sfx/coin.ogg");
public void PlayLevelUpSound() =>
PlaySfx("res://assets/audio/sfx/level_up.ogg");
public void PlayDrawSound() =>
PlaySfx("res://assets/audio/sfx/draw.ogg");
public void PlayLegendaryDrawSound() =>
PlaySfx("res://assets/audio/sfx/legendary_draw.ogg");
public void PlayEnhanceSuccessSound() =>
PlaySfx("res://assets/audio/sfx/enhance_success.ogg");
public void PlayEnhanceFailSound() =>
PlaySfx("res://assets/audio/sfx/enhance_fail.ogg");
public void PlayTapSound() =>
PlaySfx("res://assets/audio/sfx/tap.ogg");
}GDScript
extends Node
## 放置游戏音频管理器
var _bgm_player: AudioStreamPlayer
var _sfx_player: AudioStreamPlayer
@export var bgm_volume: float = -12.0
@export var sfx_volume: float = -8.0
func _ready() -> void:
_bgm_player = AudioStreamPlayer.new()
_bgm_player.name = "BgmPlayer"
add_child(_bgm_player)
_sfx_player = AudioStreamPlayer.new()
_sfx_player.name = "SfxPlayer"
add_child(_sfx_player)
play_bgm("res://assets/audio/music/idle_main.ogg")
## 播放背景音乐
func play_bgm(path: String) -> void:
var stream = load(path) as AudioStream
if stream == null:
return
_bgm_player.stream = stream
_bgm_player.volume_db = bgm_volume
_bgm_player.play()
## 播放音效
func play_sfx(path: String) -> void:
var stream = load(path) as AudioStream
if stream == null:
return
_sfx_player.stream = stream
_sfx_player.volume_db = sfx_volume
_sfx_player.play()
# ===== 快捷音效方法 =====
func play_coin_sound() -> void:
play_sfx("res://assets/audio/sfx/coin.ogg")
func play_level_up_sound() -> void:
play_sfx("res://assets/audio/sfx/level_up.ogg")
func play_draw_sound() -> void:
play_sfx("res://assets/audio/sfx/draw.ogg")
func play_legendary_draw_sound() -> void:
play_sfx("res://assets/audio/sfx/legendary_draw.ogg")
func play_enhance_success_sound() -> void:
play_sfx("res://assets/audio/sfx/enhance_success.ogg")
func play_enhance_fail_sound() -> void:
play_sfx("res://assets/audio/sfx/enhance_fail.ogg")
func play_tap_sound() -> void:
play_sfx("res://assets/audio/sfx/tap.ogg")9.3 音效清单
| 音效 | 触发时机 | 风格 |
|---|---|---|
| 金币叮咚 | 每秒收入、领取奖励 | 清脆的金属声 |
| 升级音效 | 英雄升级成功 | 欢快的上升音 |
| 抽卡音效 | 普通抽卡结果 | 翻牌的"唰"声 |
| 传说抽卡音效 | 抽到传说英雄 | 金光闪闪的特殊音效 |
| 强化成功 | 装备强化成功 | 铁锤敲打的"叮"声 |
| 强化失败 | 装备强化失败 | 低沉的"嗡"声 |
| 点击音效 | 按下任何按钮 | 轻轻的"哒"声 |
| Boss警告 | 进入Boss关 | 紧张的鼓声 |
9.4 升级特效
当英雄升级时,显示一个华丽的特效来增强成就感:
C
using Godot;
/// <summary>
/// 升级特效——英雄升级时的视觉效果
/// </summary>
public partial class LevelUpEffect : Control
{
private Label _levelLabel;
private GpuParticles2D _particles;
public override void _Ready()
{
_levelLabel = GetNode<Label>("LevelLabel");
_particles = GetNode<GpuParticles2D>("Particles");
Visible = false;
}
/// <summary>
/// 播放升级特效
/// </summary>
public void Play(string heroName, int newLevel)
{
_levelLabel.Text = $"{heroName}\nLV.{newLevel}!";
Visible = true;
// 播放粒子特效
_particles.Emitting = true;
// 放大动画
var tween = CreateTween();
tween.TweenProperty(this, "scale",
new Vector2(1.2f, 1.2f), 0.2f);
tween.TweenProperty(this, "scale",
Vector2.One, 0.2f);
tween.TweenProperty(this, "modulate:a", 0f, 0.5f);
// 1秒后自动隐藏
var timer = GetTree().CreateTimer(1.0);
timer.Timeout += () =>
{
Visible = false;
_particles.Emitting = false;
Scale = Vector2.One;
Modulate = Colors.White;
};
}
}GDScript
extends Control
## 升级特效——英雄升级时的视觉效果
@onready var _level_label: Label = $LevelLabel
@onready var _particles: GPUParticles2D = $Particles
func _ready() -> void:
visible = false
## 播放升级特效
func play(hero_name: String, new_level: int) -> void:
_level_label.text = "%s\nLV.%d!" % [hero_name, new_level]
visible = true
_particles.emitting = true
# 放大动画
var tween = create_tween()
tween.tween_property(self, "scale", Vector2(1.2, 1.2), 0.2)
tween.tween_property(self, "scale", Vector2.ONE, 0.2)
tween.tween_property(self, "modulate:a", 0.0, 0.5)
# 1秒后自动隐藏
await get_tree().create_timer(1.0).timeout
visible = false
_particles.emitting = false
scale = Vector2.ONE
modulate = Color.WHITE9.5 抽卡特效
抽到不同稀有度的英雄时,显示不同的特效:
| 稀有度 | 特效 | 持续时间 |
|---|---|---|
| 普通 | 简单的白色闪光 | 0.5秒 |
| 稀有 | 绿色光芒 | 1秒 |
| 史诗 | 蓝色光芒+粒子 | 1.5秒 |
| 传说 | 金色全屏光效+大量粒子+特殊音效 | 2秒 |
C
/// <summary>
/// 抽卡特效——根据稀有度显示不同效果
/// </summary>
public partial class DrawEffect : Control
{
private ColorRect _overlay;
private GpuParticles2D _particles;
private Label _rarityLabel;
public override void _Ready()
{
_overlay = GetNode<ColorRect>("Overlay");
_particles = GetNode<GpuParticles2D>("Particles");
_rarityLabel = GetNode<Label>("RarityLabel");
Visible = false;
}
/// <summary>
/// 播放抽卡特效
/// </summary>
public async void Play(HeroRarity rarity, string heroName)
{
Visible = true;
// 根据稀有度设置颜色和文字
Color color = rarity switch
{
HeroRarity.Common => Colors.White,
HeroRarity.Rare => new Color(0.2f, 1.0f, 0.2f),
HeroRarity.Epic => new Color(0.3f, 0.3f, 1.0f),
HeroRarity.Legend => new Color(1.0f, 0.6f, 0.0f),
_ => Colors.White
};
string rarityText = rarity switch
{
HeroRarity.Common => "普通",
HeroRarity.Rare => "稀有!",
HeroRarity.Epic => "史诗!!",
HeroRarity.Legend => "传说!!!",
_ => ""
};
_overlay.Color = new Color(color, 0.3f);
_rarityLabel.Text = $"{rarityText}\n{heroName}";
_rarityLabel.Modulate = color;
// 传说英雄:全屏光效
if (rarity == HeroRarity.Legend)
{
var tween = CreateTween();
tween.TweenProperty(_overlay, "color:a", 0.6f, 0.3f);
tween.TweenProperty(_overlay, "color:a", 0f, 0.5f);
_particles.Emitting = true;
}
// 等待一段时间后隐藏
float duration = rarity == HeroRarity.Legend ? 2.5f : 1.5f;
await ToSignal(GetTree().CreateTimer(duration), "timeout");
Visible = false;
_particles.Emitting = false;
}
}GDScript
extends Control
## 抽卡特效——根据稀有度显示不同效果
@onready var _overlay: ColorRect = $Overlay
@onready var _particles: GPUParticles2D = $Particles
@onready var _rarity_label: Label = $RarityLabel
func _ready() -> void:
visible = false
## 播放抽卡特效
func play(rarity: int, hero_name: String) -> void:
visible = true
var color: Color
var rarity_text: String
match rarity:
HeroRarity.COMMON:
color = Color.WHITE
rarity_text = "普通"
HeroRarity.RARE:
color = Color(0.2, 1.0, 0.2)
rarity_text = "稀有!"
HeroRarity.EPIC:
color = Color(0.3, 0.3, 1.0)
rarity_text = "史诗!!"
HeroRarity.LEGEND:
color = Color(1.0, 0.6, 0.0)
rarity_text = "传说!!!"
_:
color = Color.WHITE
rarity_text = ""
_overlay.color = Color(color.r, color.g, color.b, 0.3)
_rarity_label.text = "%s\n%s" % [rarity_text, hero_name]
_rarity_label.modulate = color
# 传说英雄:全屏光效
if rarity == HeroRarity.LEGEND:
var tween = create_tween()
tween.tween_property(_overlay, "color:a", 0.6, 0.3)
tween.tween_property(_overlay, "color:a", 0.0, 0.5)
_particles.emitting = true
var duration: float = 2.5 if rarity == HeroRarity.LEGEND else 1.5
await get_tree().create_timer(duration).timeout
visible = false
_particles.emitting = false9.6 伤害飘字
战斗中的伤害飘字需要更加醒目——数字从大到小,颜色根据伤害类型变化。
| 伤害类型 | 颜色 | 字号 |
|---|---|---|
| 普通攻击 | 白色 | 正常 |
| 暴击 | 黄色 | 放大 |
| 技能伤害 | 蓝色 | 放大 |
| 治疗量 | 绿色 | 正常 |
9.7 本章小结
| 知识点 | 说明 |
|---|---|
| 轻松BGM | 循环播放舒适的音乐,不会让玩家烦躁 |
| 即时音效 | 金币、升级、抽卡等操作的即时反馈 |
| 升级特效 | 粒子+放大+淡出的组合动画 |
| 抽卡特效 | 根据稀有度显示不同颜色和强度的特效 |
| 伤害飘字 | 不同类型的伤害用不同颜色和大小区分 |
最后一章我们将进行数值平衡和发布准备。
