备份CatanBuilding瘦身独立工程

This commit is contained in:
JSD\13999
2026-05-26 16:15:54 +08:00
commit 2d0e6a61b7
12001 changed files with 2431925 additions and 0 deletions

View File

@@ -0,0 +1,338 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.AddressableAssets;
using cfg;
using asap.core;
using UnityEngine.ResourceManagement.AsyncOperations;
public class BlockManager : MonoBehaviour
{
private Dictionary<string, GameObject> _blockPrefabs = new Dictionary<string, GameObject>();
//[SerializeField] private BoxCollider2D _deathWall;
[SerializeField] List<Block> _blocks = new List<Block>();
[SerializeField] private Transform _focus;
public Block CurrentBlock;
private TbConstructionBasicUnits _blockTypesTable;
private TbConstructionUnits _blocksTable;
private TbConstructionHeightEvent _heightEventTable;
private InfiniteBuildingConf _cfg;
private InfiniteBuildingData _data;
private EventAggregator _eventAggregator;
private List<AsyncOperationHandle> _prefabOps;
public List<Block> Blocks => _blocks;
private void Start()
{
_blockTypesTable = GContext.container.Resolve<Tables>().TbConstructionBasicUnits;
_blocksTable = GContext.container.Resolve<Tables>().TbConstructionUnits;
_prefabOps = new List<AsyncOperationHandle>();
}
private void OnDestroy()
{
foreach (var op in _prefabOps)
Addressables.Release(op);
}
public void Init(InfiniteBuildingConf cfg, InfiniteBuildingData data, EventAggregator ea)
{
_cfg = cfg;
_data = data;
_eventAggregator = ea;
_heightEventTable = GContext.container.Resolve<Tables>().TbConstructionHeightEvent;
}
/// <summary>
/// Get prefab according to PrefabID, will be used in init and block generation
/// </summary>
/// <param name="id">name of the prefab in addressables</param>
/// <returns>the prefab GameObject</returns>
private async System.Threading.Tasks.Task<GameObject> GetBlockPrefab(string id)
{
if (_blockPrefabs.TryGetValue(id, out var prefab))
return prefab;
_prefabOps.Add(Addressables.LoadAssetAsync<object>(id));
var go = (GameObject) await _prefabOps[^1].Task;
_blockPrefabs.Add(id, go);
return go;
}
private int GetRandomIDFromWeightTable(Dictionary<int, float> weightTable)
{
Dictionary<int, float> weightSum = new Dictionary<int, float>();
float sum = 0;
foreach (var e in weightTable)
{
sum += e.Value;
weightSum.Add(e.Key, sum);
}
float randomNum = UnityEngine.Random.Range(0, sum);
foreach (var e in weightSum)
{
if (randomNum <= e.Value)
{
return e.Key;
}
}
Debug.LogError($"Random ID not available. WeightTable entries count: {weightTable.Count}.");
return -1;
}
public async System.Threading.Tasks.Task<Block> GenerateBlock(Vector3 spawnPos, bool isFirst = false)
{
Block generatedBlock;
Dictionary<int, float> weightTable = new Dictionary<int, float>();
//_crane.ResetPosition();
//await Awaiters.NextFrame;
int type, block;
foreach (var bt in _blockTypesTable.DataList)
{
weightTable.Add(bt.ID, bt.Weight);
}
type = GetRandomIDFromWeightTable(weightTable);
weightTable.Clear();
foreach (int blockID in _blockTypesTable[type].UnitList)
{
if (_data.Lvl < _blocksTable[blockID].UnlockedHeight)
continue;
weightTable.Add(blockID, _blocksTable[blockID].Weight);
}
block = GetRandomIDFromWeightTable(weightTable);
if (isFirst && _data.LastHangingBlock != -1)
{
block = _data.LastHangingBlock;
_data.LastHangingBlock = -1;
}
TbConstructionInfiniteInit initTable = GContext.container.Resolve<Tables>().TbConstructionInfiniteInit;
if (_data.Lvl < initTable.DataList.Count)
block = GContext.container.Resolve<Tables>().TbConstructionInfiniteInit.DataList[_data.Lvl].UnitID;
#if UNITY_EDITOR
if (_cfg.NextBlockToSpawn != -1 && _blocksTable.DataMap.ContainsKey(_cfg.NextBlockToSpawn))
block = _cfg.NextBlockToSpawn;
#endif
string id = _blocksTable[block].Prefab;
GameObject prefab = await GetBlockPrefab(id);
//GameObject prefab = await GetBlockPrefab("block_000");//Get test prefab
//Debug.Log($"<color=red>{_crane.transform.position}</color>");
//Debug.Log($"<color=red>{_cfg.blockSpawnOffset}</color>");
generatedBlock = Instantiate(prefab, spawnPos + _blocksTable[block].Height * Vector3.down,
prefab.transform.rotation, transform).GetComponent<Block>();
generatedBlock.InitHangingBlock(BlockState.Hanging, block, _eventAggregator, _cfg);
generatedBlock.Rb.angularDrag = GetDataByIBLvl(_data.Lvl, _heightEventTable.DataList).AngularDrag;
generatedBlock.Rb.drag = GetDataByIBLvl(_data.Lvl, _heightEventTable.DataList).LinearDrag;
//_currentBlock.SetParams(_cfg, _deathWall.name, block, _focus);
//generatedBlock.OnRest += async d => await OnBlockRest(d);
//generatedBlock.OnDestroy += async () => await OnBlockDestroy();
//_currentBlock.AttachJoints(_crane);
//_crane.AttachJoints(generatedBlock);
//await _crane.Descend();
//if (doSwitchState)
// _stateMachine.SetState(EInfiniteBuildingState.PlayerCtrl);
return generatedBlock;
}
private async System.Threading.Tasks.Task<GameObject> GenerateBlock(InfiniteBuildingData.BlockRecord record, IEventAggregator ea)
{
GameObject b = Instantiate(await GetBlockPrefab(record.PrefabID),
new Vector3(record.Pos.x, record.Pos.y, _cfg.blockDepth), Quaternion.identity, transform);
b.GetComponent<Rigidbody2D>().isKinematic = true;
b.GetComponent<Rigidbody2D>().velocity = Vector2.zero;
b.GetComponent<Block>().Idx = record.ID;
b.GetComponent<Block>().EventAggregator = ea;
//_blocks[^1].SetParams(_cfg, _deathWall.name, record.id, _focus);
return b;
}
public int GetExcellentScore()
{
int fallingBlockScore = _blocksTable[CurrentBlock.Idx].FallPoint;
int stackedBlockScore = _blocks is { Count: > 0 } ? _blocksTable[_blocks[^1].Idx].StackPoint : 0;
// Debug.Log($"<color=red>Incoming: {fallingBlockScore}, stacked: {stackedBlockScore}</color>");
return fallingBlockScore + stackedBlockScore;
}
public bool TrySnap()
{
if (_blocks is not { Count: > 0 })
{
if (Mathf.Abs(CurrentBlock.Rb.position.x - _focus.position.x) > _cfg.snapThresh)
return false;
CurrentBlock.Rb.MovePosition(new Vector2(_focus.position.x, CurrentBlock.Rb.position.y));
return true;
}
if (Mathf.Abs(CurrentBlock.Rb.position.x - _blocks[^1].Rb.position.x) > _cfg.snapThresh)
return false;
CurrentBlock.Rb.MovePosition(new Vector2(_blocks[^1].Rb.position.x, CurrentBlock.Rb.position.y));
return true;
}
public async void AlignBlocks(IEventAggregator ea)
{
Block b;
for (int j = _blocks.Count - 1; j >= 0; j--)
{
b = _blocks[j];
//_blocks.RemoveAt(j);
if (b != null)
Destroy(b.gameObject);
}
Vector3 pivot = _focus.position;
for (int i = _data.Record.Count - 1; i >= 0; i--)
{
InfiniteBuildingData.BlockRecord r = _data.Record[i];
b = Instantiate(await GetBlockPrefab(r.PrefabID),
pivot + r.Height * Vector3.down,
Quaternion.identity, transform).GetComponent<Block>();
pivot += r.Height * Vector3.down;
//_blocks[_data.Record.Count - 1 - i] = b;
_blocks[i] = b;
b.Rb.isKinematic = true;
b.Rb.velocity = Vector2.zero;
b.Idx = r.ID;
b.EventAggregator = ea;
}
for (int i = _blocks.Count - 1; i >= 0; i--)
{
b = _blocks[i];
if (b.WorldHeight < _focus.position.y + _cfg.blockDestroyOffset)
{
_blocks.RemoveAt(i);
Destroy(b.gameObject);
}
else if (b.WorldHeight < _focus.position.y + _cfg.blockRestingOffset)
{
b.Rb.isKinematic = true;
b.State = BlockState.Locked;
}
else
{
b.Rb.isKinematic = false;
b.State = BlockState.Resting;
}
}
//for (int i = 0; i < _blocks.Count; i++)
//{
// if (_blocks[i] == null)
// continue;
// _blocks[i].Rb.MovePosition(new Vector2(0, _data.Record[i].pos.y));
//}
}
private float _blockDestructionTimer = 1000f;
public void BlockFallFixedUpdate()
{
float rot = CurrentBlock.Rb.rotation;
_blockDestructionTimer -= Time.fixedDeltaTime;
if (_blockDestructionTimer < 0)
{
_eventAggregator.Publish(new EventInfiniteBuildingFail());
return;
}
if (!CurrentBlock.Freezable || !CurrentBlock.IsCurrentBlockStill)
return;
if ((rot <= _cfg.blockDestroyThreshAngle && rot > -_cfg.blockDestroyThreshAngle)
|| (rot >= 180 - _cfg.blockDestroyThreshAngle && rot <= 180)
|| (rot >= -180 && rot <= -180 + _cfg.blockDestroyThreshAngle))
_eventAggregator.Publish(new EventInfiniteBuildingSucceed());
else
_eventAggregator.Publish(new EventInfiniteBuildingFail());
}
public void StartDestroyCountDown()
{
//Debug.Log("111111111111111");
_blockDestructionTimer = _cfg.blockDestroyDelay;
}
public void ResetDestroyCountDown()
{
_blockDestructionTimer = float.PositiveInfinity;
}
public void AddCurrentBlock()
{
_blocks.Add(CurrentBlock);
}
private void CurrentBlockFail()
{
Debug.Log("Build failure.");
}
/// <summary>
/// Lock or clear blocks according to their height, need focus updated first
/// </summary>
public void LockOrClearBlocks(bool isFilterOnly = false)
{
for (int i = _blocks.Count - 1; i >= 0; i--)
{
Block b = _blocks[i];
if (b.WorldHeight < _cfg.blockDestroyOffset + _focus.position.y)
{
_blocks.RemoveAt(i);
Destroy(b.gameObject);
}
else if (b.WorldHeight < _cfg.blockRestingOffset + _focus.position.y )
{
b.Rb.velocity = Vector2.zero;
b.Rb.rotation = 0;
b.Rb.angularVelocity = 0;
b.Rb.isKinematic = true;
}
else if (!isFilterOnly)
b.Rb.isKinematic = false;
}
}
/// <summary>
/// Clear stage, generate blocks according to data, and reset focus position
/// </summary>
/// <returns>Task</returns>
public async System.Threading.Tasks.Task RebuildAllBlocks()
{
//clear the act
if (CurrentBlock != null)
Destroy(CurrentBlock.gameObject);
await RebuildBlocks();
}
/// <summary>
/// reset stage, bug leave the current block alone
/// </summary>
/// <returns></returns>
public async System.Threading.Tasks.Task RebuildBlocks(bool doesLockAll = false)
{
Block b;
for (int j = _blocks.Count - 1; j >= 0; j--)
{
b = _blocks[j];
_blocks.RemoveAt(j);
if (b != null)
Destroy(b.gameObject);
}
//regenerate
_focus.position = new Vector3(_focus.position.x, 0, _focus.position.z);
foreach (var record in _data.Record)
{
b = (await GenerateBlock(record, _eventAggregator)).GetComponent<Block>();
b.InitRecordBlock(_cfg);
b.LitBlock();
_blocks.Add(b);
if (_focus.position.y < b.WorldHeight)
_focus.position = new Vector3(_focus.position.x, b.WorldHeight, _focus.position.z);
}
for (int i = _blocks.Count - 1; i >= 0; i--)
{
b = _blocks[i];
if (b.WorldHeight < _focus.position.y + _cfg.blockDestroyOffset)
{
_blocks.RemoveAt(i);
Destroy(b.gameObject);
}
else if (b.WorldHeight < _focus.position.y + _cfg.blockRestingOffset || doesLockAll)
{
b.Rb.isKinematic = true;
b.State = BlockState.Locked;
}
else
{
b.Rb.isKinematic = false;
b.State = BlockState.Resting;
}
}
}
private ConstructionHeightEvent GetDataByIBLvl(int lvl, List<ConstructionHeightEvent> dataList)
{
for (int i = 0; i < dataList.Count - 1; i++)
{
if (lvl < dataList[i + 1].Height)
return dataList[i];
}
return dataList[^1];
}
}