Game/GameSfx.cs
using System;
/// <summary>
/// 游戏音效(M4):**全部 2D 平面声(.sound UI 标志,用户定稿——不随距离衰减)**。
/// 吃食物这类高频音只播"本机耳朵"自己的(IsMine 判定),死亡/爆裂全场都播(低频事件)。
/// 资产未就绪(导入中/客户端未下载)时静默跳过,绝不让音效调用打断游戏循环。
/// (曾名 GameSound:创建时与编辑器写入竞态把编译缓存搞花,换名重建——内容与旧版一致)
/// </summary>
public static class GameSfx
{
const string SfxEat = "sounds/cr_eat.sound";
const string SfxEatBall = "sounds/cr_eat_ball.sound";
const string SfxPop = "sounds/cr_pop.sound";
const string SfxSplit = "sounds/cr_split.sound";
const string SfxEject = "sounds/cr_eject.sound";
const string SfxRespawn = "sounds/cr_respawn.sound";
static int _eatCount; // 本局吃食物计数(每 10 分播一次音,重生清零)
/// <summary> 该 owner 的事件是否归"本机耳朵"管:host 比对 SteamId;客户端比对
/// 本机球的 OwnerSteamId(双开合成 ID 与 Game.SteamId 对不上,只能走球上同步值) </summary>
public static bool IsMine( long ownerSteamId )
{
if ( NetworkManager.IsAuthority )
return ownerSteamId == Game.SteamId.Value;
var b = CircleroyaleGame.Current?.LocalBall;
return b.IsValid() && b.OwnerSteamId == ownerSteamId;
}
/// <summary> 吃食物:每累计 10 分播一次(不再每颗都播,避免机关枪)。重生时 ResetEatCount 清零 </summary>
public static void EatFood( Vector3 pos )
{
if ( ++_eatCount % 10 != 0 ) return;
Play( SfxEat, pos );
}
/// <summary> 重生时清零吃食物计数(下一条命重新从 0 计) </summary>
public static void ResetEatCount() => _eatCount = 0;
public static void EatBall( Vector3 pos ) => Play( SfxEatBall, pos );
public static void Pop( Vector3 pos ) => Play( SfxPop, pos );
public static void Split( Vector3 pos ) => Play( SfxSplit, pos );
public static void Eject( Vector3 pos ) => Play( SfxEject, pos );
public static void Respawn( Vector3 pos ) => Play( SfxRespawn, pos );
static void Play( string path, Vector3 pos )
{
try
{
Sound.Play( path, pos );
}
catch
{
// 资源未就绪:静默跳过(不刷日志)
}
}
}