From 7ae55fc7270a773d5d7d69f09cb6a152248d9782 Mon Sep 17 00:00:00 2001 From: Texel Date: Sun, 29 Jan 2023 19:34:24 -0500 Subject: [PATCH] Semi-playable test state, load Lemon_Test scene and LayeredStaging under it --- Assets/Art/GenericArtAssets.meta | 2 +- Assets/LayeredStaging.unity | 208 +++++++++++ .../SFX.meta => LayeredStaging.unity.meta} | 3 +- Assets/Scenes/Lemon_Test.unity | 7 +- Assets/ScriptableObjects.meta | 8 - Assets/Scripts/EntityScripts.meta | 8 - Assets/Scripts/GameManagerScripts.meta | 8 - Assets/Scripts/ScriptableObjectScripts.meta | 8 - Assets/Texel/Gameplay/GameBoard.cs | 340 +++++++++++++++++- Assets/Texel/Gameplay/GameBoardDrawer.cs | 129 ++++++- .../Texel/Gameplay/Staging/BoardStaging.unity | 7 + Assets/Texel/Resources/TileDrawer.prefab | 7 +- 12 files changed, 685 insertions(+), 50 deletions(-) create mode 100644 Assets/LayeredStaging.unity rename Assets/{Audio/SFX.meta => LayeredStaging.unity.meta} (67%) delete mode 100644 Assets/ScriptableObjects.meta delete mode 100644 Assets/Scripts/EntityScripts.meta delete mode 100644 Assets/Scripts/GameManagerScripts.meta delete mode 100644 Assets/Scripts/ScriptableObjectScripts.meta diff --git a/Assets/Art/GenericArtAssets.meta b/Assets/Art/GenericArtAssets.meta index 5470da1..88160de 100644 --- a/Assets/Art/GenericArtAssets.meta +++ b/Assets/Art/GenericArtAssets.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: a5a1671f2bf6f9341b8ec7fc994dcc9e +guid: 085f7e86b59eaf34e8904a7be40e68ad folderAsset: yes DefaultImporter: externalObjects: {} diff --git a/Assets/LayeredStaging.unity b/Assets/LayeredStaging.unity new file mode 100644 index 0000000..915f6cc --- /dev/null +++ b/Assets/LayeredStaging.unity @@ -0,0 +1,208 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!29 &1 +OcclusionCullingSettings: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_OcclusionBakeSettings: + smallestOccluder: 5 + smallestHole: 0.25 + backfaceThreshold: 100 + m_SceneGUID: 00000000000000000000000000000000 + m_OcclusionCullingData: {fileID: 0} +--- !u!104 &2 +RenderSettings: + m_ObjectHideFlags: 0 + serializedVersion: 9 + m_Fog: 0 + m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} + m_FogMode: 3 + m_FogDensity: 0.01 + m_LinearFogStart: 0 + m_LinearFogEnd: 300 + m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} + m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} + m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} + m_AmbientIntensity: 1 + m_AmbientMode: 3 + m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} + m_SkyboxMaterial: {fileID: 0} + m_HaloStrength: 0.5 + m_FlareStrength: 1 + m_FlareFadeSpeed: 3 + m_HaloTexture: {fileID: 0} + m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} + m_DefaultReflectionMode: 0 + m_DefaultReflectionResolution: 128 + m_ReflectionBounces: 1 + m_ReflectionIntensity: 1 + m_CustomReflection: {fileID: 0} + m_Sun: {fileID: 0} + m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} + m_UseRadianceAmbientProbe: 0 +--- !u!157 &3 +LightmapSettings: + m_ObjectHideFlags: 0 + serializedVersion: 11 + m_GIWorkflowMode: 1 + m_GISettings: + serializedVersion: 2 + m_BounceScale: 1 + m_IndirectOutputScale: 1 + m_AlbedoBoost: 1 + m_EnvironmentLightingMode: 0 + m_EnableBakedLightmaps: 0 + m_EnableRealtimeLightmaps: 0 + m_LightmapEditorSettings: + serializedVersion: 12 + m_Resolution: 2 + m_BakeResolution: 40 + m_AtlasSize: 1024 + m_AO: 0 + m_AOMaxDistance: 1 + m_CompAOExponent: 1 + m_CompAOExponentDirect: 0 + m_ExtractAmbientOcclusion: 0 + m_Padding: 2 + m_LightmapParameters: {fileID: 0} + m_LightmapsBakeMode: 1 + m_TextureCompression: 1 + m_FinalGather: 0 + m_FinalGatherFiltering: 1 + m_FinalGatherRayCount: 256 + m_ReflectionCompression: 2 + m_MixedBakeMode: 2 + m_BakeBackend: 1 + m_PVRSampling: 1 + m_PVRDirectSampleCount: 32 + m_PVRSampleCount: 512 + m_PVRBounces: 2 + m_PVREnvironmentSampleCount: 256 + m_PVREnvironmentReferencePointCount: 2048 + m_PVRFilteringMode: 1 + m_PVRDenoiserTypeDirect: 1 + m_PVRDenoiserTypeIndirect: 1 + m_PVRDenoiserTypeAO: 1 + m_PVRFilterTypeDirect: 0 + m_PVRFilterTypeIndirect: 0 + m_PVRFilterTypeAO: 0 + m_PVREnvironmentMIS: 1 + m_PVRCulling: 1 + m_PVRFilteringGaussRadiusDirect: 1 + m_PVRFilteringGaussRadiusIndirect: 5 + m_PVRFilteringGaussRadiusAO: 2 + m_PVRFilteringAtrousPositionSigmaDirect: 0.5 + m_PVRFilteringAtrousPositionSigmaIndirect: 2 + m_PVRFilteringAtrousPositionSigmaAO: 1 + m_ExportTrainingData: 0 + m_TrainingDataDestination: TrainingData + m_LightProbeSampleCountMultiplier: 4 + m_LightingDataAsset: {fileID: 0} + m_UseShadowmask: 1 +--- !u!196 &4 +NavMeshSettings: + serializedVersion: 2 + m_ObjectHideFlags: 0 + m_BuildSettings: + serializedVersion: 2 + agentTypeID: 0 + agentRadius: 0.5 + agentHeight: 2 + agentSlope: 45 + agentClimb: 0.4 + ledgeDropHeight: 0 + maxJumpAcrossDistance: 0 + minRegionArea: 2 + manualCellSize: 0 + cellSize: 0.16666667 + manualTileSize: 0 + tileSize: 256 + accuratePlacement: 0 + debug: + m_Flags: 0 + m_NavMeshData: {fileID: 0} +--- !u!1 &20737161 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 20737164} + - component: {fileID: 20737163} + - component: {fileID: 20737162} + m_Layer: 0 + m_Name: Testboard + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!114 &20737162 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20737161} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 30516090f4fb2954fba121c0dfdfe3ea, type: 3} + m_Name: + m_EditorClassIdentifier: + TilePrefab: {fileID: 6929433238081324627, guid: 2d35555d89dd5e94fb9527d52c616c11, + type: 3} + nextUI: {x: -1.3, y: 7, z: 0} + currentUI: {x: 6.3, y: 7, z: 0} + currentDrawers: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + nextDrawer: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + placementDrawer: + - {fileID: 0} + - {fileID: 0} + - {fileID: 0} + Cursor: {fileID: 21300000, guid: 2b4cf7a8a6d213a40a7b76c8f50678b4, type: 3} + TileSize: 1 +--- !u!114 &20737163 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20737161} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: d402e786b88425242825f7fe22d84afb, type: 3} + m_Name: + m_EditorClassIdentifier: + EntityID: 0 + authorityID: -1 + paused: 0 + controlledByPlayer: 1 + controlledByAI: 1 + CollapseCycleTime: 1.5 + cursorX: 3 + cursorY: 9 + comboDelay: 0 + collapseCount: 0 + Options: 05020304 +--- !u!4 &20737164 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 20737161} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -7.5, y: -5, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} diff --git a/Assets/Audio/SFX.meta b/Assets/LayeredStaging.unity.meta similarity index 67% rename from Assets/Audio/SFX.meta rename to Assets/LayeredStaging.unity.meta index 674af17..6a308c0 100644 --- a/Assets/Audio/SFX.meta +++ b/Assets/LayeredStaging.unity.meta @@ -1,6 +1,5 @@ fileFormatVersion: 2 -guid: 9583f386cfcb0aa489cef79c2fe974d0 -folderAsset: yes +guid: a2fb181b4f5a28c4fbfdff575a7c6f11 DefaultImporter: externalObjects: {} userData: diff --git a/Assets/Scenes/Lemon_Test.unity b/Assets/Scenes/Lemon_Test.unity index 07d65b9..825cf14 100644 --- a/Assets/Scenes/Lemon_Test.unity +++ b/Assets/Scenes/Lemon_Test.unity @@ -728,7 +728,7 @@ Transform: m_PrefabAsset: {fileID: 0} m_GameObject: {fileID: 2045221401} m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -10} + m_LocalPosition: {x: 0, y: 0, z: -16.78} m_LocalScale: {x: 1, y: 1, z: 1} m_Children: [] m_Father: {fileID: 0} @@ -1138,6 +1138,11 @@ PrefabInstance: propertyPath: m_IsActive value: 1 objectReference: {fileID: 0} + - target: {fileID: 7910694390442910741, guid: 55ee90197a494d54eb9b01aad0a7527e, + type: 3} + propertyPath: m_IsActive + value: 0 + objectReference: {fileID: 0} m_RemovedComponents: [] m_SourcePrefab: {fileID: 100100000, guid: 55ee90197a494d54eb9b01aad0a7527e, type: 3} --- !u!114 &7394357951300366995 stripped diff --git a/Assets/ScriptableObjects.meta b/Assets/ScriptableObjects.meta deleted file mode 100644 index 42c8dcd..0000000 --- a/Assets/ScriptableObjects.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 295ac802c88cd48448df9ecb56c7fb04 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/EntityScripts.meta b/Assets/Scripts/EntityScripts.meta deleted file mode 100644 index f410147..0000000 --- a/Assets/Scripts/EntityScripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: eb26112da6fce9c4ca2610cb953c66e6 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/GameManagerScripts.meta b/Assets/Scripts/GameManagerScripts.meta deleted file mode 100644 index 94c2b87..0000000 --- a/Assets/Scripts/GameManagerScripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: 7bdec22f29afa8245899160b77f09c8f -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Scripts/ScriptableObjectScripts.meta b/Assets/Scripts/ScriptableObjectScripts.meta deleted file mode 100644 index d95b53f..0000000 --- a/Assets/Scripts/ScriptableObjectScripts.meta +++ /dev/null @@ -1,8 +0,0 @@ -fileFormatVersion: 2 -guid: e8e3cbd1de7025044a7a92113d6e88f0 -folderAsset: yes -DefaultImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/Texel/Gameplay/GameBoard.cs b/Assets/Texel/Gameplay/GameBoard.cs index 9067ca8..8a2aa66 100644 --- a/Assets/Texel/Gameplay/GameBoard.cs +++ b/Assets/Texel/Gameplay/GameBoard.cs @@ -21,6 +21,189 @@ using Cluster = System.Collections.Generic.List<(int x, int y)>; public class GameBoard : EntityBase, IAutoSerialize, IAutoDeserialize { public BoardState board = new BoardState(); + [Header("Gameplay")] + public bool paused = false; + public bool controlledByPlayer = true; + public bool controlledByAI = true; + + public Move Current, Next; + + public Move Recommended; + + [Tooltip("Time it takes for the collapse to process")] + public float CollapseCycleTime = 1.5f; + + public int cursorX, cursorY; + + void Start() { + TestBoard(); + } + + void Update() { + UpdateControls(); + } + + [Header("Game State)"), ReadOnly] + public float comboDelay = 0; + [ReadOnly] + public float collapseCount; + + void UpdateControls() { + // Scan the board for tile activations + board = board.Activate(out int activations); + + if (activations > 0) { + if (comboDelay > 0) { + comboDelay -= Time.deltaTime; + + if (comboDelay <= 0) { + board = board.BreakPending(this, true); + board = board.Collapse(out _); + } + } else { + Collapse(); + comboDelay = 1.5f; // Half second combo delay + } + } else { + board = board.Collapse(out _); + + if (controlledByPlayer) { + PlayerControls(); + } + } + } + + public void MoveCursor(MoveDir d) { + var (dx,dy) = d.ToPair(); + cursorX += dx; + cursorY += dy; + + var clampX = Mathf.Clamp(cursorX, 0, BoardState.BoardWidth - 1); + var clampY = Mathf.Clamp(cursorY, BoardState.BoardHeight - 4, BoardState.BoardHeight - 2); + + if (cursorX != clampX) goto Invalid; + if (cursorY != clampY) goto Invalid; + + Current.location = (cursorX, cursorY); + + // Leave/pickup our motion chain + if (Current.first == d) { + Current.first = MoveDir.None; + } else { + if (Current.second == d && Current.first == MoveDir.None) { + Current.second = MoveDir.None; + } else { + Current.second = Current.first; + Current.first = d.Reverse(); + } + } + + Invalid: + cursorX = clampX; + cursorY = clampY; + } + + public bool Drop() { + // Don't allow drops while combo delay is going + if (comboDelay > 0) return false; + + bool valid = Current.isValid(board); + if (!valid) return false; + + board = board.Place(Current); + Current = Next; + Next = new Move().Set(Random,Random,Random); + + board = board.Collapse(out _); + return true; + } + + static bool AnyCode(params KeyCode[] kc) { + foreach (var code in kc) + if (Input.GetKeyDown(code)) return true; + return false; + } + + void PlayerControls() { + var intent = MoveDir.None; + + if (AnyCode(KeyCode.W,KeyCode.UpArrow)) + intent = MoveDir.Up; + if (AnyCode(KeyCode.A, KeyCode.LeftArrow)) + intent = MoveDir.Left; + if (AnyCode(KeyCode.S, KeyCode.DownArrow)) + intent = MoveDir.Down; + if (AnyCode(KeyCode.D, KeyCode.RightArrow)) + intent = MoveDir.Right; + + if (intent != MoveDir.None) + MoveCursor(intent); + + if (AnyCode(KeyCode.Space, KeyCode.KeypadEnter, KeyCode.Return)) { + Drop(); + } + } + + // AI Solver + [ContextMenu("Recommend Move")] + public void SolveRecommendedMove() { + // First, create the sim board + var simBoard = board.SelfCopy(); + + ValidateMoves(); + } + + static List PossibleMoves; + public static void ValidateMoves() { + if (PossibleMoves != null) return; + PossibleMoves = new List(); + + // Array of all possible movement direction sequences + (MoveDir a, MoveDir b)[] sequences = new[] { + (MoveDir.Down, MoveDir.Down), + (MoveDir.Down, MoveDir.Left), + (MoveDir.Down, MoveDir.Right), + (MoveDir.Up, MoveDir.Up), + (MoveDir.Up, MoveDir.Left), + (MoveDir.Up, MoveDir.Right), + (MoveDir.Right, MoveDir.Right), + (MoveDir.Right, MoveDir.Up), + (MoveDir.Right, MoveDir.Down), + (MoveDir.Left, MoveDir.Left), + (MoveDir.Left, MoveDir.Down), + (MoveDir.Left, MoveDir.Up)}; + + // Create a new empty board, then collapse to fill with iar + BoardState airBoard = new BoardState(); + airBoard = airBoard.Collapse(out _); + + // Just for fun :) + int considered = 0; + int ignored = 0; + + // 2D Loop over the top three board rows + for(int x = 0; x < BoardState.BoardWidth; ++x) + for (int y = BoardState.BoardHeight - 4; y < BoardState.BoardHeight - 1; ++y) { + // From this position, attempt each sequence + foreach(var s in sequences) { + considered += 1; + + var move = new Move { + location = (x, y), + first = s.a, + second = s.b + }; + + if (move.isValid(airBoard)) + PossibleMoves.Add(move); + else + ignored += 1; + } + } + + Debug.LogFormat("Possible Moves table built, Considered {0} (Ignored: {1})", considered, ignored); + } + GameBoardDrawer _drawer; public GameBoardDrawer drawer { get { @@ -37,11 +220,22 @@ public class GameBoard : EntityBase, IAutoSerialize, IAutoDeserialize { base.Serialize(h); if (h.TryGetValue('b', out var hashedBoard)) board = new BoardState((Hashtable)hashedBoard); + + if (h.TryGetValue('c', out var curArrayObject)) { + Current = Move.FromIntArray((int[])curArrayObject); + } + + if (h.TryGetValue('n', out var nxtArrayObject)) { + Next = Move.FromIntArray((int[])nxtArrayObject); + } } public override void Serialize(Hashtable h) { base.Serialize(h); h.Add('b', board.ToHashtable()); + + h.Add('c', Move.ToIntArray(Current)); + h.Add('n', Move.ToIntArray(Next)); } public TileColor[] Options; @@ -56,6 +250,14 @@ public class GameBoard : EntityBase, IAutoSerialize, IAutoDeserialize { for(int i = 0; i < BoardState.BoardWidth; ++i) { board[i] = new TileStack(new[] { Random, Random, Random, Random, Random, Random }); } + + Current = new Move(); + Current.triplet = (Random, Random, Random); + + Next = new Move(); + Next.triplet = (Random, Random, Random); + + Collapse(); } [ContextMenu("Test Board Serialization")] @@ -74,7 +276,7 @@ public class GameBoard : EntityBase, IAutoSerialize, IAutoDeserialize { public void BreakPending() => board = board.BreakPending(this, Application.isPlaying); [ContextMenu("Collapse")] - public void Collapse() => board = board.Collapse(); + public void Collapse() => board = board.Collapse(out _); } @@ -258,7 +460,6 @@ public static class BoardLogic { public static int TallestStack(this BoardState bs) => bs.state.Max(t => t.Count); - // Get a tile from a stack padded with nulls public static TileInfo NullPadded(this TileStack ts, int row) { if (row < 0) return null; @@ -417,8 +618,9 @@ public static class BoardLogic { return ClosedSet.Select(e => (x, e)).ToList(); } - public static BoardState Collapse(this BoardState bs) { + public static BoardState Collapse(this BoardState bs, out int remCount) { // TODO: Proper support for fairy blocks + remCount = 0; for (int x = 0; x < bs.state.Count; ++x) { var col = bs[x]; @@ -427,6 +629,8 @@ public static class BoardLogic { for (int i = 0; i < col.Count; ++i) { col[i] = col[i].SetFalling(foundAir); if (col[i].isAir) foundAir = true; + + //remCount += foundAir ? 1 : 0; } // First, pad to length with air @@ -436,12 +640,16 @@ public static class BoardLogic { // Create an unlinked copy var oldCol = col.Copy(); // Remove all air tiles - col.RemoveAll(t => t.isAir); + /*remCount += */col.RemoveAll(t => t.isAir); // Repad with air while (col.Count < BoardState.BoardHeight) col.Add(TileInfo.Air); - + + foreach(var elm in col) { + if (elm.detail.HasFlag(TileDetail.Dropped)) + remCount += 1; + } // TODO: Better falling logic // Set the falling flag for drawing @@ -458,11 +666,25 @@ public static class BoardLogic { var (first, second, third) = m.triplet; + var (x, y) = m.location; + //Debug.LogFormat("Placing at {0},{1}", x, y); + + var activeCol = state[x]; + activeCol[y] = first; + + (x, y) = m.locationB; + activeCol = state[x]; + activeCol[y] = second; + + (x, y) = m.locationC; + activeCol = state[x]; + activeCol[y] = third; + // FIXME SetAtPoint is shite and doesn't work good?? - state.SetAtPoint(m.location, first); - state.SetAtPoint(m.locationB, second); - state.SetAtPoint(m.locationC, third); + //state.SetAtPoint(m.location, first); + //state.SetAtPoint(m.locationB, second); + //state.SetAtPoint(m.locationC, third); return state; } @@ -507,13 +729,27 @@ public static class BoardLogic { continue; at.SetPending(); - activations += 1; // Increment the activation counter + //activations += 1; // Increment the activation counter } } + // Turns out, we need to know pending counts more + activations = CountPending(bs); + return bs; } + public static int CountPending(this BoardState bs) { + int pending = 0; + foreach(var col in bs.state) { + foreach (var elem in col) { + if (elem.isPending) + pending += 1; + } + } + return pending; + } + public static BoardState BreakPending(this BoardState bs, GameBoard gb, bool sendCallbacks = false) { var broken = new Cluster(); for(int x = 0; x < bs.state.Count; ++x) { @@ -552,7 +788,7 @@ public static class BoardLogic { // Iterations for the current step int stepActivations = 0; do { - bs = bs.Collapse().Activate(out stepActivations).BreakPending(gb); + bs = bs.Collapse(out _).Activate(out stepActivations).BreakPending(gb); activations += stepActivations; // Repeat until no new tiles activate Debug.LogFormat("Processed {0} activations", stepActivations); @@ -581,18 +817,71 @@ public static class BoardLogic { return (0, 0); } } + + public static MoveDir Reverse(this MoveDir md) { + switch(md) { + case MoveDir.Left: + return MoveDir.Right; + case MoveDir.Right: + return MoveDir.Left; + case MoveDir.Up: + return MoveDir.Down; + case MoveDir.Down: + return MoveDir.Up; + default: + return MoveDir.None; + } + } } #endregion #region moves -public enum MoveDir { None, Left, Right, Up, Down } +public enum MoveDir { None=0, Left, Right, Up, Down } public class Move { public (TileInfo first, TileInfo second, TileInfo third) triplet; public (int x, int y) location; + public Move Set(params TileInfo[] elements){ + triplet = (elements[0], elements[1], elements[2]); + return this; + } + + + public bool isValid(BoardState bs) { + // Check if current move is valid + if (this.first == MoveDir.None || this.second == MoveDir.None) + return false; + + var mX = BoardState.BoardWidth - 1; + var mY = BoardState.BoardHeight - 4; + + // Validate all the placement positions are in bounds + var locs = new[] { location, locationB, locationC }; + foreach(var loc in locs) { + if (loc.x < 0) return false; + if (loc.x > mX) return false; + if (loc.y < mY) return false; + if (loc.y > mY + 3) return false; + } + + // Validate that the board positions are empty + var at = bs.TileAtPoint(this.location); + if (!at.isAir) return false; + at = bs.TileAtPoint(this.locationB); + if (!at.isAir) return false; + at = bs.TileAtPoint(this.locationC); + if (!at.isAir) return false; + + return true; + } + + public void ClearMove() { + first = MoveDir.None; + second = MoveDir.None; + } public MoveDir first, second; public (int x, int y) locationB { @@ -608,6 +897,34 @@ public class Move { return (locationB.x + x, locationB.y + y); } } + + public static int[] ToIntArray(Move m) { + var ml = new int[7]; + ml[0] = m.triplet.first; + ml[1] = m.triplet.second; + ml[2] = m.triplet.third; + + ml[3] = (int)m.first; + ml[4] = (int)m.second; + + ml[5] = m.location.x; + ml[6] = m.location.y; + return ml; + } + + public static Move FromIntArray(int[] ia) { + var m = new Move(); + m.triplet.first = (TileInfo)ia[0]; + m.triplet.second = (TileInfo)ia[1]; + m.triplet.third = (TileInfo)ia[2]; + + m.first = (MoveDir)ia[3]; + m.second = (MoveDir)ia[4]; + + m.location = (ia[5], ia[6]); + + return m; + } } #endregion @@ -645,6 +962,7 @@ public class BoardState { return null; } + // This doesn't work for whatevre damn reason public void SetAtPoint((int x, int y) p, TileInfo tile) { if (TryCol(p.x, out var col)) { col.ChangeTile(p.x, tile); diff --git a/Assets/Texel/Gameplay/GameBoardDrawer.cs b/Assets/Texel/Gameplay/GameBoardDrawer.cs index a60b1ee..4eadda2 100644 --- a/Assets/Texel/Gameplay/GameBoardDrawer.cs +++ b/Assets/Texel/Gameplay/GameBoardDrawer.cs @@ -14,6 +14,110 @@ public class GameBoardDrawer : MonoBehaviour { return TilePrefab; } + public Move CurrentMove; + public Move NextMove; + + public Vector3 nextUI, currentUI; + + public List currentDrawers, nextDrawer, placementDrawer; + public void DrawMove() { + if (gameBoard.Current != null) { + var cur = gameBoard.Current; + var (first, second, third) = cur.triplet; + + currentDrawers[0].toDraw = first; + currentDrawers[1].toDraw = second; + currentDrawers[2].toDraw = third; + + for(int i = 0; i < 3; ++i) + currentDrawers[i].transform.localPosition = + Position(0, i) + currentUI; + + + placementDrawer[0].toDraw = first; + placementDrawer[1].toDraw = second; + placementDrawer[2].toDraw = third; + + var pla = placementDrawer[0].transform; + var plb = placementDrawer[1].transform; + var plc = placementDrawer[2].transform; + + var offset = Vector3.forward * -5f; + pla.localPosition = Position(gameBoard.cursorX, gameBoard.cursorY) + offset; + placementDrawer[0].opacity = 0.8f; + + var cx = gameBoard.cursorX; + var cy = gameBoard.cursorY; + + if (cur.first != MoveDir.None) { + placementDrawer[1].opacity = 0.8f; + + var (x,y) = cur.locationB; + plb.localPosition = Position(x, y) + offset; + } else { + placementDrawer[1].opacity = 0.5f; + // Draw the piece as a little floater + plb.localPosition = + Vector3.Lerp( + Position(cx, cy) + offset, + Position(cx, cy + 1) + (offset*0.9f), + 0.3f); + } + + if (cur.second != MoveDir.None) { + placementDrawer[2].opacity = 0.9f; + var (x, y) = cur.locationC; + + plc.localPosition = Position(x, y) + offset; + } else { + plc.localPosition = + Vector3.Lerp( + Position(cx, cy) + offset, + Position(cx, cy + 2) + (offset * 0.85f), + 0.3f); + + placementDrawer[2].opacity = 0.5f; + } + } + + if (gameBoard.Next != null) { + var tri = gameBoard.Next.triplet; + + nextDrawer[0].toDraw = tri.first; + nextDrawer[1].toDraw = tri.second; + nextDrawer[2].toDraw = tri.third; + + for (int i = 0; i < 3; ++i) + nextDrawer[i].transform.localPosition = + Position(0, i) + nextUI; + } + } + + public Sprite Cursor; + Transform _cursorObject; + public void UpdateCursor() { + if (_cursorObject) { + _cursorObject.localPosition = + Position(gameBoard.cursorX, gameBoard.cursorY) + + (Vector3.forward * -10); + return; + } + + var cgo = new GameObject("Cursor"); + cgo.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + _cursorObject = cgo.transform; + + _cursorObject.SetParent(transform, false); + + var src = cgo.AddComponent(); + src.sprite = Cursor; + + + src.sortingLayerID = TilePrefab.GetComponent().sortingLayerID; + + src.sortingOrder = 100; // Draw high up + } + // Cached reference to the gameboard GameBoard _gameBoard; public GameBoard gameBoard { @@ -49,6 +153,8 @@ public class GameBoardDrawer : MonoBehaviour { if (TileDrawers == null) { ClearDrawers(); + var flags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + Transform self = transform; // Cache // Setup the board // Board is arranged as a series of column 'stacks', bottom up @@ -58,7 +164,7 @@ public class GameBoardDrawer : MonoBehaviour { for (int y = 0; y < BoardState.BoardHeight; ++y) { var tile = Instantiate(TilePrefab,self); - tile.hideFlags = HideFlags.DontSaveInBuild | HideFlags.DontSaveInEditor; + tile.hideFlags = flags; // placement is handled in the update section //var tileT = tile.transform; //tileT.localPosition = new Vector3(x, y) * TileSize; @@ -67,6 +173,23 @@ public class GameBoardDrawer : MonoBehaviour { } TileDrawers.Add(col); } + + currentDrawers = new List(); + nextDrawer = new List(); + placementDrawer = new List(); + for(int i = 0; i < 3; ++i) { + var ctd = Instantiate(TilePrefab, self); + var ntd = Instantiate(TilePrefab, self); + var ptd = Instantiate(TilePrefab, self); + + ctd.hideFlags = flags; + ntd.hideFlags = flags; + ptd.hideFlags = flags; + + currentDrawers.Add(ctd.GetComponent()); + nextDrawer.Add(ntd.GetComponent()); + placementDrawer.Add(ptd.GetComponent()); + } } } @@ -132,5 +255,9 @@ public class GameBoardDrawer : MonoBehaviour { ValidateDrawers(); UpdateDrawers(); + + UpdateCursor(); + + DrawMove(); } } diff --git a/Assets/Texel/Gameplay/Staging/BoardStaging.unity b/Assets/Texel/Gameplay/Staging/BoardStaging.unity index 54ed46d..d68f0f4 100644 --- a/Assets/Texel/Gameplay/Staging/BoardStaging.unity +++ b/Assets/Texel/Gameplay/Staging/BoardStaging.unity @@ -153,6 +153,7 @@ MonoBehaviour: m_EditorClassIdentifier: TilePrefab: {fileID: 6929433238081324627, guid: 2d35555d89dd5e94fb9527d52c616c11, type: 3} + Cursor: {fileID: 21300000, guid: 2b4cf7a8a6d213a40a7b76c8f50678b4, type: 3} TileSize: 1 --- !u!114 &20737163 MonoBehaviour: @@ -168,6 +169,12 @@ MonoBehaviour: m_EditorClassIdentifier: EntityID: 0 authorityID: -1 + paused: 0 + controlledByPlayer: 1 + controlledByAI: 1 + CollapseCycleTime: 1.5 + cursorX: 3 + cursorY: 9 Options: 05020304 --- !u!4 &20737164 Transform: diff --git a/Assets/Texel/Resources/TileDrawer.prefab b/Assets/Texel/Resources/TileDrawer.prefab index e107550..b9d9530 100644 --- a/Assets/Texel/Resources/TileDrawer.prefab +++ b/Assets/Texel/Resources/TileDrawer.prefab @@ -47,6 +47,9 @@ MonoBehaviour: tsi: {fileID: 11400000, guid: 18b884ffdbcbecd489662f53d8e1b44d, type: 2} toDraw: data: 257 + board: {fileID: 0} + xCoord: 0 + yCoord: 0 detail: 1 color: 1 stackedBelow: 0 @@ -90,8 +93,8 @@ SpriteRenderer: m_AutoUVMaxDistance: 0.5 m_AutoUVMaxAngle: 89 m_LightmapParameters: {fileID: 0} - m_SortingLayerID: 0 - m_SortingLayer: 0 + m_SortingLayerID: 662872267 + m_SortingLayer: 4 m_SortingOrder: 0 m_Sprite: {fileID: -6936698821596298334, guid: ba7046a7d637abc4ba486e3e9e4fcfd3, type: 3}