存档点

This commit is contained in:
2026-08-22 17:23:07 +08:00
parent 9ac5dbc317
commit 6697c1e696
42 changed files with 936 additions and 1189 deletions
@@ -51,4 +51,21 @@ public class LayeredPool
}
return null;
}
/// <summary>
/// 随机分包 + 随机爆金币但不死鱼:
/// 发 randomDieFish 帧(guids 为空),所有客户端只播屏幕随机位置的金币特效,场上鱼不死亡。
/// </summary>
public List<RedPacketRecord> BossGlodCoinRandromNotFish(Vector3 v3Point, int min=3, int max=8, int killerSitPos = -1)
{
if (game.HasNext())
{
int currentSubCount = Random.Range(min, max + 1);
List<RedPacketRecord> result = game.GrabFullCycle(currentSubCount);
CreateFishManager.Instance.SyncGameData_SendRandomCoinFX(result, v3Point, killerSitPos);
return result;
}
return null;
}
}
+75 -391
View File
@@ -798,6 +798,79 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: -20, y: 0}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1001 &230530519
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1179516840748032749, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_Name
value: 6002_Timeline Variant
objectReference: {fileID: 0}
- target: {fileID: 1179516840748032749, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalRotation.w
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalRotation.y
value: 1
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 180
objectReference: {fileID: 0}
- target: {fileID: 4996427902980830852, guid: 517a34ff6be7fbd4893b6e9a70ba4685,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: -0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 517a34ff6be7fbd4893b6e9a70ba4685, type: 3}
--- !u!1 &260232825
GameObject:
m_ObjectHideFlags: 0
@@ -6398,7 +6471,7 @@ MonoBehaviour:
spawnList: []
isCreateFish: 0
isFrozen: 0
debugSpawnFishNumber: 13040
debugSpawnFishNumber: 11027
fishList_All: []
fishList_Small: []
fishList_Boss: []
@@ -6561,99 +6634,6 @@ RectTransform:
m_AnchoredPosition: {x: 0, y: 0}
m_SizeDelta: {x: 899, y: 554}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1001 &841547336076769388
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 2112818773112888307, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_Name
value: 7001
objectReference: {fileID: 0}
- target: {fileID: 2112818773112888307, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalScale.x
value: 4
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalScale.y
value: 4
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalScale.z
value: 4
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 3091632925678412136, guid: 6fe331de34f8a1c459d3d8888b1bcd01,
type: 3}
propertyPath: m_ConstrainProportionsScale
value: 1
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 6fe331de34f8a1c459d3d8888b1bcd01, type: 3}
--- !u!1 &1060248940485052805
GameObject:
m_ObjectHideFlags: 0
@@ -6691,79 +6671,6 @@ RectTransform:
m_AnchoredPosition: {x: -36.025818, y: -85.671844}
m_SizeDelta: {x: 671.0558, y: 367.3435}
m_Pivot: {x: 0.5, y: 0.5}
--- !u!1001 &1328183416056466136
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 3531218012915984842, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_Name
value: 7001_Timeline
objectReference: {fileID: 0}
- target: {fileID: 3531218012915984842, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 8822545478285579720, guid: ad0160ec062450746ac31aa7aec0e507,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: -0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ad0160ec062450746ac31aa7aec0e507, type: 3}
--- !u!114 &1465445836008020758
MonoBehaviour:
m_ObjectHideFlags: 0
@@ -6832,84 +6739,6 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1001 &2518911503280687070
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 6379684486006968571, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_Name
value: PW_Prop_IronFist
objectReference: {fileID: 0}
- target: {fileID: 6379684486006968571, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6385227750942468653, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: -0
objectReference: {fileID: 0}
- target: {fileID: 6411523127270236248, guid: 9b8be0fc8702c6546bdb3fce2d1f479f,
type: 3}
propertyPath: m_Mesh
value:
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 9b8be0fc8702c6546bdb3fce2d1f479f, type: 3}
--- !u!224 &2557606984666069063
RectTransform:
m_ObjectHideFlags: 0
@@ -7124,79 +6953,6 @@ MonoBehaviour:
m_FillOrigin: 0
m_UseSpriteMesh: 0
m_PixelsPerUnitMultiplier: 1
--- !u!1001 &4272855452577043047
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalPosition.x
value: 3.2313976
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalPosition.y
value: 1.60395
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalPosition.z
value: -1.430045
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3187087628806128005, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_Name
value: GameObject
objectReference: {fileID: 0}
- target: {fileID: 3363739725897090535, guid: 97aa30e2785dc6b4a8857b2718fedf53,
type: 3}
propertyPath: m_IsActive
value: 0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: 97aa30e2785dc6b4a8857b2718fedf53, type: 3}
--- !u!224 &4559688231163668212
RectTransform:
m_ObjectHideFlags: 0
@@ -7707,74 +7463,6 @@ GameObject:
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!1001 &7937577344510224963
PrefabInstance:
m_ObjectHideFlags: 0
serializedVersion: 2
m_Modification:
serializedVersion: 3
m_TransformParent: {fileID: 0}
m_Modifications:
- target: {fileID: 1093432214310145427, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_Name
value: Z_1596
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalPosition.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalPosition.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalPosition.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalRotation.w
value: 1
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalRotation.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalRotation.y
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalRotation.z
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalEulerAnglesHint.x
value: 0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalEulerAnglesHint.y
value: -0
objectReference: {fileID: 0}
- target: {fileID: 8769189682057519396, guid: ea8300491ad555343ba924c381e23ade,
type: 3}
propertyPath: m_LocalEulerAnglesHint.z
value: -0
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
m_AddedComponents: []
m_SourcePrefab: {fileID: 100100000, guid: ea8300491ad555343ba924c381e23ade, type: 3}
--- !u!222 &7973113366657543629
CanvasRenderer:
m_ObjectHideFlags: 0
@@ -8061,8 +7749,4 @@ SceneRoots:
- {fileID: 1184862095}
- {fileID: 1663842063}
- {fileID: 260232829}
- {fileID: 841547336076769388}
- {fileID: 1328183416056466136}
- {fileID: 2518911503280687070}
- {fileID: 4272855452577043047}
- {fileID: 7937577344510224963}
- {fileID: 230530519}
@@ -15,7 +15,7 @@ public class MonsterControl_BossBase : MonsterContral
{
// ==================== 基础 ====================
public string bossName;
// ==================== 爆奖 ====================
[Header("爆奖")]
public bool isToUI = true; // 爆奖特效是 UI(RectTransform)还是 3D 场景物体
@@ -1472,6 +1472,37 @@ public class CreateFishManager : MonoSingleton<CreateFishManager>
return guids;
}
/// <summary>
/// 发送"随机爆金币不死鱼"帧:guids 为空列表,所有客户端只播屏幕随机位置的金币特效,
/// 场上鱼不死亡(Id_DieListFish_FX 中 guids 为空 → 全部走 SpawnRandomCoinFX)。
/// </summary>
/// <param name="coinNum">红包分包记录(每条对应一个金币特效)</param>
/// <param name="v3Point">爆奖中心(金币特效的基准位置)</param>
/// <param name="killerSitPos">击杀者座位 ID(-1 = 本地座位)</param>
public void SyncGameData_SendRandomCoinFX(List<RedPacketRecord> coinNum, Vector3 v3Point, int killerSitPos = -1)
{
if (coinNum == null || coinNum.Count == 0) return;
int posID = killerSitPos >= 0 ? killerSitPos : currGameType.currSitData.posID;
var sgd = new SyncGameData
{
sitPos = posID,
frameType = FrameDataType.randomDieFish,
time = BeijingTimeManager.Instance.CurrentTimestampMs,
frameData = new FrameData_RandomDieFish
{
x = v3Point.x,
y = v3Point.y,
z = v3Point.z,
guids = new List<string>(), // ⭐ 空 = 不关联场上鱼,金币全走 SpawnRandomCoinFX
coinNum = coinNum,
count = coinNum.Count
}
};
WebSocketSendList.SyncGameData(sgd);
}
/// <summary>
/// 鱼离场
/// </summary>
+1 -1
View File
@@ -3,7 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class DefaultBJEvent : BJEventBase
public class DefaultBJEvent : BJRedPacketEvent
{
//public PlayableDirector playableDirector;
//private void Awake()
+99 -456
View File
@@ -1,82 +1,47 @@
using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;
/// <summary>
/// Boss 爆奖事件基类
/// 完整流程:死亡特效 → (多次 CallBJ 发红包 → 协程模拟金币逐个到达累分)→ EffEnd →
/// DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd → JiaFen → die
///
/// CallBJ 调用 BigPrize 发包后,不立即累加分数,而是启动实例级协程,
/// 按金币飞行动画的节奏(0.5s 飞行 + 0.1s 间隔)逐个累分到 tMP_Score。
/// 每个 BJEventBase 实例独立管理自己的协程,支持多个 Boss 同时爆奖。
/// Boss 爆奖事件基类(骨架)。
/// 只保留所有爆奖形态共用的部分:
/// 1. 参数初始化(金币/座位/炮倍/底分/倍数)与座位归属(isSelf)
/// 2. 结束流程:OnScoreEnd → JiaFen(回加金币)→ ShowBJEndUI(结算面板)→ die
/// 3. 通用工具:GetSeatPosition / ShrinkEffect / RollNumber(数字滚动)
///
/// 爆奖形态与继承层级:
/// 1. 积分型(分红包 n 次加积分)→ BJRedPacketEvent:红包分包、金币逐个累分、分数面板、滚分、飞回座位
/// 2. 倍数型(分 n 次加爆奖倍数)→ 多数直接继承 BJRedPacketEvent(复用结算与分数面板),倍数文本各自管理;
/// FLXJ / GSL 这类 Timeline 累倍数玩法继承 TimelineBeiShuEvent
/// </summary>
public class BJEventBase : MonoBehaviour
{
public BJEndUI bjEndUI;
[Header("结算")]
public BJEndUI bjEndUI; // 爆奖结算面板预制体
public float bjEndUIOffsetY = 150f; // BJEndUI 在座位上方偏移
// ==================== Inspector 字段 ====================
[Header("分数")]
public bool useScorePanel = true; // 是否启用分数面板效果(关闭则跳过创建/滚分/移动)
public TextMeshProUGUI tMP_Score; // 分数显示文本(空则自动从预制体创建)
public GameObject scorePanelPrefab; // 分数版预制体(优先;空则用 Manager 自带 dieFXPrefabAwardTmp)
public int currScore; // 当前显示分数
public int maxScore; // 最终总分
[Header("玩家参数")]
public int posID; // 击杀者座位ID
public int paoBei; // 炮倍
public int fishScore; // 底分
public int bJbeishu; // 爆奖倍数
public int maxScore; // 最终总分
public LayeredPool layeredPool; // 红包分层对象池
[Header("红包")]
public int scoreCount; // 红包分包数量(每次 CallBJ 发几个红包)
[Header("位置")]
public Vector3 startOffset = new Vector3(0, 0, -100); // 爆奖对象初始位置偏移
[Header("玩家")]
public int posID; // 击杀者座位ID
public int paoBei; // 炮倍
public int fishScore; // 底分
public int bJbeishu;
[Header("移动")]
public float showDelay = 3f; // 报完奖后停留时间(让玩家看清爆奖效果)
public float moveDuration = 0.5f; // UI 移动到座位的时间
public Ease moveEase = Ease.OutQuad; // 移动缓动曲线
public Vector3 startOffset = new Vector3(0, 0, -100);
public float bjEndUIOffsetY = 150f; // BJEndUI 在座位上方偏移(useScorePanel=false 时生效)
/// <summary>金币飞行到达面板的模拟时间(秒),应匹配 coinEvent DOMove 时长</summary>
public float coinFlyDuration = 0.5f;
/// <summary>金币之间到达的间隔时间(秒)</summary>
public float coinArrivalInterval = 0.1f;
/// <summary>是否显示加分飘字特效(dieFXPrefabAwardTmp_AddScore);false=只加分不飘字</summary>
public bool showAddScoreFX = true;
// ==================== 回调 ====================
public Action JiaFen; // 加分完成回调(回加到玩家金币)
// ==================== 归属 ====================
public bool isSelf; // 是否是自己打出的爆奖(非自己只播特效不加分)
[Header("手动结束")]
[Tooltip("积分加满后是否自动进入结束界面;关闭后需手动调用 ManualFinishBJ 触发")]
public bool autoFinishOnScoreFull = true;
private bool _isWaitingForManualFinish; // 积分已满,等待手动结束
// ==================== 回调 / 归属 ====================
public Action JiaFen; // 加分完成回调(回加到玩家金币)
public bool isSelf; // 是否是自己打出的爆奖(非自己只播特效不加分)
public object obj; // 服务端下发参数(RoomKillNotice.param)
// ==================== 运行时状态 ====================
public int totalBJCount; // 计划爆奖总次数(由 boss 设置)
public int currBJCount; // 已爆奖次数
public bool isEffEnd; // 特效阶段已结束
public bool isScoreStart; // 加分阶段已开始
public bool isScoreEnd; // 加分阶段已结束
public bool isGoldEffectStart; // 红包特效阶段已开始
public bool isScoreEnd; // 结束流程已触发(OnScoreEnd 防重入)
private SitPosData _targetSit; // 目标座位引用
private Coroutine _scoreCoroutine; // 加分协程
protected GameObject _scoreBoard; // 自动创建的分数版(用于移动)—— protected 供子类清理
protected BJImage _bjImage; // 分数版上的 BJImage 组件(可选,用于切换金币/银币样式)
protected int _activeCoinRoutines; // 正在运行的 CoinArrival 协程数量(protected 供子类兜底检测)
protected SitPosData _targetSit; // 目标座位引用
public object obj;
private Coroutine _rollCoroutine; // 当前数字滚动协程(RollNumber 防重复启动)
// ==================== 初始化 ====================
/// <summary>
@@ -88,15 +53,11 @@ public class BJEventBase : MonoBehaviour
/// <param name="paobei">炮倍</param>
/// <param name="action">最终加分回调(回加到玩家金币)</param>
/// <param name="action1">初始化完成后的附加回调(如设置龙珠值)</param>
public virtual void Init(long goldCount, int posID, long paobei,long fishScore, int beishu,Action<int> action, Action action1 = null)
public virtual void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
{
// ⭐ 重置运行时状态(对象池复用的爆奖对象会残留上次状态,导致 OnScoreEnd 等直接 return)
ResetState();
// ⭐ 从 Inspector 默认值恢复 totalBJCount(原 Start() 逻辑移到这里)
// Start() 只在首次激活时执行一次,对象池复用时不触发,会导致 totalBJCount=0 → 自动结束检测失效
totalBJCount = scoreCount;
JiaFen = () => { action?.Invoke(0); };
maxScore = (int)goldCount;
this.posID = posID;
@@ -104,147 +65,32 @@ public class BJEventBase : MonoBehaviour
paoBei = (int)paobei;
bJbeishu = beishu;
// 自动检测:tMP_Score 为空则按优先级创建分数版
EnsureScoreBoard();
// 初始位置:座位坐标 + 手调偏移
ApplySeatOffset();
// 初始位置:画布中心 + 手调偏移(并缓存座位引用)
ApplySeatOffset();
// 是否是本地玩家自己打的
isSelf = _targetSit != null && _targetSit.user == GameManager.Instance.user.id;
// 根据 isSelf 切换分数样式(自己=金币,他人=银币)
ApplyScoreStyle();
action1?.Invoke();
}
/// <summary>
/// 重置所有运行时状态(对象池复用时调用,避免上次爆奖残留导致下次流程异常)。
/// 同时清理上次可能残留的分数面板。
/// 子类 override 必须调用 base.ResetState()。
/// </summary>
protected virtual void ResetState()
{
// 清理上次残留的分数面板(如果上次流程未正常跑完 OnScoreEnd)
// ⭐ 同时重置 tMP_Score:所有预制体 tMP_Score 都是 {fileID:0}(未在 Inspector 赋值),
// 由 EnsureScoreBoard 从 _scoreBoard 子级动态获取。_scoreBoard 被销毁后
// tMP_Score 变成"假 null"(Unity 已销毁但 C# 引用仍在),EnsureScoreBoard 的
// if (tMP_Score != null) 判断在 Destroy 延迟销毁的同一帧内仍为 true,导致跳过创建新面板。
// 必须显式置 null 让 EnsureScoreBoard 下次重建。
if (_scoreBoard != null)
{
Destroy(_scoreBoard);
_scoreBoard = null;
tMP_Score = null;
}
else if (tMP_Score != null)
{
// 上次 die() → CleanupBeforeDie 已销毁 _scoreBoard,但 tMP_Score 引用残留
// (CleanupBeforeDie 只 Destroy _scoreBoard,不重置 tMP_Score)
tMP_Score = null;
}
// 重置状态标志
isEffEnd = false;
isScoreStart = false;
isScoreEnd = false;
isGoldEffectStart = false;
currScore = 0;
maxScore = 0;
currBJCount = 0;
totalBJCount = 0;
_activeCoinRoutines = 0;
_isWaitingForManualFinish = false;
_scoreCoroutine = null;
_bjImage = null;
_targetSit = null;
obj = null;
// ⭐ 重置红包分层池:对象池复用时旧的 layeredPool 仍持有上次的 maxScore 分包,
// 下次 BigPrize 会用错误的总金额分包,必须置 null 让 BigPrize 按新 maxScore 重建
layeredPool = null;
// 停止所有残留协程
StopAllCoroutines();
}
/// <summary>
/// 自动补充分数版:tMP_Score 为空 → 优先用 scorePanelPrefab → 否则用 Manager 的 dieFXPrefabAwardTmp
/// 父对象挂在 CreateFishManager.Instance.currGameType.subPanelParent 下(随 UI 卸载自动清理)
/// </summary>
protected virtual void EnsureScoreBoard()
{
if (tMP_Score != null) return;
if (!useScorePanel) return;
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null) return;
var parent = CreateFishManager.Instance.currGameType.subPanelParent;
if (parent == null) return;
// 1. 优先用 Inspector 设置的预制体
GameObject prefab = scorePanelPrefab;
// 2. 否则用 Manager 自带的 dieFXPrefabAwardTmp
if (prefab == null)
prefab = CreateFishManager.Instance.dieFXPrefabAwardTmp;
if (prefab == null) return;
var board = Instantiate(prefab, parent);
_scoreBoard = board;
// 优先获取 BJImage 组件(新预制体),用其 tmp_CoinNum 作为分数 TMP
_bjImage = board.GetComponentInChildren<BJImage>();
if (_bjImage != null && _bjImage.tmp_CoinNum != null)
{
tMP_Score = _bjImage.tmp_CoinNum;
}
else
{
// 回退:直接获取 TextMeshProUGUI
var tmp = board.GetComponentInChildren<TextMeshProUGUI>();
if (tmp != null) tMP_Score = tmp;
}
_rollCoroutine = null;
}
/// <summary>
/// 根据 isSelf 切换分数 TMP 的 spriteAsset:
/// 自己击杀 → goldSprite(金币样式)
/// 他人击杀 → silverSprite(银币样式)
/// 需要预制体上挂有 BJImage 组件且对应 sprite 已赋值;否则跳过不影响原有显示。
/// </summary>
protected virtual void ApplyScoreStyle()
{
if (_bjImage == null || tMP_Score == null) return;
var spriteAsset = isSelf ? _bjImage.goldSprite : _bjImage.silverSprite;
if (spriteAsset != null)
tMP_Score.spriteAsset = spriteAsset;
}
// ==================== 特效相关 ====================
/// <summary>死亡特效阶段结束回调(由动画事件/子类调用)</summary>
public virtual void EffEnd()
{
if (isEffEnd) return;
isEffEnd = true;
// 停留 showDelay 秒让玩家看清爆奖效果 → 开始加分滚动
StartCoroutine(DelayThenScore());
}
private IEnumerator DelayThenScore()
{
yield return new WaitForSeconds(showDelay);
StartAddScore(); // → AddScoreRoutine → MoveToSit → OnScoreEnd
}
/// <summary>触发红包特效 + 开始滚分</summary>
public virtual void GoldEffect()
{
isGoldEffectStart = true;
BigPrize();
}
// ==================== 移动到座位 ====================
// ==================== 定位 ====================
/// <summary>
/// 设置爆奖初始位置:RectTransform → UI 画布中间;普通 Transform → 场景原点 (0,0,0)
/// </summary>
@@ -279,240 +125,6 @@ public class BJEventBase : MonoBehaviour
_targetSit = sits[posID];
}
/// <summary>分数版飞回到座位上方,爆奖对象本身不动</summary>
public virtual void MoveToSit()
{
if (!useScorePanel)
{
OnScoreEnd();
return;
}
if (_scoreBoard == null && tMP_Score == null)
{
OnScoreEnd();
return;
}
float y = bjEndUIOffsetY;
if (posID == 2 || posID == 3) y *= -1f;
Vector3 seatPos = GetSeatPosition() + Vector3.up * y;
Transform moveTarget = _scoreBoard != null ? _scoreBoard.transform : tMP_Score.transform.parent;
moveTarget.DOMove(seatPos, moveDuration)
.SetEase(moveEase)
.OnComplete(() =>
{
DOVirtual.DelayedCall(0.5f, () => OnScoreEnd());
});
}
// ==================== 爆奖(发红包) ====================
/// <summary>
/// 执行一次爆奖(发红包)。可在动画事件中多次调用。
/// 每次调用通过 LayeredPool 分发红包数据,然后启动协程按金币飞行节奏逐个累加分数到 tMP_Score。
/// </summary>
/// <param name="minCount">每次最小红包数</param>
/// <param name="maxCount">每次最大红包数</param>
public virtual void CallBJ(int minCount = 10, int maxCount = 15)
{
if (isScoreEnd) return;
var records = BigPrize(minCount, maxCount);
if (records != null && records.Count > 0)
{
// 启动协程:模拟金币逐个飞到面板的节奏
_activeCoinRoutines++;
StartCoroutine(CoinArrivalRoutine(records));
}
else
{
// ⭐ 诊断日志:BigPrize 返回空(maxScore=0 或 layeredPool 已分完)
Debug.LogWarning($"[BJEventBase] CallBJ({currBJCount + 1}/{totalBJCount}) BigPrize 返回空!maxScore={maxScore} scoreCount={scoreCount} currScore={currScore} layeredPool={layeredPool != null}");
}
currBJCount++;
}
/// <summary>
/// 协程:模拟金币飞行到达后逐个累加分数。
/// 等待 coinFlyDuration(匹配 coinEvent DOMove 0.5s),
/// 然后按 coinArrivalInterval 间隔逐个累加。
/// </summary>
private IEnumerator CoinArrivalRoutine(List<RedPacketRecord> records)
{
// 等待金币飞行时间(匹配 DOMove)
yield return new WaitForSeconds(coinFlyDuration);
foreach (var r in records)
{
currScore += (int)r.Amount;
if (tMP_Score != null)
tMP_Score.text = currScore.ToString();
// 加分弹出特效 + 音效
Transform parent = tMP_Score != null ? tMP_Score.transform.parent : transform;
GameObject addScorePrefab = CreateFishManager.Instance.dieFXPrefabAwardTmp_AddScore;
if (showAddScoreFX && addScorePrefab != null)
{
var inst = Instantiate(addScorePrefab, parent.position + Vector3.up * 60, Quaternion.identity, parent);
// 优先用 ScoreNumScrollEvent 组件,按 isSelf 切换金/银币样式
var scrollEvent = inst.GetComponent<ScoreNumScrollEvent>();
if (scrollEvent != null)
{
scrollEvent.SetScoreStyle(isSelf);
scrollEvent.SetScoreText(CoinScript.NumAdd(r.Amount.ToString()));
}
else
{
// 回退:直接取第一个子物体的 TMP
var tmp = inst.transform.GetChild(0).GetComponent<TextMeshProUGUI>();
if (tmp != null)
tmp.text = CoinScript.NumAdd(r.Amount.ToString());
}
}
//AudioManager.Instance.PlayerFX(62022);
// 金币之间间隔
yield return new WaitForSeconds(coinArrivalInterval);
}
_activeCoinRoutines--;
// 所有协程完成 + 轮次满足 → 决定直接结束还是等手动触发
if (_activeCoinRoutines <= 0 && totalBJCount > 0 && currBJCount >= totalBJCount)
{
if (autoFinishOnScoreFull)
{
isGoldEffectStart = false;
EffEnd(); // → DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd → JiaFen → die
}
else
{
_isWaitingForManualFinish = true;
// 等待离场动画结束 → ManualFinishBJ → WaitScoreThenEffEnd → EffEnd
}
}
}
/// <summary>
/// 包一个红包分层
/// </summary>
public virtual List<RedPacketRecord> BigPrize(int min = 10, int max = 15)
{
if (layeredPool == null)
layeredPool = new LayeredPool(maxScore, scoreCount > 0 ? scoreCount : 1);
var v = layeredPool.BossGlodCoinRandrom(
tMP_Score != null ? tMP_Score.transform.position : transform.position,
min, max, posID);
int totalAmount = 0;
if (v != null) foreach (var r in v) totalAmount += (int)r.Amount;
Debug.Log($"[BJEventBase] BigPrize: maxScore={maxScore} scoreCount={scoreCount} records={(v != null ? v.Count : 0)} totalAmount={totalAmount}");
return v;
}
// ==================== 加分滚动 ====================
/// <summary>开始加分滚动动画(子类可 override 自定义)</summary>
public virtual void StartAddScore()
{
if (!useScorePanel)
{
OnScoreEnd();
return;
}
if (_scoreCoroutine != null)
StopCoroutine(_scoreCoroutine);
_scoreCoroutine = StartCoroutine(AddScoreRoutine());
}
/// <summary>默认加分滚动协程</summary>
protected virtual IEnumerator AddScoreRoutine()
{
if (currBJCount > 0)
{
// CallBJ 模式:等所有金币协程跑完
while (_activeCoinRoutines > 0)
yield return null;
// ⭐ 不覆盖 maxScore!保留 Init/子类设置的原始值。
// currScore 是 CoinArrivalRoutine 累加的结果,可能因 LayeredPool 分包舍入
// 或 long→int 截断而与 maxScore 不一致,用 currScore 覆盖会导致最终显示错误。
// 直接显示 maxScore(真实总分)。
if (tMP_Score != null)
tMP_Score.text = maxScore.ToString();
}
else
{
// 非 CallBJ 模式(如雷龙): 滚动加分
while (currScore < maxScore - paoBei)
{
int step = Random.Range(paoBei , paoBei * 2);
currScore += step;
if (tMP_Score != null)
tMP_Score.text = currScore.ToString();
yield return null;
}
if (tMP_Score != null)
tMP_Score.text = maxScore.ToString();
yield return new WaitForSeconds(0.5f);
}
// 加分完毕 → 分数版飞回座位 → 结束后 JiaFen → die
MoveToSit();
}
/// <summary>加分完成——加金币、显示结束UI、删面板、销毁自身</summary>
protected virtual void OnScoreEnd()
{
if (isScoreEnd) return;
isScoreEnd = true;
// 回加金币到玩家
JiaFen?.Invoke();
// BJEndUI:无论是否开启分数面板都显示
if (bjEndUI != null)
{
Vector3 uiPos;
if (useScorePanel)
{
// 开启分数面板:定位在分数面板位置
if (_scoreBoard != null)
uiPos = _scoreBoard.transform.position;
else if (tMP_Score != null)
uiPos = tMP_Score.transform.position;
else
uiPos = transform.position;
}
else
{
float y = bjEndUIOffsetY;
if (posID == 2 || posID == 3) y *= -1f;
uiPos = GetSeatPosition() + Vector3.up * y;
}
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, CreateFishManager.Instance.bjEffectRoot);
endUI.Init(bJbeishu, maxScore, isSelf);
}
// 删除分数面板(同步重置引用,避免 Destroy 延迟导致 CleanupBeforeDie 跳过清理)
if (_scoreBoard != null)
{
Destroy(_scoreBoard);
_scoreBoard = null;
tMP_Score = null;
_bjImage = null;
}
// 销毁爆奖对象自身
die();
}
/// <summary>获取座位坐标</summary>
public Vector3 GetSeatPosition()
{
@@ -536,31 +148,75 @@ public class BJEventBase : MonoBehaviour
return transform.position;
}
// ==================== 手动结束(非自动模式) ====================
/// <summary>
/// 手动结束爆奖。由离场动画结束帧事件调用。
/// 等待所有积分协程完成后再触发 EffEnd → 后续回收/加分流程。
/// </summary>
public void ManualFinishBJ()
// ==================== 结束流程 ====================
/// <summary>加分完成——回加金币、显示结束UI、销毁自身。子类可 override 扩展(需调用 base)。</summary>
protected virtual void OnScoreEnd()
{
foreach (Transform routine in transform)
{
routine.gameObject.SetActive(false);
}
if (!_isWaitingForManualFinish) return;
_isWaitingForManualFinish = false;
if (isScoreEnd) return;
isScoreEnd = true;
StartCoroutine(WaitScoreThenEffEnd());
// 回加金币到玩家
JiaFen?.Invoke();
// BJEndUI:无论是否开启分数面板都显示
ShowBJEndUI();
// 销毁爆奖对象自身
die();
}
/// <summary>等待积分全部到账后再进入结束流程(避免边加分边回收)</summary>
private IEnumerator WaitScoreThenEffEnd()
/// <summary>创建爆奖结算面板(统一入口:所有子类不要各自 Instantiate bjEndUI)</summary>
protected void ShowBJEndUI()
{
while (_activeCoinRoutines > 0)
yield return null;
if (bjEndUI == null) return;
isGoldEffectStart = false;
EffEnd();
var uiPos = GetBJEndUIPosition();
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, CreateFishManager.Instance.bjEffectRoot);
endUI.Init(bJbeishu, maxScore, isSelf);
}
/// <summary>BJEndUI 的生成位置:默认座位上方(2/3 号座位翻转到下方)。子类可 override。</summary>
protected virtual Vector3 GetBJEndUIPosition()
{
float y = bjEndUIOffsetY;
if (posID == 2 || posID == 3) y *= -1f;
return GetSeatPosition() + Vector3.up * y;
}
// ==================== 通用数字滚动 ====================
/// <summary>
/// 数字滚动:从 from 每帧插值到 to,通过 onValue 回调当前值(供倍数滚动/分数滚动复用)。
/// 自动停止上一次未完成的滚动,防止动画叠加;duration<=0 或 to<=from 时直接落值。
/// </summary>
protected void RollNumber(Action<int> onValue, int from, int to, float duration, Action onDone = null)
{
if (_rollCoroutine != null)
StopCoroutine(_rollCoroutine);
_rollCoroutine = StartCoroutine(RollNumberRoutine(onValue, from, to, duration, onDone));
}
private IEnumerator RollNumberRoutine(Action<int> onValue, int from, int to, float duration, Action onDone)
{
if (duration <= 0f || to <= from)
{
onValue?.Invoke(to);
onDone?.Invoke();
_rollCoroutine = null;
yield break;
}
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
onValue?.Invoke(Mathf.RoundToInt(Mathf.Lerp(from, to, t)));
yield return null;
}
onValue?.Invoke(to);
onDone?.Invoke();
_rollCoroutine = null;
}
// ==================== 销毁 ====================
@@ -570,27 +226,14 @@ public class BJEventBase : MonoBehaviour
transform.DOScale(Vector3.zero, 0.5f);
}
/// <summary>
/// 清理分数面板并停止协程(子类 die() 回收/销毁前必须调用)。
/// ⭐ 防止 _scoreBoard 泄漏:EnsureScoreBoard 在 subPanelParent 下 Instantiate 的面板
/// 是独立物体,不会随 Event 一起回收。
/// </summary>
/// <summary>停止协程并清理派生资源(子类 override 必须调用 base)。</summary>
protected virtual void CleanupBeforeDie()
{
// 停止所有协程(防止 SetActive(false) 后协程残留)
StopAllCoroutines();
// 清理分数面板
if (_scoreBoard != null)
{
Destroy(_scoreBoard);
_scoreBoard = null;
// ⭐ 同步清除 tMP_Score 引用(它指向 _scoreBoard 的子级,销毁后变成假 null)
tMP_Score = null;
_bjImage = null;
}
}
/// <summary>销毁自身 GameObject(先清理分数面板)</summary>
/// <summary>销毁自身 GameObject(先清理派生资源)</summary>
public virtual void die()
{
CleanupBeforeDie();
@@ -0,0 +1,478 @@
using DG.Tweening;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;
/// <summary>
/// 爆奖红包的金币表现模式
/// </summary>
public enum BigPrizeFishMode
{
/// <summary>死鱼:随机选场上鱼死亡,在鱼位置掉金币(原 BossGlodCoinRandrom 行为)</summary>
KillFish = 0,
/// <summary>不死鱼:只分包发红包,无金币特效</summary>
NoFish = 1,
/// <summary>随机爆金币不死鱼:屏幕随机位置爆金币特效,场上鱼不死亡</summary>
CoinNoFish = 2,
}
/// <summary>
/// 积分型爆奖事件(分红包 n 次加积分)。
/// 完整流程:死亡特效 → (多次 CallBJ 发红包 → 协程模拟金币逐个到达累分)→ EffEnd →
/// DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd(基类:JiaFen + BJEndUI + die)
///
/// CallBJ 调用 BigPrize 发包后,不立即累加分数,而是启动实例级协程,
/// 按金币飞行动画的节奏(coinFlyDuration 飞行 + coinArrivalInterval 间隔)逐个累分到 tMP_Score。
/// 每个 BJRedPacketEvent 实例独立管理自己的协程,支持多个 Boss 同时爆奖。
///
/// 子类职责:只决定"何时调 CallBJ、调几次"(动画事件/Timeline/协程触发),其余流程全部复用本类。
/// </summary>
public class BJRedPacketEvent : BJEventBase
{
[Header("分数")]
public bool useScorePanel = true; // 是否启用分数面板效果(关闭则跳过创建/滚分/移动)
public TextMeshProUGUI tMP_Score; // 分数显示文本(空则自动从预制体创建)
public GameObject scorePanelPrefab; // 分数版预制体(优先;空则用 Manager 自带 dieFXPrefabAwardTmp)
public int currScore; // 当前显示分数
public LayeredPool layeredPool; // 红包分层对象池
[Header("红包")]
public int scoreCount; // 红包分包数量(每次 CallBJ 发几个红包)
[Tooltip("爆奖红包的金币表现:死鱼=随机选场上鱼死亡并在鱼位置掉金币;不死鱼=只分包无金币特效;随机爆金币不死鱼=屏幕随机位置爆金币,场上鱼不死")]
public BigPrizeFishMode bigPrizeFishMode = BigPrizeFishMode.KillFish;
[Header("移动")]
public float showDelay = 3f; // 报完奖后停留时间(让玩家看清爆奖效果)
public float moveDuration = 0.5f; // UI 移动到座位的时间
public Ease moveEase = Ease.OutQuad; // 移动缓动曲线
/// <summary>金币飞行到达面板的模拟时间(秒),应匹配 coinEvent DOMove 时长</summary>
public float coinFlyDuration = 0.5f;
/// <summary>金币之间到达的间隔时间(秒)</summary>
public float coinArrivalInterval = 0.1f;
/// <summary>是否显示加分飘字特效(dieFXPrefabAwardTmp_AddScore);false=只加分不飘字</summary>
public bool showAddScoreFX = true;
[Header("手动结束")]
[Tooltip("积分加满后是否自动进入结束界面;关闭后需手动调用 ManualFinishBJ 触发")]
public bool autoFinishOnScoreFull = true;
private bool _isWaitingForManualFinish; // 积分已满,等待手动结束
// ==================== 运行时状态 ====================
public int totalBJCount; // 计划爆奖总次数(由 Init 从 scoreCount 恢复)
public int currBJCount; // 已爆奖次数
public bool isEffEnd; // 特效阶段已结束
public bool isScoreStart; // 加分阶段已开始
public bool isGoldEffectStart; // 红包特效阶段已开始
private Coroutine _scoreCoroutine; // 加分协程
protected GameObject _scoreBoard; // 自动创建的分数版(用于移动)—— protected 供子类清理
protected BJImage _bjImage; // 分数版上的 BJImage 组件(可选,用于切换金币/银币样式)
protected int _activeCoinRoutines; // 正在运行的 CoinArrival 协程数量(protected 供子类兜底检测)
// ==================== 初始化 ====================
/// <summary>积分型初始化:基类参数 + 恢复红包总次数 + 创建分数面板 + 金银币样式</summary>
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
{
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
// ⭐ 从 Inspector 默认值恢复 totalBJCount(原 Start() 逻辑移到这里):
// Start() 只在首次激活时执行一次,对象池复用时不触发,会导致 totalBJCount=0 → 自动结束检测失效
totalBJCount = scoreCount;
// 自动检测:tMP_Score 为空则按优先级创建分数版
EnsureScoreBoard();
// 根据 isSelf 切换分数样式(自己=金币,他人=银币)
ApplyScoreStyle();
}
/// <summary>
/// 重置积分型运行时状态(分数面板、红包池、轮次计数等)。
/// </summary>
protected override void ResetState()
{
base.ResetState();
// 清理上次残留的分数面板(如果上次流程未正常跑完 OnScoreEnd)
// ⭐ 同时重置 tMP_Score:所有预制体 tMP_Score 都是 {fileID:0}(未在 Inspector 赋值),
// 由 EnsureScoreBoard 从 _scoreBoard 子级动态获取。_scoreBoard 被销毁后
// tMP_Score 变成"假 null"(Unity 已销毁但 C# 引用仍在),EnsureScoreBoard 的
// if (tMP_Score != null) 判断在 Destroy 延迟销毁的同一帧内仍为 true,导致跳过创建新面板。
// 必须显式置 null 让 EnsureScoreBoard 下次重建。
if (_scoreBoard != null)
{
Destroy(_scoreBoard);
_scoreBoard = null;
tMP_Score = null;
}
else if (tMP_Score != null)
{
// 上次 die() → CleanupBeforeDie 已销毁 _scoreBoard,但 tMP_Score 引用残留
tMP_Score = null;
}
// 重置状态标志
isEffEnd = false;
isScoreStart = false;
isGoldEffectStart = false;
currScore = 0;
currBJCount = 0;
totalBJCount = 0;
_activeCoinRoutines = 0;
_isWaitingForManualFinish = false;
_scoreCoroutine = null;
_bjImage = null;
// ⭐ 重置红包分层池:对象池复用时旧的 layeredPool 仍持有上次的 maxScore 分包,
// 下次 BigPrize 会用错误的总金额分包,必须置 null 让 BigPrize 按新 maxScore 重建
layeredPool = null;
}
/// <summary>
/// 自动补充分数版:tMP_Score 为空 → 优先用 scorePanelPrefab → 否则用 Manager 的 dieFXPrefabAwardTmp
/// 父对象挂在 CreateFishManager.Instance.currGameType.subPanelParent 下(随 UI 卸载自动清理)
/// </summary>
protected virtual void EnsureScoreBoard()
{
if (tMP_Score != null) return;
if (!useScorePanel) return;
if (CreateFishManager.Instance == null || CreateFishManager.Instance.currGameType == null) return;
var parent = CreateFishManager.Instance.currGameType.subPanelParent;
if (parent == null) return;
// 1. 优先用 Inspector 设置的预制体
GameObject prefab = scorePanelPrefab;
// 2. 否则用 Manager 自带的 dieFXPrefabAwardTmp
if (prefab == null)
prefab = CreateFishManager.Instance.dieFXPrefabAwardTmp;
if (prefab == null) return;
var board = Instantiate(prefab, parent);
_scoreBoard = board;
// 优先获取 BJImage 组件(新预制体),用其 tmp_CoinNum 作为分数 TMP
_bjImage = board.GetComponentInChildren<BJImage>();
if (_bjImage != null && _bjImage.tmp_CoinNum != null)
{
tMP_Score = _bjImage.tmp_CoinNum;
}
else
{
// 回退:直接获取 TextMeshProUGUI
var tmp = board.GetComponentInChildren<TextMeshProUGUI>();
if (tmp != null) tMP_Score = tmp;
}
}
/// <summary>
/// 根据 isSelf 切换分数 TMP 的 spriteAsset:
/// 自己击杀 → goldSprite(金币样式)
/// 他人击杀 → silverSprite(银币样式)
/// 需要预制体上挂有 BJImage 组件且对应 sprite 已赋值;否则跳过不影响原有显示。
/// </summary>
protected virtual void ApplyScoreStyle()
{
if (_bjImage == null || tMP_Score == null) return;
var spriteAsset = isSelf ? _bjImage.goldSprite : _bjImage.silverSprite;
if (spriteAsset != null)
tMP_Score.spriteAsset = spriteAsset;
}
// ==================== 特效相关 ====================
/// <summary>死亡特效阶段结束回调(由动画事件/子类调用)</summary>
public virtual void EffEnd()
{
if (isEffEnd) return;
isEffEnd = true;
// 停留 showDelay 秒让玩家看清爆奖效果 → 开始加分滚动
StartCoroutine(DelayThenScore());
}
private IEnumerator DelayThenScore()
{
yield return new WaitForSeconds(showDelay);
StartAddScore(); // → AddScoreRoutine → MoveToSit → OnScoreEnd
}
/// <summary>触发红包特效 + 开始滚分</summary>
public virtual void GoldEffect()
{
isGoldEffectStart = true;
BigPrize();
}
// ==================== 移动到座位 ====================
/// <summary>分数版飞回到座位上方,爆奖对象本身不动</summary>
public virtual void MoveToSit()
{
if (!useScorePanel)
{
OnScoreEnd();
return;
}
if (_scoreBoard == null && tMP_Score == null)
{
OnScoreEnd();
return;
}
float y = bjEndUIOffsetY;
if (posID == 2 || posID == 3) y *= -1f;
Vector3 seatPos = GetSeatPosition() + Vector3.up * y;
Transform moveTarget = _scoreBoard != null ? _scoreBoard.transform : tMP_Score.transform.parent;
moveTarget.DOMove(seatPos, moveDuration)
.SetEase(moveEase)
.OnComplete(() =>
{
DOVirtual.DelayedCall(0.5f, () => OnScoreEnd());
});
}
// ==================== 爆奖(发红包) ====================
/// <summary>
/// 执行一次爆奖(发红包)。可在动画事件中多次调用。
/// 每次调用通过 LayeredPool 分发红包数据,然后启动协程按金币飞行节奏逐个累加分数到 tMP_Score。
/// </summary>
/// <param name="minCount">每次最小红包数</param>
/// <param name="maxCount">每次最大红包数</param>
public virtual void CallBJ(int minCount = 10, int maxCount = 15)
{
if (isScoreEnd) return;
var records = BigPrize(minCount, maxCount);
if (records != null && records.Count > 0)
{
// 启动协程:模拟金币逐个飞到面板的节奏
_activeCoinRoutines++;
StartCoroutine(CoinArrivalRoutine(records));
}
else
{
// ⭐ 诊断日志:BigPrize 返回空(maxScore=0 或 layeredPool 已分完)
Debug.LogWarning($"[BJRedPacketEvent] CallBJ({currBJCount + 1}/{totalBJCount}) BigPrize 返回空!maxScore={maxScore} scoreCount={scoreCount} currScore={currScore} layeredPool={layeredPool != null}");
}
currBJCount++;
}
/// <summary>
/// 协程:模拟金币飞行到达后逐个累加分数。
/// 等待 coinFlyDuration(匹配 coinEvent DOMove 0.5s),
/// 然后按 coinArrivalInterval 间隔逐个累加。
/// </summary>
private IEnumerator CoinArrivalRoutine(List<RedPacketRecord> records)
{
// 等待金币飞行时间(匹配 DOMove)
yield return new WaitForSeconds(coinFlyDuration);
foreach (var r in records)
{
currScore += (int)r.Amount;
if (tMP_Score != null)
tMP_Score.text = currScore.ToString();
// 加分弹出特效 + 音效
Transform parent = tMP_Score != null ? tMP_Score.transform.parent : transform;
GameObject addScorePrefab = CreateFishManager.Instance.dieFXPrefabAwardTmp_AddScore;
if (showAddScoreFX && addScorePrefab != null)
{
var inst = Instantiate(addScorePrefab, parent.position + Vector3.up * 60, Quaternion.identity, parent);
// 优先用 ScoreNumScrollEvent 组件,按 isSelf 切换金/银币样式
var scrollEvent = inst.GetComponent<ScoreNumScrollEvent>();
if (scrollEvent != null)
{
scrollEvent.SetScoreStyle(isSelf);
scrollEvent.SetScoreText(CoinScript.NumAdd(r.Amount.ToString()));
}
else
{
// 回退:直接取第一个子物体的 TMP
var tmp = inst.transform.GetChild(0).GetComponent<TextMeshProUGUI>();
if (tmp != null)
tmp.text = CoinScript.NumAdd(r.Amount.ToString());
}
}
//AudioManager.Instance.PlayerFX(62022);
// 金币之间间隔
yield return new WaitForSeconds(coinArrivalInterval);
}
_activeCoinRoutines--;
// 所有协程完成 + 轮次满足 → 决定直接结束还是等手动触发
if (_activeCoinRoutines <= 0 && totalBJCount > 0 && currBJCount >= totalBJCount)
{
if (autoFinishOnScoreFull)
{
isGoldEffectStart = false;
EffEnd(); // → DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd → JiaFen → die
}
else
{
_isWaitingForManualFinish = true;
// 等待离场动画结束 → ManualFinishBJ → WaitScoreThenEffEnd → EffEnd
}
}
}
/// <summary>
/// 包一个红包分层。由 bigPrizeFishMode 决定金币表现:
/// KillFish → BossGlodCoinRandrom:随机选场上鱼死亡,在鱼位置掉金币(默认)
/// NoFish → BossGlodCoinNotFish:只分包发红包,无金币特效
/// CoinNoFish → BossGlodCoinRandromNotFish:屏幕随机位置爆金币特效,场上鱼不死亡
/// </summary>
public virtual List<RedPacketRecord> BigPrize(int min = 10, int max = 15)
{
if (layeredPool == null)
layeredPool = new LayeredPool(maxScore, scoreCount > 0 ? scoreCount : 1);
List<RedPacketRecord> v;
Vector3 point = tMP_Score != null ? tMP_Score.transform.position : transform.position;
switch (bigPrizeFishMode)
{
case BigPrizeFishMode.NoFish:
v = layeredPool.BossGlodCoinNotFish(Random.Range(min, max + 1));
break;
case BigPrizeFishMode.CoinNoFish:
v = layeredPool.BossGlodCoinRandromNotFish(point, min, max, posID);
break;
default:
v = layeredPool.BossGlodCoinRandrom(point, min, max, posID);
break;
}
int totalAmount = 0;
if (v != null) foreach (var r in v) totalAmount += (int)r.Amount;
Debug.Log($"[BJRedPacketEvent] BigPrize: mode={bigPrizeFishMode} maxScore={maxScore} scoreCount={scoreCount} records={(v != null ? v.Count : 0)} totalAmount={totalAmount}");
return v;
}
// ==================== 加分滚动 ====================
/// <summary>开始加分滚动动画(子类可 override 自定义)</summary>
public virtual void StartAddScore()
{
if (!useScorePanel)
{
OnScoreEnd();
return;
}
if (_scoreCoroutine != null)
StopCoroutine(_scoreCoroutine);
_scoreCoroutine = StartCoroutine(AddScoreRoutine());
}
/// <summary>默认加分滚动协程</summary>
protected virtual IEnumerator AddScoreRoutine()
{
if (currBJCount > 0)
{
// CallBJ 模式:等所有金币协程跑完
while (_activeCoinRoutines > 0)
yield return null;
// ⭐ 不覆盖 maxScore!保留 Init/子类设置的原始值。
// currScore 是 CoinArrivalRoutine 累加的结果,可能因 LayeredPool 分包舍入
// 或 long→int 截断而与 maxScore 不一致,用 currScore 覆盖会导致最终显示错误。
// 直接显示 maxScore(真实总分)。
if (tMP_Score != null)
tMP_Score.text = maxScore.ToString();
}
else
{
// 非 CallBJ 模式(如雷龙): 滚动加分
while (currScore < maxScore - paoBei)
{
int step = Random.Range(paoBei , paoBei * 2);
currScore += step;
if (tMP_Score != null)
tMP_Score.text = currScore.ToString();
yield return null;
}
if (tMP_Score != null)
tMP_Score.text = maxScore.ToString();
yield return new WaitForSeconds(0.5f);
}
// 加分完毕 → 分数版飞回座位 → 结束后 JiaFen → die
MoveToSit();
}
// ==================== 手动结束(非自动模式) ====================
/// <summary>
/// 手动结束爆奖。由离场动画结束帧事件调用。
/// 等待所有积分协程完成后再触发 EffEnd → 后续回收/加分流程。
/// </summary>
public void ManualFinishBJ()
{
foreach (Transform routine in transform)
{
routine.gameObject.SetActive(false);
}
if (!_isWaitingForManualFinish) return;
_isWaitingForManualFinish = false;
StartCoroutine(WaitScoreThenEffEnd());
}
/// <summary>等待积分全部到账后再进入结束流程(避免边加分边回收)</summary>
private IEnumerator WaitScoreThenEffEnd()
{
while (_activeCoinRoutines > 0)
yield return null;
isGoldEffectStart = false;
EffEnd();
}
// ==================== 结算定位 ====================
/// <summary>开启分数面板时 BJEndUI 定位在分数面板位置;否则走基类座位定位</summary>
protected override Vector3 GetBJEndUIPosition()
{
if (useScorePanel)
{
if (_scoreBoard != null)
return _scoreBoard.transform.position;
if (tMP_Score != null)
return tMP_Score.transform.position;
return transform.position;
}
return base.GetBJEndUIPosition();
}
// ==================== 清理 ====================
/// <summary>
/// 停止协程并销毁分数面板。
/// ⭐ 防止 _scoreBoard 泄漏:EnsureScoreBoard 在 subPanelParent 下 Instantiate 的面板
/// 是独立物体,不会随 Event 一起回收。
/// </summary>
protected override void CleanupBeforeDie()
{
// 停止所有协程(防止 SetActive(false) 后协程残留)
base.CleanupBeforeDie();
// 清理分数面板
if (_scoreBoard != null)
{
Destroy(_scoreBoard);
_scoreBoard = null;
// ⭐ 同步清除 tMP_Score 引用(它指向 _scoreBoard 的子级,销毁后变成假 null)
tMP_Score = null;
_bjImage = null;
}
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 163499c0aa205f54da2b9f64caa0f3a5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DLYDieEvent : BJEventBase
public class DLYDieEvent : BJRedPacketEvent
{
private void Awake()
{
+18 -125
View File
@@ -1,137 +1,30 @@
using DG.Tweening;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using Random = UnityEngine.Random;
public class FLXJEvent : BJEventBase
/// <summary>
/// FLXJ 倍数型爆奖:累计倍数带数字滚动 + 缩放动画,其余流程同 TimelineBeiShuEvent。
/// </summary>
public class FLXJEvent : TimelineBeiShuEvent
{
public LeiLongkillObj flxjKill;
public TextMeshProUGUI beishu;
public int beishunum;
public TextMeshProUGUI chengshu;
public TextMeshProUGUI xiaoGuo_Effect;
[Header("倍数滚动")]
[Tooltip("倍数从当前值滚到累计值所需时间(秒)")]
public float beiShuRollDuration = 0.5f;
public int currCount = 0;
public int count;
public PlayableDirector director; // 控制 Timeline
public List<GameObject> gameObjects;
public int count4; // 如果重复4次 从指定位置开始播放的帧数 timeline
public int count5; // 如果重复5次 从指定位置开始播放的帧数 timeline
public int count6; // 如果重复6次 从指定位置开始播放的帧数 timeline
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
/// <summary>累计倍数滚动显示:从当前值滚到 beishunum,带放大→缩小动画</summary>
public override void SetBeiShu()
{
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
flxjKill = JsonConvert.DeserializeObject<LeiLongkillObj>(obj.ToString());
count = flxjKill.res.Count;
}
int prev = 0;
int.TryParse(beishu.text, out prev);
public void SetChengshu()
{
chengshu.text = fishScore.ToString();
}
/// <summary>触发爆奖效果面板:累加倍数、随机激活效果面板(按 currCount 取 index)</summary>
public void SetxiaoGuo_Effect()
{
int index = currCount;
int addbeishu = flxjKill.res[index].score;
beishunum += addbeishu;
xiaoGuo_Effect.text = addbeishu.ToString();
// 随机激活一个效果面板
int temp = Random.Range(0, gameObjects.Count);
foreach (var item in gameObjects)
{
if (item.activeSelf)
item.SetActive(false);
}
gameObjects[temp].SetActive(true);
currCount++;
}
/// <summary>Timeline 快播:currCount>=3 时跳一次到 4/5/6 对应帧位置</summary>
public void PlayFastTimeline()
{
if (count <= 3) return;
if (director == null) return;
if (currCount < 3) return; // 没走完 3 轮不跳
if (_hasJumped) return; // 已经跳过不再跳
_hasJumped = true;
int jumpFrame = count switch
{
4 => count4,
5 => count5,
6 => count6,
_ => count4,
};
var timeline = director.playableAsset as TimelineAsset;
double fps = timeline != null ? timeline.editorSettings.frameRate : 30.0;
director.time = jumpFrame / fps;
director.Play();
}
private bool _hasJumped;
public void SetBeiShu()
{
int.TryParse(beishu.text, out int prev);
StopAllCoroutinesForBeiShu();
_beiShuCoroutine = StartCoroutine(BeiShuEffect(prev, beishunum));
}
private Coroutine _beiShuCoroutine;
private void StopAllCoroutinesForBeiShu()
{
if (_beiShuCoroutine != null)
StopCoroutine(_beiShuCoroutine);
}
private IEnumerator BeiShuEffect(int from, int to)
{
float duration = 0.5f;
float elapsed = 0f;
Vector3 normalScale = beishu.transform.localScale;
Vector3 bigScale = normalScale * 1.5f;
// 放大
beishu.transform.DOScale(bigScale, duration * 0.3f).SetEase(Ease.OutBack);
// 放大(原节奏:总时长的 30% 用于放大)
beishu.transform.DOScale(normalScale * 1.5f, beiShuRollDuration * 0.3f).SetEase(Ease.OutBack);
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = elapsed / duration;
int val = (int)Mathf.Lerp(from, to, t);
beishu.text = val.ToString();
yield return null;
}
beishu.text = to.ToString();
// 迅速缩小回正常
beishu.transform.DOScale(normalScale, 0.15f).SetEase(Ease.InBack);
}
public void EndBJ()
{
if (bjEndUI != null)
{
var uiPos = GetSeatPosition() + Vector3.up * bjEndUIOffsetY;
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, CreateFishManager.Instance.bjEffectRoot);
endUI.Init(bJbeishu, maxScore);
bjEndUI = null; // 防止 OnScoreEnd 重复创建
}
OnScoreEnd();
// 基类通用数字滚动(自动停止上一次滚动),结束后缩放回正常大小
RollNumber(
v => beishu.text = v.ToString(),
prev, beishunum, beiShuRollDuration,
onDone: () => beishu.transform.DOScale(normalScale, 0.15f).SetEase(Ease.InBack));
}
}
@@ -1,100 +1,12 @@
using DG.Tweening;
using Newtonsoft.Json;
using Spine.Unity;
using System;
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using Random = UnityEngine.Random;
public class GSLDieEvent :BJEventBase
/// <summary>
/// GSL 倍数型爆奖:累计倍数直接显示(无滚动动画)、快播无轮次守卫,其余流程同 TimelineBeiShuEvent。
/// </summary>
public class GSLDieEvent : TimelineBeiShuEvent
{
public LeiLongkillObj flxjKill;
public TextMeshProUGUI beishu;
public int beishunum;
public TextMeshProUGUI chengshu;
public TextMeshProUGUI xiaoGuo_Effect;
public int currCount = 0;
public int count;
public PlayableDirector director; // 控制 Timeline
public List<GameObject> gameObjects;
public int count4; // 如果重复4次 从指定位置开始播放的帧数 timeline
public int count5; // 如果重复5次 从指定位置开始播放的帧数 timeline
public int count6; // 如果重复6次 从指定位置开始播放的帧数 timeline
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
{
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
flxjKill = JsonConvert.DeserializeObject<LeiLongkillObj>(obj.ToString());
count = flxjKill.res.Count;
}
public void SetChengshu()
{
chengshu.text = fishScore.ToString();
}
/// <summary>触发爆奖效果面板:累加倍数、随机激活效果面板(按 currCount 取 index)</summary>
public void SetxiaoGuo_Effect()
{
int index = currCount;
int addbeishu = flxjKill.res[index].score;
beishunum += addbeishu;
xiaoGuo_Effect.text = addbeishu.ToString();
// 随机激活一个效果面板
int temp = Random.Range(0, gameObjects.Count);
foreach (var item in gameObjects)
{
if (item.activeSelf)
item.SetActive(false);
}
gameObjects[temp].SetActive(true);
currCount++;
}
/// <summary>Timeline 快播:根据 count 跳到 4/5/6 对应帧位置</summary>
public void PlayFastTimeline()
/// <summary>GSL 版快播:无轮次守卫,直接按 count 跳帧(保留原行为)</summary>
public override void PlayFastTimeline()
{
if (director == null) return;
int jumpFrame = count switch
{
4 => count4,
5 => count5,
6 => count6,
_ => count4,
};
var timeline = director.playableAsset as TimelineAsset;
double fps = timeline != null ? timeline.editorSettings.frameRate : 30.0;
director.time = jumpFrame / fps;
director.Play();
}
public void SetBeiShu()
{
beishu.text = beishunum.ToString();
}
public void EndBJ()
{
if (bjEndUI != null)
{
var uiPos = GetSeatPosition() + Vector3.up * bjEndUIOffsetY;
var endUI = Instantiate(bjEndUI, uiPos, Quaternion.identity, CreateFishManager.Instance.bjEffectRoot);
endUI.Init(bJbeishu, maxScore);
bjEndUI = null; // 防止 OnScoreEnd 重复创建
}
OnScoreEnd();
JumpToCountFrame();
}
}
@@ -105,31 +105,33 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
bjEndUI: {fileID: 4300126860111980404, guid: aad12370f7ffcff46953d04d43d3dc0e, type: 3}
bjEndUIOffsetY: 150
posID: 0
paoBei: 0
fishScore: 0
bJbeishu: 0
maxScore: 0
startOffset: {x: 0, y: 0, z: -100}
isSelf: 0
isScoreEnd: 0
useScorePanel: 1
tMP_Score: {fileID: 0}
scorePanelPrefab: {fileID: 3444441392116629287, guid: c338a40e357668544bc5786c387beb6d,
type: 3}
currScore: 0
maxScore: 0
scoreCount: 0
posID: 0
paoBei: 0
fishScore: 0
bJbeishu: 0
bigPrizeFishMode: 2
showDelay: 3
moveDuration: 0.5
moveEase: 6
startOffset: {x: 0, y: 0, z: -100}
bjEndUIOffsetY: 150
coinFlyDuration: 0.5
coinArrivalInterval: 0.1
isSelf: 0
showAddScoreFX: 1
autoFinishOnScoreFull: 1
totalBJCount: 0
currBJCount: 0
isEffEnd: 0
isScoreStart: 0
isScoreEnd: 0
isGoldEffectStart: 0
--- !u!1 &3554409069372481140 stripped
GameObject:
@@ -4,7 +4,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class JBP_Evenrt : BJEventBase
public class JBP_Evenrt : BJRedPacketEvent
{
private void Awake()
{
@@ -7,7 +7,7 @@ using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;
public class JinLongEvent : BJEventBase
public class JinLongEvent : BJRedPacketEvent
{
public SkeletonGraphic skeletonGraphic;
@@ -70,7 +70,7 @@ public class JinLongEvent : BJEventBase
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
{
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
GoldEffect();
}
public override void GoldEffect()
{
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class LLBTDieEvent : BJEventBase
public class LLBTDieEvent : BJRedPacketEvent
{
public GameObject obj;
private void Awake()
@@ -1881,31 +1881,33 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier:
bjEndUI: {fileID: 4300126860111980404, guid: 32ec3a78eb49ab84da41f0a3b57630cf, type: 3}
bjEndUIOffsetY: 150
posID: 0
paoBei: 0
fishScore: 0
bJbeishu: 0
maxScore: 0
startOffset: {x: 0, y: 0, z: -100}
isSelf: 0
isScoreEnd: 0
useScorePanel: 1
tMP_Score: {fileID: 0}
scorePanelPrefab: {fileID: 8000219247718126128, guid: 49f9a636613f12d4ca7d32814d229c0d,
type: 3}
currScore: 0
maxScore: 0
scoreCount: 0
posID: 0
paoBei: 0
fishScore: 0
bJbeishu: 0
killFishOnBigPrize: 0
showDelay: 3
moveDuration: 0.5
moveEase: 6
startOffset: {x: 0, y: 0, z: -100}
bjEndUIOffsetY: 150
coinFlyDuration: 0.5
coinArrivalInterval: 0.1
isSelf: 0
showAddScoreFX: 1
autoFinishOnScoreFull: 1
totalBJCount: 0
currBJCount: 0
isEffEnd: 0
isScoreStart: 0
isScoreEnd: 0
isGoldEffectStart: 0
mod: {fileID: 335302965287046095}
--- !u!1 &335302965287046095 stripped
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PTSDieEvent : BJEventBase
public class PTSDieEvent : BJRedPacketEvent
{
public GameObject mod;
private void Awake()
@@ -7,7 +7,7 @@ using TMPro;
using UnityEngine;
using Random = UnityEngine.Random;
public class LeiLongEvent : BJEventBase
public class LeiLongEvent : BJRedPacketEvent
{
public SkeletonGraphic skeletonGraphic;
public TextMeshProUGUI tMP_longzhu1;
@@ -4,7 +4,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class RYGZDieEvent : BJEventBase
public class RYGZDieEvent : BJRedPacketEvent
{
public PlayableDirector playable;
public List<GameObject> bJ_BeiShu;
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SLZPDieEvent : BJEventBase
public class SLZPDieEvent : BJRedPacketEvent
{
private void Awake()
{
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TSKDieEvent : BJEventBase
public class TSKDieEvent : BJRedPacketEvent
{
private void Awake()
{
@@ -0,0 +1,118 @@
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using Random = UnityEngine.Random;
/// <summary>
/// Timeline 驱动的倍数型爆奖事件(分 n 次加爆奖倍数)。
/// FLXJ / GSL 共用流程:
/// Timeline 每轮触发 SetxiaoGuo_Effect(本轮加成倍数 + 随机激活效果面板)
/// → SetBeiShu(累计倍数显示)→ 最后一轮 EndBJ 结算(基类统一 JiaFen + BJEndUI + die)。
///
/// 两个子类的差异(由子类 override 保留):
/// FLXJEvent.SetBeiShu —— 数字滚动 + 缩放动画;GSL 直接显示
/// GSLDieEvent.PlayFastTimeline —— 无轮次守卫直接跳帧
///
/// ⭐ 字段名与原 FLXJEvent / GSLDieEvent 完全一致,预制体序列化数据无需重拖。
/// </summary>
public class TimelineBeiShuEvent : BJRedPacketEvent
{
public LeiLongkillObj flxjKill; // 服务端下发的每轮加成倍数
public TextMeshProUGUI beishu; // 累计倍数显示
public int beishunum; // 累计倍数
public TextMeshProUGUI chengshu; // 底分(成数)显示
public TextMeshProUGUI xiaoGuo_Effect; // 本轮效果/加成倍数显示
public int currCount = 0; // 已结算轮次
public int count; // 总轮次(服务端 res 数量)
public PlayableDirector director; // 控制 Timeline
public List<GameObject> gameObjects; // 效果面板列表(随机激活一个)
public int count4; // 如果重复4次 从指定位置开始播放的帧数 timeline
public int count5; // 如果重复5次 从指定位置开始播放的帧数 timeline
public int count6; // 如果重复6次 从指定位置开始播放的帧数 timeline
/// <summary>PlayFastTimeline 是否已跳过帧(防重复跳帧)</summary>
protected bool _hasJumped;
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
{
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
flxjKill = JsonConvert.DeserializeObject<LeiLongkillObj>(obj.ToString());
count = flxjKill.res.Count;
}
/// <summary>显示底分(成数)</summary>
public void SetChengshu()
{
chengshu.text = fishScore.ToString();
}
/// <summary>触发爆奖效果面板:累加倍数、随机激活效果面板(按 currCount 取 index)</summary>
public void SetxiaoGuo_Effect()
{
int index = currCount;
int addbeishu = flxjKill.res[index].score;
beishunum += addbeishu;
xiaoGuo_Effect.text = addbeishu.ToString();
// 随机激活一个效果面板
int temp = Random.Range(0, gameObjects.Count);
foreach (var item in gameObjects)
{
if (item.activeSelf)
item.SetActive(false);
}
gameObjects[temp].SetActive(true);
currCount++;
}
/// <summary>Timeline 快播:currCount>=3 时跳一次到 4/5/6 对应帧位置(子类可 override)</summary>
public virtual void PlayFastTimeline()
{
if (count <= 3) return;
if (director == null) return;
if (currCount < 3) return; // 没走完 3 轮不跳
if (_hasJumped) return; // 已经跳过不再跳
_hasJumped = true;
JumpToCountFrame();
}
/// <summary>按 count 跳到 4/5/6 对应的 Timeline 帧位置</summary>
protected void JumpToCountFrame()
{
if (director == null) return;
int jumpFrame = count switch
{
4 => count4,
5 => count5,
6 => count6,
_ => count4,
};
var timeline = director.playableAsset as TimelineAsset;
double fps = timeline != null ? timeline.editorSettings.frameRate : 30.0;
director.time = jumpFrame / fps;
director.Play();
}
/// <summary>更新累计倍数显示(子类可 override 加滚动动画,如 FLXJEvent)</summary>
public virtual void SetBeiShu()
{
beishu.text = beishunum.ToString();
}
/// <summary>结束爆奖:走基类统一结算(JiaFen + BJEndUI + die)</summary>
public void EndBJ()
{
OnScoreEnd();
}
}
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42cae83bc3d652f4eb94afd13bd5b21f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -4,7 +4,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class YGLGDieEvent : BJEventBase
public class YGLGDieEvent : BJRedPacketEvent
{
public PlayableDirector playable;
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class TYGSMieEvent : BJEventBase
public class TYGSMieEvent : BJRedPacketEvent
{
public override void Init(long goldCount, int posID, long paobei, long fishScore, int beishu, Action<int> action, Action action1 = null)
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ZDXDieEvent : BJEventBase
public class ZDXDieEvent : BJRedPacketEvent
{
private void Awake()
{
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BGJDieEvent : BJEventBase
public class BGJDieEvent : BJRedPacketEvent
{
private void Awake()
{
@@ -3407,6 +3407,11 @@ PrefabInstance:
propertyPath: m_Layer
value: 10
objectReference: {fileID: 0}
- target: {fileID: 5361217301145289591, guid: 2210a380332683b4e8f0f7b1a922af06,
type: 3}
propertyPath: m_AnchoredPosition.y
value: 95
objectReference: {fileID: 0}
- target: {fileID: 5361949059686210397, guid: 2210a380332683b4e8f0f7b1a922af06,
type: 3}
propertyPath: m_Layer
@@ -3,7 +3,7 @@ using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class XBLDieEvent : BJEventBase
public class XBLDieEvent : BJRedPacketEvent
{
private void Awake()
{
@@ -18,7 +18,7 @@ using UnityEngine;
/// PlayEffect() —— 由 MonsterDieList.SpecialDieFish 调用(ZDX 覆写为宝箱金币);
/// CreateBaoJiangEffect() —— 子类自身流程结束后调用,按模式分发爆奖。
/// </summary>
public class DieEffect_TSY : BJEventBase
public class DieEffect_TSY : BJRedPacketEvent
{
[Header("====== 爆奖模式(特殊鱼/Boss 互通开关)======")]
[Tooltip("小鱼爆奖 = 走 BaoJiangTSSmallFish 拓展;Boss爆奖 = 走 BJEventBase 完整流程")]
@@ -14,7 +14,7 @@ using Random = UnityEngine.Random;
/// → 播放爆炸特效 + Physics2D 圈形检测范围内鱼 → 普通鱼走 Id_DieFish_FX 死亡
/// → 爆炸后进入加分滚动 → MoveToSit → OnScoreEnd → JiaFen → die
/// </summary>
public class BaoLieJinShaEvent : BJEventBase
public class BaoLieJinShaEvent : BJRedPacketEvent
{
[Header("爆炸配置")]
[Tooltip("爆炸特效预制体")]
@@ -44,6 +44,9 @@ public class BaoLieJinShaEvent : BJEventBase
base.Init(goldCount, posID, paobei, fishScore, beishu, action, action1);
// ⭐ 关闭加金币飘字特效(dieFXPrefabAwardTmp_AddScore),只加分不飘字
showAddScoreFX = false;
// ⭐ 爆奖只分包不关联场上鱼(爆炸范围内鱼的死鱼爆奖已由 TriggerExplosion 处理,
// 避免全屏随机位置死飞机爆奖)
bigPrizeFishMode = BigPrizeFishMode.NoFish;
// ⭐ 取消 base 的报奖后停留(showDelay=3s,会拖慢收尾),
// 由重写的 MoveToSit 统一"加完分后等 1 秒直接显示 bjEndUI"
showDelay = 0f;
@@ -133,25 +136,6 @@ public class BaoLieJinShaEvent : BJEventBase
// → DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd → JiaFen → die
}
/// <summary>
/// 重写 BigPrize:用 BossGlodCoinNotFish 分包(不关联场上鱼),
/// 避免 BossGlodCoinRandrom 从场上随机选普通鱼在各自位置掉金币,
/// 导致"全屏随机位置死飞机爆奖"。爆炸范围鱼的爆奖已由 TriggerExplosion 处理。
/// </summary>
public override List<RedPacketRecord> BigPrize(int min = 10, int max = 15)
{
if (layeredPool == null)
layeredPool = new LayeredPool(maxScore, scoreCount > 0 ? scoreCount : 1);
var v = layeredPool.BossGlodCoinNotFish(Random.Range(min, max) + 1);
int totalAmount = 0;
if (v != null) foreach (var r in v) totalAmount += (int)r.Amount;
Debug.Log($"[BaoLieJinSha] BigPrize: maxScore={maxScore} scoreCount={scoreCount} records={(v != null ? v.Count : 0)} totalAmount={totalAmount}");
return v;
}
/// <summary>
/// 加分完成后等 1 秒直接显示结束 UI(不飞回座位、不做多余停留)。
/// 爆炸/掉金币本身已展示爆奖效果,加分完成后无需再长时间等待。
@@ -8,7 +8,7 @@ using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class ChaoNengMoHeEvent : BJEventBase
public class ChaoNengMoHeEvent : BJRedPacketEvent
{
/// <summary>Boss 死亡时传来的特殊值(服务端 res 数组),与幸运轮一致</summary>
private List<BossKillOption> _cardParams = new List<BossKillOption>();
@@ -16,7 +16,7 @@ using UnityEngine;
///
/// ⭐ 分数面板位置 = 爆奖位置 + scorePanelOffset(默认上方),不走屏幕正下方。
/// </summary>
public class HeiDongFeiChuanEvent : BJEventBase
public class HeiDongFeiChuanEvent : BJRedPacketEvent
{
[Header("黑洞配置")]
[Tooltip("黑洞持续时间(秒)")]
@@ -1,9 +1,11 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class JiJiaLeiTingEvent : BJEventBase
/// <summary>
/// 机甲雷霆:倍数从 1 滚到服务端下发的 bJbeishu(复用基类 RollNumber 滚动),
/// Timeline 结束直接 OnScoreEnd 结算。
/// </summary>
public class JiJiaLeiTingEvent : BJRedPacketEvent
{
public Text number_BeiShu;
@@ -11,13 +13,11 @@ public class JiJiaLeiTingEvent : BJEventBase
[Tooltip("倍数从1涨到最终倍数(bJbeishu)所需时间(秒)")]
public float beiShuRollDuration = 2f;
/// <summary>倍数滚动协程(防重复启动)</summary>
private Coroutine _beiShuCoroutine;
public void BJ()
{
CallBJ();
}
public void TimeLineEnd()
{
// 最后不发金币红包,直接结束:回加金币 + 显示 bjEndUI + 删分数面板 + 回收
@@ -35,32 +35,7 @@ public class JiJiaLeiTingEvent : BJEventBase
// 音效:数字滚动(PW_Number_Roll)
AudioManager.Instance.PlayerFXByName("PW_Number_Roll");
// 防重复触发:先停掉上一次滚动
if (_beiShuCoroutine != null)
StopCoroutine(_beiShuCoroutine);
_beiShuCoroutine = StartCoroutine(BeiShuRollRoutine(1, bJbeishu, beiShuRollDuration));
}
private IEnumerator BeiShuRollRoutine(int from, int to, float duration)
{
if (duration <= 0f || to <= from)
{
number_BeiShu.text = to.ToString();
_beiShuCoroutine = null;
yield break;
}
float elapsed = 0f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
float t = Mathf.Clamp01(elapsed / duration);
number_BeiShu.text = Mathf.RoundToInt(Mathf.Lerp(from, to, t)).ToString();
yield return null;
}
// 确保最终精确落在最终倍数
number_BeiShu.text = to.ToString();
_beiShuCoroutine = null;
// 基类通用数字滚动(自动停止上一次滚动,防重复触发)
RollNumber(v => number_BeiShu.text = v.ToString(), 1, bJbeishu, beiShuRollDuration);
}
}
@@ -31,7 +31,7 @@ using Random = UnityEngine.Random;
/// ⭐ 资源配置:所有预制体/图片/名称集中在 JiXieXieConfig 资产(ScriptableObject),
/// 只需拖一个 config 字段。资产用菜单 Tools → 机械蝎 → 生成八连抽配置资产 一键生成。
/// </summary>
public class JiXieXieEvent : BJEventBase
public class JiXieXieEvent : BJRedPacketEvent
{
// ==================== Inspector 字段 ====================
@@ -9,7 +9,7 @@ using UnityEngine;
/// 炸一下(播放爆炸特效,不死任何鱼)→ 等特效播完 → 显示 bjEndUI + 回加金币 → 回收。
/// 死亡/未死亡由 Boss 解析服务端 param 决定,Event 不关心。
/// </summary>
public class LieYanFengBaoEvent : BJEventBase
public class LieYanFengBaoEvent : BJRedPacketEvent
{
[Header("爆炸配置")]
[Tooltip("爆炸特效播放时长(播完后显示 bjEndUI)")]
@@ -11,7 +11,7 @@ using UnityEngine;
///
/// 不自动启动爆炸杀鱼协程,不自动触发 EffEnd/StartAddScore。
/// </summary>
public class PoHuaiQiuEvent : BJEventBase
public class PoHuaiQiuEvent : BJRedPacketEvent
{
/// <summary>爆炸中心(世界坐标,由 Boss 传入=中心位置 dieTargetPosition)</summary>
[HideInInspector]
@@ -430,9 +430,9 @@ public class PoHuaiQiu_BOSS : MonsterControl_BossBase
RectTransform canvasRect = canvas.GetComponent<RectTransform>();
// 获取 Event 引用(用于调用 BigPrize 红包算法)
BJEventBase evt = null;
BJRedPacketEvent evt = null;
if (_pendingEffectObj != null)
evt = _pendingEffectObj.GetComponent<BJEventBase>();
evt = _pendingEffectObj.GetComponent<BJRedPacketEvent>();
// 红包记录队列:用完一批再调 BigPrize 补充
var redPacketQueue = new System.Collections.Generic.List<RedPacketRecord>();
@@ -26,7 +26,7 @@ using Random = UnityEngine.Random;
/// numIndex 0-12 → 牌面 1-13(A,2..10,J,Q,K)
/// huaIndex 0-3 → 0=方片(♦红) 1=梅花(♣黑) 2=红心(♥红) 3=黑桃(♠黑)(PW_CardType)
/// </summary>
public class XiaoChouPuKeEvent : BJEventBase
public class XiaoChouPuKeEvent : BJRedPacketEvent
{
[Header("卡牌面板")]
public FanPai fanPai; // 三张牌调度面板(Inspector 拖入)
@@ -43,7 +43,7 @@ using UnityEngine;
/// → 奖励框 → CallBJ发红包 → 暴击文字 → 结算特效 → EffEnd
/// → DelayThenScore → StartAddScore → MoveToSit → OnScoreEnd → JiaFen → die
/// </summary>
public class XingJiXunHangEvent : BJEventBase
public class XingJiXunHangEvent : BJRedPacketEvent
{
// ==================== 形态一:富甲天下(无道具武器) ====================
@@ -305,6 +305,9 @@ public class XingJiXunHangEvent : BJEventBase
// ⭐ 星际巡航不需要 ScoreNumScroll(Clone) 加分数字滚动特效(杀鱼分已加 Boss 面板)
showAddScoreFX = false;
// ⭐ 爆奖只分包不关联场上鱼(已有完整的道具武器/全屏/结算动画,
// 避免全屏随机位置死飞机爆奖)
bigPrizeFishMode = BigPrizeFishMode.NoFish;
// 解析武器 ID
ParseWeaponId();
@@ -449,28 +452,6 @@ public class XingJiXunHangEvent : BJEventBase
$" prop={(_propPrefab != null ? _propPrefab.name : "null")}");
}
// ==================== 红包发奖(重写) ====================
/// <summary>
/// 重写 BigPrize:用 BossGlodCoinNotFish 分包(不关联场上鱼),
/// 避免 BossGlodCoinRandrom 从场上随机选普通鱼在各自位置掉金币,
/// 导致"全屏随机位置死飞机爆奖"。
/// 星际迷航已有完整的道具武器/全屏/结算动画,只需分包发红包。
/// </summary>
public override List<RedPacketRecord> BigPrize(int min = 10, int max = 15)
{
if (layeredPool == null)
layeredPool = new LayeredPool(maxScore, scoreCount > 0 ? scoreCount : 1);
var v = layeredPool.BossGlodCoinNotFish(UnityEngine.Random.Range(min, max) + 1);
int totalAmount = 0;
if (v != null) foreach (var r in v) totalAmount += (int)r.Amount;
Debug.Log($"[XingJiXunHang] BigPrize: maxScore={maxScore} scoreCount={scoreCount} records={(v != null ? v.Count : 0)} totalAmount={totalAmount}");
return v;
}
// ==================== 爆奖主流程 ====================
/// <summary>
@@ -28,7 +28,7 @@ using Random = UnityEngine.Random;
///
/// OptionId → 角度映射:索引 × (360/选项数)
/// </summary>
public class RotatePan_XJMH : BJEventBase
public class RotatePan_XJMH : BJRedPacketEvent
{
[Header("转盘")]
public Transform wai; // 外圈转盘
@@ -24,7 +24,7 @@ using UnityEngine;
/// 服务端 param 格式:{ "res": [{optionId, triggerRate, score}], "count": N }
/// optionId = 分值(如 130/300/280),映射到 slotScores 中匹配的格子索引
/// </summary>
public class XingYunLunEvent : BJEventBase
public class XingYunLunEvent : BJRedPacketEvent
{
public GameObject BJFXEffectModel; // 爆奖特效模型(转轮预制体)