备份CatanBuilding瘦身独立工程
This commit is contained in:
338
Assets/Scripts/InfiniteBuilding/BlockManager.cs
Normal file
338
Assets/Scripts/InfiniteBuilding/BlockManager.cs
Normal 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];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user