From aad1ec4d0ff6061fd9af409a39ebe501548d6cc1 Mon Sep 17 00:00:00 2001 From: Moenenn Date: Wed, 11 Aug 2021 19:47:53 +0800 Subject: [PATCH] Battle Attacker AI First Finished --- Assets/Battle Soup AI/Core/Data.cs | 75 +++- Assets/Battle Soup AI/Core/SoupStrategy.cs | 130 ++++--- .../Core/SoupStrategy_Advanced.cs | 92 +++++ .../Battle Soup AI/Strategy/BattleAttacker.cs | 115 +++++- .../Battle Soup AI/Strategy/RevealAndSnipe.cs | 32 +- Assets/Battle Soup/Image/Game/Misc.png | Bin 4299 -> 4567 bytes Assets/Battle Soup/Image/Game/Misc.png.meta | 26 +- Assets/Battle Soup/Image/Game/UI.png | Bin 31770 -> 30828 bytes Assets/Battle Soup/Prefab/Ability Ship.prefab | 84 +++- Assets/Battle Soup/Scene/Main.unity | 364 +++++++++++++++++- Assets/Battle Soup/Script/Game/BattleSoup.cs | 6 + .../Battle Soup/Script/Game/BattleSoup_LGC.cs | 4 + Assets/Battle Soup/Script/Game/Game.cs | 5 + .../Battle Soup/Script/UI/BlocksRenderer.cs | 47 ++- .../Battle Soup/Script/UI/ShipPositionUI.cs | 2 +- 15 files changed, 847 insertions(+), 135 deletions(-) diff --git a/Assets/Battle Soup AI/Core/Data.cs b/Assets/Battle Soup AI/Core/Data.cs index 9b232ad..1e34fff 100644 --- a/Assets/Battle Soup AI/Core/Data.cs +++ b/Assets/Battle Soup AI/Core/Data.cs @@ -18,6 +18,77 @@ public Int2 (int x, int y) { this.x = x; this.y = y; } + public static Int2 operator + (Int2 a, Int2 b) { + a.x += b.x; + a.y += b.y; + return a; + } + public static Int2 operator - (Int2 a, Int2 b) { + a.x -= b.x; + a.y -= b.y; + return a; + } + public static Int2 operator * (Int2 a, Int2 b) { + a.x *= b.x; + a.y *= b.y; + return a; + } + public static Int2 operator / (Int2 a, Int2 b) { + a.x /= b.x; + a.y /= b.y; + return a; + } + public static Int2 operator * (Int2 a, int b) { + a.x *= b; + a.y *= b; + return a; + } + public static Int2 operator / (Int2 a, int b) { + a.x /= b; + a.y /= b; + return a; + } + public override string ToString () => $"({x},{y})"; + } + + + public struct Float2 { + public float x; + public float y; + public Float2 (float x, float y) { + this.x = x; + this.y = y; + } + public static Float2 operator + (Float2 a, Float2 b) { + a.x += b.x; + a.y += b.y; + return a; + } + public static Float2 operator - (Float2 a, Float2 b) { + a.x -= b.x; + a.y -= b.y; + return a; + } + public static Float2 operator * (Float2 a, Float2 b) { + a.x *= b.x; + a.y *= b.y; + return a; + } + public static Float2 operator / (Float2 a, Float2 b) { + a.x /= b.x; + a.y /= b.y; + return a; + } + public static Float2 operator * (Float2 a, float b) { + a.x *= b; + a.y *= b; + return a; + } + public static Float2 operator / (Float2 a, float b) { + a.x /= b; + a.y /= b; + return a; + } } @@ -250,7 +321,7 @@ public bool Symmetry { // API - public (Int2 min, Int2 max) GetBounds (ShipPosition pos) { + public (Int2 min, Int2 max) GetBounds (bool flip) { int minX = int.MaxValue; int minY = int.MaxValue; int maxX = int.MinValue; @@ -261,7 +332,7 @@ public bool Symmetry { maxX = System.Math.Max(maxX, v.x); maxY = System.Math.Max(maxY, v.y); } - return pos.Flip ? + return flip ? (new Int2(minY, minX), new Int2(maxY, maxX)) : (new Int2(minX, minY), new Int2(maxX, maxY)); } diff --git a/Assets/Battle Soup AI/Core/SoupStrategy.cs b/Assets/Battle Soup AI/Core/SoupStrategy.cs index fc4c530..14cf1e9 100644 --- a/Assets/Battle Soup AI/Core/SoupStrategy.cs +++ b/Assets/Battle Soup AI/Core/SoupStrategy.cs @@ -27,6 +27,8 @@ public int AliveShipCount { public int[] Cooldowns; public bool[] ShipsAlive; public ShipPosition?[] KnownPositions; + public List Sonars; + } @@ -82,7 +84,7 @@ public abstract class SoupStrategy { // Data private int[,] RIP_ValuesCache = null; private int[,,] RIP_ValuesCacheAlt = null; - private static System.Random Random = new System.Random(); + protected static System.Random Random = new System.Random(); #endregion @@ -163,7 +165,7 @@ public static bool PositionShips_Random (int mapSize, Ship[] ships, Int2[] stone // Func bool PositionAvailable (Ship _ship, ShipPosition _pos) { // Border Check - var (min, max) = _ship.GetBounds(_pos); + var (min, max) = _ship.GetBounds(_pos.Flip); if (_pos.Pivot.x < -min.x || _pos.Pivot.x > mapSize - max.x - 1 || _pos.Pivot.y < -min.y || _pos.Pivot.y > mapSize - max.y - 1 ) { @@ -520,66 +522,6 @@ int Exposure (Ship _ship, ShipPosition _sPos) { } - public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, out Int2 pos) => GetTileMVP(values, tiles, filter, Tile.None, out pos); - public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, Tile neighbourFilter, out Int2 pos) => GetTileMVP(values, tiles, filter, neighbourFilter, null, out pos); - public bool GetTileMVP (float[,,] values, Tile[,] tiles, Tile filter, Tile neighbourFilter, List attacks, out Int2 pos) { - int size = tiles.GetLength(0); - int valueIndex = values.GetLength(0) - 1; - bool hasAttacks = attacks != null && attacks.Count > 0; - float maxValue = 0; - bool success = false; - bool neighbour = neighbourFilter != Tile.None; - pos = default; - for (int j = 0; j < size; j++) { - for (int i = 0; i < size; i++) { - var tile = tiles[i, j]; - if (!filter.HasFlag(tile)) { continue; } - float value = GetValue(i, j); - if (value > maxValue || (value == maxValue && Random.NextDouble() > 0.66666f)) { - maxValue = value; - pos.x = i; - pos.y = j; - success = true; - } - } - } - return success; - // Func - float GetValue (int _i, int _j) { - float result = values[valueIndex, _i, _j]; - if (neighbour) { - if (!hasAttacks) { - // Default Cross - if (_i - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i - 1, _j])) { - result += values[valueIndex, _i - 1, _j]; - } - if (_j - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i, _j - 1])) { - result += values[valueIndex, _i, _j - 1]; - } - if (_i + 1 < size && neighbourFilter.HasFlag(tiles[_i + 1, _j])) { - result += values[valueIndex, _i + 1, _j]; - } - if (_j + 1 < size && neighbourFilter.HasFlag(tiles[_i, _j + 1])) { - result += values[valueIndex, _i, _j + 1]; - } - } else { - // Attacks - foreach (var att in attacks) { - if (att.Trigger == AttackTrigger.PassiveRandom || att.Trigger == AttackTrigger.Random) { continue; } - int _x = _i + att.X; - int _y = _j + att.Y; - if (_x < 0 || _x >= size || _y < 0 || _y >= size) { continue; } - var _tile = tiles[_x, _y]; - if (!att.AvailableTarget.HasFlag(_tile) || !neighbourFilter.HasFlag(_tile)) { continue; } - result += values[valueIndex, _x, _y]; - } - } - } - return result; - } - } - - public int GetShipWithMinimalPotentialPosCount (BattleInfo info, List[] hiddenPositions, List[] exposedPositions) => GetShipWithMinimalPotentialPosCount(info, hiddenPositions, exposedPositions, out _); @@ -728,6 +670,70 @@ public int CountNeighborTile (Tile[,] tiles, int x, int y, Tile filter) { } + public bool AveragePosition (Tile[,] tiles, Tile filter, out Float2 pos) { + Float2? resultPos = null; + int size = tiles.GetLength(0); + float count = 0f; + pos = default; + for (int j = 0; j < size; j++) { + for (int i = 0; i < size; i++) { + var tile = tiles[i, j]; + if (!filter.HasFlag(tile)) { continue; } + if (!resultPos.HasValue) { + resultPos = new Float2(i, j); + } else { + resultPos += new Float2(i, j); + } + count++; + } + } + if (resultPos.HasValue && count > 0) { + resultPos /= count; + pos = resultPos.Value; + return true; + } else { + return false; + } + } + + + public bool NearestPosition (Tile[,] tiles, int x, int y, Tile filter, out Int2 pos, out float sqrtDistance) { + pos = default; + sqrtDistance = float.MaxValue; + int size = tiles.GetLength(0); + bool success = false; + for (int j = 0; j < size; j++) { + for (int i = 0; i < size; i++) { + var tile = tiles[i, j]; + if (!filter.HasFlag(tile)) { continue; } + float a = System.Math.Abs(x - i); + float b = System.Math.Abs(y - j); + float sqrtDis = a * a + b * b; + if (sqrtDis < sqrtDistance) { + sqrtDistance = sqrtDis; + pos.x = i; + pos.y = j; + success = true; + } + } + } + return success; + } + + + public bool ContainsTile (Tile[,] tiles, Tile filter) { + int size = tiles.GetLength(0); + for (int j = 0; j < size; j++) { + for (int i = 0; i < size; i++) { + if (filter.HasFlag(tiles[i, j])) { + return true; + } + } + } + return false; + } + + #endregion diff --git a/Assets/Battle Soup AI/Core/SoupStrategy_Advanced.cs b/Assets/Battle Soup AI/Core/SoupStrategy_Advanced.cs index 1194abb..2e4d62a 100644 --- a/Assets/Battle Soup AI/Core/SoupStrategy_Advanced.cs +++ b/Assets/Battle Soup AI/Core/SoupStrategy_Advanced.cs @@ -6,6 +6,14 @@ namespace BattleSoupAI { public abstract class SoupStrategy_Advanced : SoupStrategy { + // SUB + public enum MVPConfig { + Hidden = 0, + Exposed = 1, + Both = 2, + } + + // Data protected int OwnAliveShipCount = 0; protected int OpponentAliveShipCount = 0; @@ -241,5 +249,89 @@ public bool TryAttackShip (BattleInfo info, int targetIndex, Tile filter, out In } + public bool GetTileMVP (Tile[,] tiles, Tile filter, MVPConfig config, out Int2 pos) => GetTileMVP(tiles, filter, Tile.None, config, out pos); + public bool GetTileMVP (Tile[,] tiles, Tile filter, Tile neighbourFilter, MVPConfig config, out Int2 pos) => GetTileMVP(tiles, filter, neighbourFilter, null, config, out pos, out _); + public bool GetTileMVP (Tile[,] tiles, Tile filter, Tile neighbourFilter, List attacks, MVPConfig config, out Int2 pos, out AbilityDirection direcion) { + var hdValues = HiddenValues; + var exValues = ExposedValues; + int size = tiles.GetLength(0); + int valueIndex = hdValues.GetLength(0) - 1; + bool hasAttacks = attacks != null && attacks.Count > 0; + float maxValue = 0; + bool success = false; + bool neighbour = neighbourFilter != Tile.None; + pos = default; + direcion = default; + for (int j = 0; j < size; j++) { + for (int i = 0; i < size; i++) { + var tile = tiles[i, j]; + if (!filter.HasFlag(tile)) { continue; } + float value = GetValue(i, j, out var _direcion); + if (value > maxValue || (value == maxValue && Random.NextDouble() > 0.66666f)) { + maxValue = value; + pos.x = i; + pos.y = j; + success = true; + direcion = _direcion; + } + } + } + return success; + // Func + float GetConfigValue (int _i, int _j) { + float result = 0f; + if (config == MVPConfig.Hidden || config == MVPConfig.Both) { + result += hdValues[valueIndex, _i, _j]; + } + if (config == MVPConfig.Exposed || config == MVPConfig.Both) { + result += exValues[valueIndex, _i, _j]; + } + return result; + } + float GetValue (int _i, int _j, out AbilityDirection _dir) { + _dir = default; + float result = GetConfigValue(_i, _j); + if (neighbour) { + if (!hasAttacks) { + // Default Cross + if (_i - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i - 1, _j])) { + result += GetConfigValue(_i - 1, _j); + } + if (_j - 1 >= 0 && neighbourFilter.HasFlag(tiles[_i, _j - 1])) { + result += GetConfigValue(_i, _j - 1); + } + if (_i + 1 < size && neighbourFilter.HasFlag(tiles[_i + 1, _j])) { + result += GetConfigValue(_i + 1, _j); + } + if (_j + 1 < size && neighbourFilter.HasFlag(tiles[_i, _j + 1])) { + result += GetConfigValue(_i, _j + 1); + } + } else { + // Attacks + float attResult = 0f; + for (int i = 0; i < 4; i++) { + float currentResult = 0; + var dir = (AbilityDirection)i; + foreach (var att in attacks) { + if (att.Trigger == AttackTrigger.PassiveRandom || att.Trigger == AttackTrigger.Random) { continue; } + var (_x, _y) = att.GetPosition(_i, _j, dir); + if (_x < 0 || _x >= size || _y < 0 || _y >= size) { continue; } + var _tile = tiles[_x, _y]; + if (!att.AvailableTarget.HasFlag(_tile) || !neighbourFilter.HasFlag(_tile)) { continue; } + currentResult += GetConfigValue(_x, _y); + } + if (currentResult > attResult) { + attResult = currentResult; + _dir = dir; + } + } + result += attResult; + } + } + return result; + } + } + + } } diff --git a/Assets/Battle Soup AI/Strategy/BattleAttacker.cs b/Assets/Battle Soup AI/Strategy/BattleAttacker.cs index e4da9dd..e6a188e 100644 --- a/Assets/Battle Soup AI/Strategy/BattleAttacker.cs +++ b/Assets/Battle Soup AI/Strategy/BattleAttacker.cs @@ -1,5 +1,6 @@ using System.Collections; using System.Collections.Generic; +using System.Linq; namespace BattleSoupAI { @@ -50,27 +51,129 @@ protected override string GetTask (BattleInfo info) { // LGC private AnalyseResult PerformTask_Search (BattleInfo info) { - var result = AnalyseResult.None; - if (TileCount_GeneralWater > (int)(info.MapSize * info.MapSize * 0.618f)) { - // Search with Sea Monster - } else { - // Search with + var result = AnalyseResult.None; + // Search with Sea Monster + if (SeaMonsterCooldown == 0 && TileCount_GeneralWater > (int)(info.MapSize * info.MapSize * 0.618f)) { + result.TargetPosition = default; + result.AbilityIndex = SEAMONSTER_INDEX; + return result; } + // Search with MiniSub + if (MiniSubCooldown == 0) { + + var disCheckFilter = Tile.HittedShip | Tile.RevealedShip | Tile.SunkShip; + bool success = false; + + if (ContainsTile(info.Tiles, disCheckFilter)) { + float maxDis = float.MinValue; + for (int i = 0; i < 4; i++) { + var checkingPos = new Int2( + i < 2 ? 0 : info.MapSize - 1, + i % 2 == 0 ? 0 : info.MapSize - 1 + ); + if ( + CheckCorner(checkingPos.x, checkingPos.y) && + NearestPosition(info.Tiles, checkingPos.x, checkingPos.y, disCheckFilter, out _, out var checkedDis) + ) { + if (checkedDis > maxDis) { + maxDis = checkedDis; + result.TargetPosition = checkingPos; + success = true; + } + } + } + } else { + var filter = Tile.GeneralWater | Tile.GeneralStone; + result.TargetPosition = + filter.HasFlag(info.Tiles[0, 0]) ? new Int2(0, 0) : + filter.HasFlag(info.Tiles[info.MapSize - 1, 0]) ? new Int2(info.MapSize - 1, 0) : + filter.HasFlag(info.Tiles[info.MapSize - 1, info.MapSize - 1]) ? new Int2(info.MapSize - 1, info.MapSize - 1) : + filter.HasFlag(info.Tiles[0, info.MapSize - 1]) ? new Int2(0, info.MapSize - 1) : + default; + success = true; + } + if (success) { + result.AbilityIndex = MINISUB_INDEX; + return result; + } + } + // Search with Normal Attack + var bestHiddenPos = HiddenValueMax[info.Ships.Length].pos; + if ( + info.Tiles[bestHiddenPos.x, bestHiddenPos.y] != Tile.GeneralWater && + !GetFirstTile(info.Tiles, Tile.GeneralWater | Tile.RevealedShip, out bestHiddenPos) + ) { + bestHiddenPos = default; + } + result.TargetPosition = bestHiddenPos; + result.AbilityIndex = -1; return result; + // Func + bool CheckCorner (int x, int y) => + (Tile.GeneralWater | Tile.GeneralStone | Tile.RevealedWater).HasFlag( + info.Tiles[x, y] + ) && !info.Sonars.Any(pos => pos.x == x && pos.y == y); } private AnalyseResult PerformTask_Attack (BattleInfo info) { - var result = AnalyseResult.None; + var result = AnalyseResult.None; + bool mustUseLongboat = UsingAbilityIndex == LONGBOAT_INDEX; + + if (mustUseLongboat || LongBoatCooldown == 0) { + // Attack with Longboat + if ( + TileCount_RevealedShip + TileCount_HittedShip > 0 && + GetTileMVP(info.Tiles, Tile.GeneralWater | Tile.RevealedShip, Tile.None, MVPConfig.Exposed, out var bestLongPos) + ) { + result.AbilityIndex = LONGBOAT_INDEX; + result.TargetPosition = bestLongPos; + return result; + } + } + if (SailBoatCooldown == 0) { + // Attack with Sailboat + var filter = Tile.GeneralWater | Tile.GeneralStone | Tile.RevealedShip; + if (GetTileMVP( + info.Tiles, filter, filter, info.Ships[SAILBOAT_INDEX].Ability.Attacks, + MVPConfig.Both, out var bestSailPos, out var bestDir + )) { + result.AbilityIndex = SAILBOAT_INDEX; + result.TargetPosition = bestSailPos; + result.AbilityDirection = bestDir; + return result; + } + } + // Attack with Normal Attack + if (TryAttackShip( + info, + ShipWithMinimalPotentialPos, + Tile.RevealedShip | Tile.GeneralWater, + out var attPos + )) { + result.TargetPosition = attPos; + result.AbilityIndex = -1; + return result; + } + // Fallback Attack + var bestHiddenPos = HiddenValueMax[info.Ships.Length].pos; + if ( + info.Tiles[bestHiddenPos.x, bestHiddenPos.y] != Tile.GeneralWater && + !GetFirstTile(info.Tiles, Tile.GeneralWater | Tile.RevealedShip, out bestHiddenPos) + ) { + bestHiddenPos = default; + } + result.AbilityIndex = -1; + result.TargetPosition = bestHiddenPos; return result; } diff --git a/Assets/Battle Soup AI/Strategy/RevealAndSnipe.cs b/Assets/Battle Soup AI/Strategy/RevealAndSnipe.cs index b5e9ffb..ba162f4 100644 --- a/Assets/Battle Soup AI/Strategy/RevealAndSnipe.cs +++ b/Assets/Battle Soup AI/Strategy/RevealAndSnipe.cs @@ -90,36 +90,32 @@ private AnalyseResult PerformTask_Search (BattleInfo info) { // Check for Ability if (WhaleCooldown == 0) { // Use Whale - if (GetTileMVP(HiddenValues, info.Tiles, Tile.All, Tile.All, out var bestWhalePos)) { + if (GetTileMVP(info.Tiles, Tile.All, Tile.All, MVPConfig.Hidden, out var bestWhalePos)) { result.TargetPosition = bestWhalePos; result.AbilityIndex = WHALE_INDEX; - LogMessage?.Invoke($"Search/Whale [{result}]"); } else { result.TargetPosition = bestHiddenPos; result.AbilityIndex = -1; - LogMessage?.Invoke($"Search/Normal(Whale Fail) [{result}]"); } } else if (SquidCooldown == 0 && TileCount_RevealedShip + TileCount_RevealedWater > 0) { // Use Squid - if (GetTileMVP(HiddenValues, info.Tiles, Tile.RevealedWater | Tile.RevealedShip, Tile.GeneralWater | Tile.RevealedShip, out var bestSquidPos)) { + if (GetTileMVP(info.Tiles, Tile.RevealedWater | Tile.RevealedShip, Tile.GeneralWater | Tile.RevealedShip, MVPConfig.Hidden, out var bestSquidPos)) { result.TargetPosition = bestSquidPos; result.AbilityIndex = SQUID_INDEX; - LogMessage?.Invoke($"Search/Squid [{result}]"); } else { result.TargetPosition = bestHiddenPos; result.AbilityIndex = -1; - LogMessage?.Invoke($"Search/Normal(Squid Fail) [{result}]"); } } else if (TurtleCooldown == 0) { // Use Turtle result.TargetPosition = bestHiddenPos; result.AbilityIndex = TURTLE_INDEX; - LogMessage?.Invoke($"Search/Turtle [{result}]"); + ////LogMessage?.Invoke($"Search/Turtle [{result}]"); } else { // Use Normal Attack result.TargetPosition = bestHiddenPos; result.AbilityIndex = -1; - LogMessage?.Invoke($"Search/Normal [{result}]"); + ////LogMessage?.Invoke($"Search/Normal [{result}]"); } @@ -143,32 +139,28 @@ private AnalyseResult PerformTask_Reveal (BattleInfo info) { // Check for Ability if (WhaleCooldown == 0) { // Use Whale - if (GetTileMVP(HiddenValues, info.Tiles, Tile.HittedShip, Tile.GeneralWater, out var bestWhalePos)) { + if (GetTileMVP(info.Tiles, Tile.HittedShip, Tile.GeneralWater, MVPConfig.Hidden, out var bestWhalePos)) { result.TargetPosition = bestWhalePos; result.AbilityIndex = WHALE_INDEX; - LogMessage?.Invoke($"Reveal/Whale [{result}]"); } else { - LogMessage?.Invoke("Reveal not performed."); return PerformTask_Attack(info); } } else if (SquidCooldown == 0 && TileCount_RevealedShip + TileCount_RevealedWater > 0) { // Use Squid - if (GetTileMVP(HiddenValues, info.Tiles, Tile.RevealedWater | Tile.RevealedShip, Tile.GeneralWater | Tile.RevealedShip, out var bestSquidPos)) { + if (GetTileMVP(info.Tiles, Tile.RevealedWater | Tile.RevealedShip, Tile.GeneralWater | Tile.RevealedShip, MVPConfig.Hidden, out var bestSquidPos)) { result.TargetPosition = bestSquidPos; result.AbilityIndex = SQUID_INDEX; - LogMessage?.Invoke($"Reveal/Squid [{result}]"); } else { - LogMessage?.Invoke("Reveal not performed."); return PerformTask_Attack(info); } } else if (TurtleCooldown == 0) { // Use Turtle result.TargetPosition = bestHiddenPos; result.AbilityIndex = TURTLE_INDEX; - LogMessage?.Invoke($"Reveal/Turtle [{result}]"); + //LogMessage?.Invoke($"Reveal/Turtle [{result}]"); } else { // Perform Attack - LogMessage?.Invoke("Reveal not performed."); + //LogMessage?.Invoke("Reveal not performed."); return PerformTask_Attack(info); } @@ -212,7 +204,7 @@ private AnalyseResult PerformTask_Attack (BattleInfo info) { if (minSlime < int.MaxValue && (OpponentAliveShipCount <= 2 || minSlime <= 2)) { result.TargetPosition = minPos; result.AbilityIndex = CORACLE_INDEX; - LogMessage?.Invoke($"Attack/Snipe [{result}]"); + //LogMessage?.Invoke($"Attack/Snipe [{result}]"); return result; } } @@ -227,7 +219,7 @@ out var tPos )) { result.TargetPosition = tPos; result.AbilityIndex = TURTLE_INDEX; - LogMessage?.Invoke($"Attack/Turtle [{result}]"); + //LogMessage?.Invoke($"Attack/Turtle [{result}]"); return result; } } @@ -241,14 +233,14 @@ out var attPos )) { result.TargetPosition = attPos; result.AbilityIndex = -1; - LogMessage?.Invoke($"Attack/Normal [{result}]"); + //LogMessage?.Invoke($"Attack/Normal [{result}]"); return result; } // Search with Normal result.TargetPosition = bestHiddenPos; result.AbilityIndex = -1; - LogMessage?.Invoke($"Search/Normal(Attack Failed) [{result}]"); + //LogMessage?.Invoke($"Search/Normal(Attack Failed) [{result}]"); return result; } diff --git a/Assets/Battle Soup/Image/Game/Misc.png b/Assets/Battle Soup/Image/Game/Misc.png index 3e11a49f4f8e7311e16af2b4d58ed1154a4a2588..d9d793d554a53a86093e6c83c5fa76e419e74ad3 100644 GIT binary patch delta 4361 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 diff --git a/Assets/Battle Soup/Image/Game/Misc.png.meta b/Assets/Battle Soup/Image/Game/Misc.png.meta index d216047..723ddb3 100644 --- a/Assets/Battle Soup/Image/Game/Misc.png.meta +++ b/Assets/Battle Soup/Image/Game/Misc.png.meta @@ -77,6 +77,9 @@ TextureImporter: - first: 213: -6064967667912391024 second: Sunk + - first: + 213: 4451419428445612202 + second: Shape externalObjects: {} serializedVersion: 11 mipmaps: @@ -279,7 +282,7 @@ TextureImporter: width: 56 height: 56 alignment: 0 - pivot: {x: 0, y: 0} + pivot: {x: 0.5, y: 0.5} border: {x: 0, y: 0, z: 0, w: 0} outline: [] physicsShape: [] @@ -291,6 +294,27 @@ TextureImporter: indices: edges: [] weights: [] + - serializedVersion: 2 + name: Shape + rect: + serializedVersion: 2 + x: 124 + y: 62 + width: 56 + height: 56 + alignment: 0 + pivot: {x: 0, y: 0} + border: {x: 0, y: 0, z: 0, w: 0} + outline: [] + physicsShape: [] + tessellationDetail: 0 + bones: [] + spriteID: aa8e5c2b26e96cd30800000000000000 + internalID: 4451419428445612202 + vertices: [] + indices: + edges: [] + weights: [] outline: [] physicsShape: [] bones: [] diff --git a/Assets/Battle Soup/Image/Game/UI.png b/Assets/Battle Soup/Image/Game/UI.png index d66c4e8da96ae6c33f16be038a4df154143a71a6..4362b1edcbf7110a5685d78236604ee72226f6e3 100644 GIT binary patch delta 11208 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 m`#q8q;7Lw$l9QZ7k6{83S6a+jX(ZoAm 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 ClearShipSelection(); + public void UI_Replay () { + CurrentState = GameState.Map; + UI_GotoNextState(); + } + + public void UI_QuitGame () { QuitGameForReal = true; Application.Quit(); diff --git a/Assets/Battle Soup/Script/Game/BattleSoup_LGC.cs b/Assets/Battle Soup/Script/Game/BattleSoup_LGC.cs index 5c43dbf..75d0a36 100644 --- a/Assets/Battle Soup/Script/Game/BattleSoup_LGC.cs +++ b/Assets/Battle Soup/Script/Game/BattleSoup_LGC.cs @@ -42,6 +42,7 @@ private void ReloadShipButtons () { grab.Grab("Label").text = ship.DisplayName; grab.Grab("Thumbnail").sprite = ship.Sprite; grab.Grab().Content = ship.Description; + grab.Grab("Shape").AddBody(ship); } // Final @@ -330,6 +331,8 @@ void DoAbilityUI (RectTransform container, Group group) { // Ability for (int i = 0; i < ships.Length; i++) { var ship = ships[i]; + + var grabber = Instantiate(m_Game.AbilityShip, container); var rt = grabber.transform as RectTransform; @@ -355,6 +358,7 @@ void DoAbilityUI (RectTransform container, Group group) { cooldown.gameObject.SetActive(ship.Ship.Ability.HasActive); cooldown.text = ship.Ship.Ability.Cooldown.ToString(); + grabber.Grab("Shape").AddBody(ship); grabber.Grab("Red Panel").gameObject.SetActive(false); grabber.Grab("Copy").gameObject.SetActive(false); grabber.Grab("Label").text = ship.DisplayName; diff --git a/Assets/Battle Soup/Script/Game/Game.cs b/Assets/Battle Soup/Script/Game/Game.cs index aa19bd6..19f0cad 100644 --- a/Assets/Battle Soup/Script/Game/Game.cs +++ b/Assets/Battle Soup/Script/Game/Game.cs @@ -160,6 +160,7 @@ private enum AttackResult { [SerializeField] Image m_Face = null; [SerializeField] Toggle m_CheatToggle = null; [SerializeField] Toggle m_DevToggle = null; + [SerializeField] Button m_ReplayButton = null; [SerializeField] Button m_AvAControlButton_Play = null; [SerializeField] Button m_AvAControlButton_Pause = null; [SerializeField] Button m_AvAControlButton_Next = null; @@ -381,6 +382,7 @@ public void Init (BattleMode battleMode, SoupStrategy strategyA, SoupStrategy st InfoA.Cooldowns = DataA.Cooldowns; InfoA.Tiles = DataA.Tiles; InfoA.KnownPositions = DataA.KnownPositions; + InfoA.Sonars = DataA.Sonars; InfoB.MapSize = DataB.Map.Size; InfoB.Ships = DataB.Ships; @@ -388,6 +390,7 @@ public void Init (BattleMode battleMode, SoupStrategy strategyA, SoupStrategy st InfoB.Cooldowns = DataB.Cooldowns; InfoB.Tiles = DataB.Tiles; InfoB.KnownPositions = DataB.KnownPositions; + InfoB.Sonars = DataB.Sonars; m_CheatToggle.SetIsOnWithoutNotify(false); m_DevToggle.SetIsOnWithoutNotify(false); @@ -398,6 +401,7 @@ public void Init (BattleMode battleMode, SoupStrategy strategyA, SoupStrategy st m_CheatToggle.gameObject.SetActive(true); m_DevToggle.gameObject.SetActive(true); + m_ReplayButton.gameObject.SetActive(false); AvA_Playing = false; AvA_GotoNext = false; @@ -605,6 +609,7 @@ private void SwitchTurn () { m_AvAControlButton_Play.gameObject.SetActive(false); m_AvAControlButton_Pause.gameObject.SetActive(false); m_AvAControlButton_Next.gameObject.SetActive(false); + m_ReplayButton.gameObject.SetActive(true); return; } diff --git a/Assets/Battle Soup/Script/UI/BlocksRenderer.cs b/Assets/Battle Soup/Script/UI/BlocksRenderer.cs index ea8b759..c1cc5af 100644 --- a/Assets/Battle Soup/Script/UI/BlocksRenderer.cs +++ b/Assets/Battle Soup/Script/UI/BlocksRenderer.cs @@ -172,6 +172,32 @@ void SetColor (Color color) { public void AddBlock (int x, int y, int id, Color color, float scale) => Blocks.Add(new Block(x, y, id, color, scale)); + public void AddBody (ShipData shipData) { + var (bodyMin, bodyMax) = shipData.Ship.GetBounds(false); + var bodySize = bodyMax - bodyMin; + bool flip = false; + if (bodySize.x > bodySize.y) { + (bodyMin, bodyMax) = shipData.Ship.GetBounds(true); + bodySize = bodyMax - bodyMin; + flip = true; + } + GridCountX = bodySize.x + 1; + GridCountY = bodySize.y + 1; + rectTransform.SetSizeWithCurrentAnchors( + RectTransform.Axis.Horizontal, + GridCountX * 12 + ); + rectTransform.SetSizeWithCurrentAnchors( + RectTransform.Axis.Vertical, + GridCountY * 12 + ); + ClearBlock(); + foreach (var v in shipData.Ship.Body) { + AddBlock(flip ? v.y : v.x, flip ? v.x : v.y, 0); + } + } + + public void ClearBlock () { if (Blocks.Count > 0) { Blocks.Clear(); @@ -187,27 +213,6 @@ public void ClearBlock () { - #region --- LGC --- - - - - - #endregion - - - - - #region --- UTL --- - - - - - #endregion - - - - - } } diff --git a/Assets/Battle Soup/Script/UI/ShipPositionUI.cs b/Assets/Battle Soup/Script/UI/ShipPositionUI.cs index 2ca449e..4fa8f23 100644 --- a/Assets/Battle Soup/Script/UI/ShipPositionUI.cs +++ b/Assets/Battle Soup/Script/UI/ShipPositionUI.cs @@ -245,7 +245,7 @@ private void ClampAllShipsInSoup () { for (int i = 0; i < _Ships.Length; i++) { var ship = _Ships[i]; var sPos = _Positions[i]; - var (min, max) = ship.Ship.GetBounds(sPos); + var (min, max) = ship.Ship.GetBounds(sPos.Flip); sPos.Pivot.x = Mathf.Clamp(sPos.Pivot.x, -min.x, mapSize - max.x - 1); sPos.Pivot.y = Mathf.Clamp(sPos.Pivot.y, -min.y, mapSize - max.y - 1); _Positions[i] = sPos;