1
This commit is contained in:
@@ -207,9 +207,10 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
public float lockPathMax = 0.9f;
|
||||
|
||||
|
||||
// ⭐ 双倍开火:toggle_Shuang 开启后计时 shuangDuration 秒自动关闭(DaoJiShi 驱动),
|
||||
// child0 的 Image(Filled 360°) 做环形倒计时显示(GetShuangFillImage 懒获取)
|
||||
float shuangDuration = 15f;
|
||||
// ⭐ 双倍开火:玩家手动开关的持久模式(同三射/锁定),不自动关闭、不消耗道具。
|
||||
// child0 的 Image(Filled 360°) 做环形转圈展示(GetShuangFillImage 懒获取):
|
||||
// 开启后环耗尽一圈从头继续转(循环动画),关闭时停转清环。
|
||||
float shuangDuration = 15f; // 环转一圈的时长(纯视觉,不控制功能开关)
|
||||
public float currShuangTime = 0f;
|
||||
private Image _shuangFillImage;
|
||||
public Toggle toggle_BaoZou;
|
||||
@@ -729,6 +730,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeZhanShen, SyncGameData_ChangeZhanShen);
|
||||
// ⭐ 表情包帧同步(biaoQing):其他玩家发送表情,对应座位显示
|
||||
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_BiaoQing, SyncGameData_BiaoQing);
|
||||
// ⭐ 加金币帧同步(addGold):其他玩家刮刮卡等 HTTP 途径获得金币,对应座位加金币刷新显示
|
||||
EventCenter.Instance.AddEventListener<SyncGameData>(ConstEventString.SyncGameData_AddGold, SyncGameData_AddGold);
|
||||
// ⭐ 刮刮卡领取金币:本地座位加金币并帧同步给房间其他玩家(先减防重复订阅)
|
||||
GuaGuaLeGPU.OnScratchGoldAwarded -= OnScratchGoldAwarded;
|
||||
GuaGuaLeGPU.OnScratchGoldAwarded += OnScratchGoldAwarded;
|
||||
// SyncGameData_FreezeFish 已废弃:冰冻改由服务端 FishFrozen 事件统一触发
|
||||
EventCenter.Instance.AddEventListener(ConstEventString.FishFrozen, OnFishFrozen);
|
||||
// ⭐ 召唤卡召唤通知:某玩家使用召唤卡,服务端已创建召唤鱼(仅播提示,实际鱼由 OnFishSpawn 创建)
|
||||
@@ -964,6 +970,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeWing, SyncGameData_ChangeWing);
|
||||
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_ChangeZhanShen, SyncGameData_ChangeZhanShen);
|
||||
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_BiaoQing, SyncGameData_BiaoQing);
|
||||
// ⭐ 加金币帧同步 + 刮刮卡领取金币订阅随面板销毁解除
|
||||
EventCenter.Instance.RemoveEventListener<SyncGameData>(ConstEventString.SyncGameData_AddGold, SyncGameData_AddGold);
|
||||
GuaGuaLeGPU.OnScratchGoldAwarded -= OnScratchGoldAwarded;
|
||||
// SyncGameData_FreezeFish 已废弃:冰冻改由服务端 FishFrozen 事件统一触发
|
||||
EventCenter.Instance.RemoveEventListener(ConstEventString.FishFrozen, OnFishFrozen);
|
||||
EventCenter.Instance.RemoveEventListener<SummonCardFishNoticeData>(ConstEventString.SummonCardFishNotice, OnSummonCardFishNotice);
|
||||
@@ -1094,7 +1103,8 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
GameManager.Instance.user.id,
|
||||
"40003", 0);
|
||||
});
|
||||
// ⭐ 双倍开火开关:开启(重新)计时 15 秒 + 满环开始倒计时,关闭停表清环。
|
||||
// ⭐ 双倍开火开关:持久模式(玩家手动开关,不自动关闭)。
|
||||
// 开启=满环开始循环转圈(DaoJiShi 驱动,转完一圈从头继续),关闭=停转清环。
|
||||
// isDouble 不需要同步开关状态:每次开火随 SyncFire 的 twoRTruect 传给服务端,
|
||||
// 三处开火入口(TryFire/HandleAutoFire/OnFlyTurretUpwardFire)都实时读 isOn
|
||||
if (toggle_Shuang != null)
|
||||
@@ -1793,6 +1803,57 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
ShowBiaoQing(dispPos, data.biaoQingType, data.spineIndex, data.content);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 刮刮卡领取金币回调(GuaGuaLeGPU.OnScratchGoldAwarded):
|
||||
/// 服务端已把金币加到大厅数据(游戏内房间不推),给本地座位显示层加金币,
|
||||
/// 并帧同步(addGold)广播给房间其他玩家。
|
||||
/// </summary>
|
||||
public void OnScratchGoldAwarded(long gold)
|
||||
{
|
||||
if (currSitData == null || gold <= 0) return;
|
||||
AddGoldToSeat(currSitData, gold, "GuaGuaKa");
|
||||
|
||||
// ⭐ 帧同步给房间其他玩家(自己回广播在 SyncGameData_AddGold 里跳过,防止双重加)
|
||||
SyncGameData sgd = new SyncGameData
|
||||
{
|
||||
sitPos = SeatMirror.ToServer(currSitData.posID),
|
||||
frameType = FrameDataType.addGold,
|
||||
time = BeijingTimeManager.Instance.CurrentTimestampMs,
|
||||
frameData = new FrameData_AddGold { gold = gold, source = "GuaGuaKa" }
|
||||
};
|
||||
WebSocketSendList.SyncGameData(sgd);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 收到其他玩家的加金币帧(addGold):给对应座位显示层加金币并刷新金币文本。
|
||||
/// 座位镜像:服务端座位先转显示座位再找场景座位;本地座位跳过(发送时已加)。
|
||||
/// </summary>
|
||||
public void SyncGameData_AddGold(SyncGameData sync)
|
||||
{
|
||||
var data = FrameDataParser.Parse<FrameData_AddGold>(sync.frameData);
|
||||
if (data == null || data.gold <= 0) return;
|
||||
|
||||
// ⭐ 座位镜像:服务端座位转显示座位
|
||||
int dispPos = SeatMirror.ToDisplay(sync.sitPos);
|
||||
if (currSitData == null || dispPos == currSitData.posID) return; // 本地座位已在 OnScratchGoldAwarded 加过
|
||||
|
||||
var sit = list_Sits.Find(s => s != null && s.posID == dispPos);
|
||||
if (sit == null) return;
|
||||
AddGoldToSeat(sit, data.gold, string.IsNullOrEmpty(data.source) ? "addGold" : data.source);
|
||||
}
|
||||
|
||||
/// <summary>给座位显示层加金币并刷新金币文本 + 记录金币流水(服务端已加钱,这里纯表现层,与杀鱼 onScoreAdd 同惯例)</summary>
|
||||
private void AddGoldToSeat(SitPosData sit, long gold, string source)
|
||||
{
|
||||
long oldGold = sit.goldNum;
|
||||
sit.goldNum += gold;
|
||||
if (sit.tMP_GoldNum != null)
|
||||
sit.tMP_GoldNum.text = sit.goldNum.ToString();
|
||||
// ⭐ 记录金币流水:已加钱(刮刮卡等途径,本地已执行)
|
||||
GameManager.LogGoldFlowAppliedGain(source,
|
||||
$"加金币=+{gold} 座位={sit.posID} 修正前金币={oldGold} 剩余金币={sit.goldNum} 房间={GameManager.Instance.gameData?.currRoomData?.roomId}");
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region 大喇叭/召唤卡(Left道具快捷按钮)
|
||||
@@ -2735,7 +2796,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
}
|
||||
|
||||
// ⭐ 本地金币校验:没钱不切换 Attack 状态,也不广播,避免无效请求
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn))
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn, toggle_Shuang != null && toggle_Shuang.isOn))
|
||||
return;
|
||||
// 按下即进入 Attack:短按→射击,松开后回 Idle
|
||||
currSitData.ChangeState(TurretState.Attack);
|
||||
@@ -3066,23 +3127,21 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
}
|
||||
}
|
||||
|
||||
// ⭐ 双倍开火倒计时:child0 的环形填充图(Image Filled 360°)随时间耗尽,
|
||||
// 15 秒后自动关闭。SetIsOnWithoutNotify 不触发 onValueChanged(避免重置计时逻辑);
|
||||
// 关闭后三处开火入口读 isOn=false,后续 SyncFire 的 twoRTruect 自动恢复单倍
|
||||
// ⭐ 双倍开火转圈环:纯展示效果,不是倒计时。
|
||||
// 双倍是玩家手动开关的持久模式(同三射/锁定),倒计时结束不许关闭功能——
|
||||
// 环耗尽一圈后从头继续转(循环动画),只有玩家手动关 toggle 才停转清环
|
||||
// (关闭走 onValueChanged:currShuangTime=0、fill=0)。
|
||||
// 功能开关由玩家手动控制;三处开火入口实时读 isOn,SyncFire 的 gold 随之×2/×1。
|
||||
if (toggle_Shuang != null && toggle_Shuang.isOn && shuangDuration > 0)
|
||||
{
|
||||
var fill = GetShuangFillImage();
|
||||
if (fill != null)
|
||||
fill.fillAmount = Mathf.Clamp01(currShuangTime / shuangDuration);
|
||||
|
||||
currShuangTime -= Time.deltaTime;
|
||||
if (currShuangTime <= 0f)
|
||||
currShuangTime = shuangDuration; // 转完一圈从头继续转
|
||||
|
||||
if (currShuangTime <= 0)
|
||||
{
|
||||
toggle_Shuang.SetIsOnWithoutNotify(false);
|
||||
currShuangTime = 0f;
|
||||
if (fill != null) fill.fillAmount = 0f;
|
||||
}
|
||||
if (fill != null)
|
||||
fill.fillAmount = Mathf.Clamp01(currShuangTime / shuangDuration);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3113,7 +3172,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
|
||||
// ⭐ 本地金币校验:没钱直接返回,不发送开炮请求
|
||||
// clickTime 保持满,金币恢复后立即开火
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn))
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn, toggle_Shuang != null && toggle_Shuang.isOn))
|
||||
return;
|
||||
|
||||
// ⭐ 子弹上限校验(先于扣费和状态切换)
|
||||
@@ -3152,7 +3211,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
{
|
||||
if (currSitData == null || _isLeavingCountdown) return;
|
||||
if (currSitData.isDrillActive) return;
|
||||
if (!HasEnoughGoldToFire(false)) return;
|
||||
if (!HasEnoughGoldToFire(false, toggle_Shuang != null && toggle_Shuang.isOn)) return;
|
||||
if (IsBulletLimitReached(currSitData.user)) return;
|
||||
|
||||
// 0° = 正上方;起飞炮台不支持三连
|
||||
@@ -3326,7 +3385,10 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
return; // 没钱,后续不发
|
||||
|
||||
MonsterContral target = targets.Count > 0 ? targets[Mathf.Min(i, targets.Count - 1)] : null;
|
||||
StartCoroutine(LaserHitRoutine(sit, target, bullitIDs[i]));
|
||||
// ⭐ 该发实际扣费炮倍(服务端权威优先,回退本地计算:双倍×2),
|
||||
// 结算 KillFish 的 paoBei 用 → 双倍激光奖励×2
|
||||
long useConsume = gold > 0 ? gold : sit.consumeGoldNum * (isDouble ? 2 : 1);
|
||||
StartCoroutine(LaserHitRoutine(sit, target, bullitIDs[i], useConsume));
|
||||
}
|
||||
|
||||
if (sit.posID == currSitData.posID)
|
||||
@@ -3348,7 +3410,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
/// 激光命中协程:延迟 laserHitDelay 后结算(不开实体子弹)。
|
||||
/// 结算逻辑与 BullitMove.AttackFish 一致:本人发 KillFish、bot 由房主发 BotKillFish、本地播 OnHurt。
|
||||
/// </summary>
|
||||
private System.Collections.IEnumerator LaserHitRoutine(SitPosData sit, MonsterContral target, string bulletId)
|
||||
private System.Collections.IEnumerator LaserHitRoutine(SitPosData sit, MonsterContral target, string bulletId, long fireGold = 0)
|
||||
{
|
||||
if (laserHitDelay > 0f)
|
||||
yield return new WaitForSeconds(laserHitDelay);
|
||||
@@ -3362,10 +3424,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
if (sit.user == GameManager.Instance.user.id)
|
||||
{
|
||||
// 真人玩家击杀:直接发后端
|
||||
// ⭐ paoBei 用该发实际扣费炮倍(双倍=2倍),后端按它结算 → 奖励×2
|
||||
var v2 = GameManager.Instance.gameData.currRoomData;
|
||||
WebSocketSendList.KillFish(v2.roomId, sit.user,
|
||||
target.monsterData.fishTypeConfig.fishNumber, target.guid,
|
||||
(int)sit.consumeGoldNum, bulletId, "63215f0afa3f5b25");
|
||||
(int)(fireGold > 0 ? fireGold : sit.consumeGoldNum), bulletId, "63215f0afa3f5b25");
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(sit.user) && sit.user.StartsWith("bot_"))
|
||||
{
|
||||
@@ -3454,7 +3517,7 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
|
||||
// ⭐ 本地金币校验:没钱直接返回,不切换攻击状态、不发送开炮请求
|
||||
// autoFireTimer 保持满,金币恢复后立即开火
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn))
|
||||
if (!HasEnoughGoldToFire(toggle_Three.isOn, toggle_Shuang != null && toggle_Shuang.isOn))
|
||||
return;
|
||||
|
||||
// ⭐ 子弹上限校验(先于状态切换和扣费)
|
||||
@@ -4426,11 +4489,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
/// 弹出后设 false,仅在金币恢复到够最小炮倍时才重置 true,
|
||||
/// 期间无论弹窗是否关闭、RequestLeaveRoom 是否异步等待,都不会再弹。
|
||||
/// </summary>
|
||||
private bool HasEnoughGoldToFire(bool isSanShe)
|
||||
private bool HasEnoughGoldToFire(bool isSanShe, bool isDouble = false)
|
||||
{
|
||||
if (currSitData == null) return false;
|
||||
int count = isSanShe ? 3 : 1;
|
||||
long need = currSitData.consumeGoldNum * count;
|
||||
// ⭐ 双倍开火每发按 2 倍炮倍扣费(与 SyncFire 的 unitGold 对齐),
|
||||
// 否则金币只够单倍时仍发双倍请求,后端扣费失败/扣成负数
|
||||
long need = currSitData.consumeGoldNum * count * (isDouble ? 2 : 1);
|
||||
if (currSitData.goldNum >= need)
|
||||
{
|
||||
// 金币够当前炮倍:可正常开火,重置弹窗标志
|
||||
@@ -4516,6 +4581,9 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
bullet.userid = sit.user;
|
||||
bullet.playerID = sit.user;
|
||||
bullet.bulletID = id;
|
||||
// ⭐ 记录该发实际扣费炮倍(服务端权威金额优先,回退本地计算:双倍×2),
|
||||
// 击中时 BullitMove.AttackFish 用它作 KillFish 的 paoBei → 双倍炮奖励×2
|
||||
bullet.fireGold = fireConsumeGold > 0 ? fireConsumeGold : sit.consumeGoldNum * (isDouble ? 2 : 1);
|
||||
|
||||
if (isLock)
|
||||
{
|
||||
@@ -4590,6 +4658,11 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
var roomdata = GameManager.Instance.gameData.currRoomData;
|
||||
var user = GameManager.Instance.user;
|
||||
|
||||
// ⭐ 双倍开火:一发子弹按 2 倍炮倍扣费。FireCannon 后端总扣费 = gold(单价) × count(发数),
|
||||
// 双倍体现在单价×2(子弹仍是一颗),与本地 ConsumeGold(isDouble?2:1) 对齐,
|
||||
// 否则后端只扣单倍,本地显示被后端权威数据覆盖 → 消耗没有×2
|
||||
long unitGold = currSitData.consumeGoldNum * (isDouble ? 2 : 1);
|
||||
|
||||
// 三射 = 3 发,否则 = 1 发
|
||||
int count = isSanShe ? 3 : 1;
|
||||
|
||||
@@ -4597,13 +4670,13 @@ public class GameMainPanel_FishBase : GameMainPanel_Base
|
||||
long timespan = BeijingTimeManager.Instance.CurrentTimestampMs; // 毫秒
|
||||
long timestamp = timespan / 1000; // 秒级
|
||||
string sign = WebSocketSendList.MakeFireCannonSign(
|
||||
roomdata.roomId, user.id, currSitData.consumeGoldNum, count, timestamp, "63215f0afa3f5b25");
|
||||
roomdata.roomId, user.id, unitGold, count, timestamp, "63215f0afa3f5b25");
|
||||
|
||||
// FireCannon:roomId, userId, gold, count, timestamp, sign, extra
|
||||
WebSocketSendList.FireCannon(
|
||||
roomdata.roomId,
|
||||
user.id,
|
||||
currSitData.consumeGoldNum,
|
||||
unitGold,
|
||||
count,
|
||||
timestamp,
|
||||
sign,
|
||||
|
||||
Reference in New Issue
Block a user