Skip to content

Commit

Permalink
Multiple tile objects on a single tile (RE-SS3D#1269)
Browse files Browse the repository at this point in the history
* add interface for different kind of tile location

* allow support multiple wall mounts

* simplify the loading of tile maps

* add polymorphic serialization

* using cysharp

* Fix removing multiple tile objects at once

* Adding doc

* remake field public

* some doc

* readd map

* some doc
  • Loading branch information
stilnat authored Nov 4, 2023
1 parent ebb74b2 commit a98d96f
Show file tree
Hide file tree
Showing 26 changed files with 613 additions and 175 deletions.
10 changes: 8 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,16 @@
!/Library/FishNet.Runtime.Editor.PrefabObjects.Generation.Settings.json
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/Game/*

/[Bb]uilds/*
!Builds/Game/

Builds/Game/*
!Builds/Game/Data/
!/[Bb]uilds/Game/Config/
!/[Bb]uilds/Game/BUILD_THE_GAME_HERE.txt


/[Ll]ogs/
/[Uu]ser[Ss]ettings/

Expand Down
74 changes: 43 additions & 31 deletions Assets/Scripts/SS3D/Systems/Tile/BuildChecker.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

Expand All @@ -16,42 +16,52 @@ public static class BuildChecker
/// <param name="tileObjectSo"></param>
/// <param name="replaceExisting"></param>
/// <returns></returns>
public static bool CanBuild(TileObject[] tileObjects, TileObjectSo tileObjectSo, Direction dir, PlacedTileObject[] adjacentObjects, bool replaceExisting)
public static bool CanBuild(ITileLocation[] tileLocations, TileObjectSo tileObjectSo, Direction dir, PlacedTileObject[] adjacentObjects, bool replaceExisting)
{
bool canBuild = true;

TileLayer placedLayer = tileObjectSo.layer;

// Cannot build if the layer is already occupied. Skip if we replace the existing object
if (!replaceExisting)
canBuild &= tileObjects[(int)placedLayer].IsEmpty;
canBuild &= tileLocations[(int)placedLayer].IsEmpty(dir);

// Cannot build anything unless a plenum is placed
if (placedLayer != TileLayer.Plenum)
canBuild &= CanBuildOnPlenum(tileObjects[(int)TileLayer.Plenum], tileObjectSo);
{
if (!(tileLocations[(int)TileLayer.Plenum] is SingleTileLocation))
{
Debug.LogError("Location on Plenum should be a Single object location");
return false;
}

canBuild &= CanBuildOnPlenum((SingleTileLocation) tileLocations[(int)TileLayer.Plenum]);
}


switch (placedLayer)
{
case TileLayer.WallMountHigh when canBuild:
case TileLayer.WallMountLow when canBuild:
{
canBuild &= CanBuildWallAttachment(tileObjects[(int)TileLayer.Turf], tileObjectSo, dir, adjacentObjects);
break;
}
{
canBuild &= CanBuildWallAttachment((SingleTileLocation) tileLocations[(int)TileLayer.Turf],
tileObjectSo, dir, adjacentObjects);
break;
}
// No furniture inside walls
case TileLayer.FurnitureBase:
case TileLayer.FurnitureTop:
{
canBuild &= !IsWall(tileObjects[(int)TileLayer.Turf]);
break;
}
{
canBuild &= !IsWall((SingleTileLocation) tileLocations[(int)TileLayer.Turf]);
break;
}
// No walls on furniture
case TileLayer.Turf when tileObjectSo.genericType == TileObjectGenericType.Wall:
{
canBuild &= tileObjects[(int)TileLayer.FurnitureBase].IsEmpty&&
tileObjects[(int)TileLayer.FurnitureTop].IsEmpty;
break;
}
{
canBuild &= tileLocations[(int)TileLayer.FurnitureBase].IsFullyEmpty() &&
tileLocations[(int)TileLayer.FurnitureTop].IsFullyEmpty();
break;
}
}

return canBuild;
Expand All @@ -76,21 +86,23 @@ private static bool CanBuildWallCollision(TileObjectSo tileObjectSo, Direction d
return canBuild;
}

private static bool IsWall(TileObject wallObject)
private static bool IsWall(SingleTileLocation wallLocation)
{
return !wallObject.IsEmpty&& wallObject.PlacedObject.GenericType == TileObjectGenericType.Wall;
return !wallLocation.IsEmpty() && wallLocation.PlacedObject.GenericType == TileObjectGenericType.Wall;
}

private static bool CanBuildWallAttachment(TileObject wallObject, TileObjectSo wallAttachment, Direction dir, PlacedTileObject[] adjacentObjects)
private static bool CanBuildWallAttachment(SingleTileLocation wallLocation, TileObjectSo wallAttachment, Direction dir, PlacedTileObject[] adjacentObjects)
{
bool canBuild = true;

// Cannot build when there isn't a wall
canBuild &= IsWall(wallObject);
canBuild &= IsWall(wallLocation);

// No low wall mounts on windows
if (!wallObject.IsEmpty)
canBuild &= !(wallObject.PlacedObject.NameString.Contains("window") && wallAttachment.layer == TileLayer.WallMountLow);
if (!wallLocation.IsEmpty(dir))
{
canBuild &= !(wallLocation.PlacedObject.NameString.Contains("window") && wallAttachment.layer == TileLayer.WallMountLow);
}

// Mounts cannot collide with neighbouring wall
canBuild &= CanBuildWallCollision(wallAttachment, dir, adjacentObjects);
Expand All @@ -99,14 +111,14 @@ private static bool CanBuildWallAttachment(TileObject wallObject, TileObjectSo w
return canBuild;
}

private static bool CanBuildOnPlenum(TileObject plenumObject, TileObjectSo plenumAttachment)
private static bool CanBuildOnPlenum(SingleTileLocation plenumLocation)
{
bool canBuild = true;

if (!plenumObject.IsEmpty)
if (!plenumLocation.IsEmpty())
{
// Can only build on a Plenum and not Catwalks or Lattices
canBuild &= plenumObject.PlacedObject.NameString.Contains("plenum") || plenumObject.PlacedObject.name.Contains("catwalk");
canBuild &= plenumLocation.PlacedObject.NameString.Contains("plenum") || plenumLocation.PlacedObject.name.Contains("catwalk");
}
else
{
Expand All @@ -122,12 +134,12 @@ private static bool CanBuildOnPlenum(TileObject plenumObject, TileObjectSo plenu
/// </summary>
/// <param name="tileObjects"></param>
/// <returns></returns>
public static List<TileObject> GetToBeDestroyedObjects(TileObject[] tileObjects)
public static List<ITileLocation> GetToBeClearedLocations(ITileLocation[] tileObjects)
{
List<TileObject> toBeDestroyedList = new List<TileObject>();
List<ITileLocation> toBeDestroyedList = new List<ITileLocation>();

// Remove everything when the plenum is missing
if (tileObjects[(int)TileLayer.Plenum].IsEmpty)
if (tileObjects[(int)TileLayer.Plenum].IsFullyEmpty())
{
for (int i = 1; i < tileObjects.Length; i++)
{
Expand All @@ -136,14 +148,14 @@ public static List<TileObject> GetToBeDestroyedObjects(TileObject[] tileObjects)
}

// Remove any wall fixtures when the turf is missing
else if (tileObjects[(int)TileLayer.Turf].IsEmpty)
else if (tileObjects[(int)TileLayer.Turf].IsFullyEmpty())
{
toBeDestroyedList.Add(tileObjects[(int)TileLayer.WallMountHigh]);
toBeDestroyedList.Add(tileObjects[(int)TileLayer.WallMountLow]);
}

// Remove furniture top is furniture base is missing
else if (tileObjects[(int)TileLayer.FurnitureBase].IsEmpty)
else if (tileObjects[(int)TileLayer.FurnitureBase].IsFullyEmpty())
toBeDestroyedList.Add(tileObjects[(int)TileLayer.FurnitureTop]);

return toBeDestroyedList;
Expand Down
131 changes: 131 additions & 0 deletions Assets/Scripts/SS3D/Systems/Tile/CardinalTileLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace SS3D.Systems.Tile
{
/// <summary>
/// Represent a Tile location able to contain up to 4 tile objects, in each cardinal directions.
/// </summary>
public class CardinalTileLocation : ITileLocation
{
private TileLayer _layer;
private int _x;
private int _y;

/// <summary>
/// the four potential placed tile objects. 0 is for north, 1 is for east, 2 for south, 3 for west.
/// </summary>
private PlacedTileObject[] _cardinalPlacedTileObject = new PlacedTileObject[4];

/// <summary>
/// The layer this location is on.
/// </summary>
public TileLayer Layer => _layer;

public CardinalTileLocation(TileLayer layer, int x, int y)
{
_layer = layer;
_x = x;
_y = y;
}

public void ClearAllPlacedObject()
{
for (int i = 0; i < 4; i++)
{
TryClearPlacedObject(IndexToDir(i));
}
}

public bool IsEmpty(Direction direction = Direction.North)
{
if (!TileHelper.IsCardinalDirection(direction))
{
return false;
}
return _cardinalPlacedTileObject[DirToIndex(direction)] == null;
}

public bool IsFullyEmpty()
{
return _cardinalPlacedTileObject.Where(x => x != null).Count() == 0;
}

public ISavedTileLocation Save()
{
List<SavedPlacedTileObject> savedTileObjects= new List<SavedPlacedTileObject>();
foreach(PlacedTileObject tileObject in _cardinalPlacedTileObject.Where(x => x != null))
{
savedTileObjects.Add(tileObject.Save());
}

return new SavedTileCardinalLocation(savedTileObjects, new Vector2Int(_x, _y), _layer);
}

public bool TryClearPlacedObject(Direction direction = Direction.North)
{
if (!TileHelper.IsCardinalDirection(direction))
{
return false;
}

PlacedTileObject placedObject = _cardinalPlacedTileObject[DirToIndex(direction)];
if (placedObject != null)
{
placedObject.DestroySelf();
placedObject = null;
return true;
}
return false;
}

public bool TryGetPlacedObject(out PlacedTileObject placedObject, Direction direction = Direction.North)
{
if (!TileHelper.IsCardinalDirection(direction))
{
placedObject = null;
return false;
}

PlacedTileObject currentPlacedObject = _cardinalPlacedTileObject[DirToIndex(direction)];
if (currentPlacedObject != null)
{
placedObject = currentPlacedObject;
return true;
}
placedObject = null;
return false;
}

public void AddPlacedObject(PlacedTileObject tileObject, Direction direction = Direction.North)
{
if (!TileHelper.CardinalDirections().Contains(direction))
{
return;
}
else
{
_cardinalPlacedTileObject[DirToIndex(direction)] = tileObject;
}
}

/// <summary>
/// Tie an index array to each cardinal direction.
/// </summary>
private int DirToIndex(Direction direction)
{
return (int)direction / 2;
}

/// <summary>
/// Tie an index array to each cardinal direction.
/// </summary>
private Direction IndexToDir(int i)
{
return (Direction) (i*2);
}
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/SS3D/Systems/Tile/CardinalTileLocation.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

24 changes: 24 additions & 0 deletions Assets/Scripts/SS3D/Systems/Tile/ISavedTileLocation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using SS3D.Systems.Tile;
using System.Collections.Generic;
using UnityEngine;

/// <summary>
/// Interface for saving tile locations.
/// Fields in classes implementing this interface should be public, at least the one that should be serialized.
/// </summary>
public interface ISavedTileLocation
{
public List<SavedPlacedTileObject> GetPlacedObjects();

public Vector2Int Location
{
get;
set;
}

public TileLayer Layer
{
get;
set;
}
}
11 changes: 11 additions & 0 deletions Assets/Scripts/SS3D/Systems/Tile/ISavedTileLocation.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit a98d96f

Please sign in to comment.