Skip to content

Commit de60561

Browse files
committed
improved desert generator, fixed characters spawning in ground, fix movement speed bug, fix vision collider sizes on static entities
1 parent 19c758d commit de60561

File tree

16 files changed

+196
-71
lines changed

16 files changed

+196
-71
lines changed

Assets/Scripts/BlockmapFramework/Base/Def/DefOf/SurfaceDefOf.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ public static class SurfaceDefOf
1313
public static SurfaceDef Grass;
1414
public static SurfaceDef Sand;
1515
public static SurfaceDef SandSoft;
16+
public static SurfaceDef Sandstone;
1617
public static SurfaceDef Sidewalk;
1718
public static SurfaceDef Street;
1819
public static SurfaceDef Tiles;

Assets/Scripts/BlockmapFramework/Base/Def/EntityDef.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ public EntityDef(EntityDef orig)
112112
}
113113

114114

115+
public bool HasCompProperties<T>()
116+
{
117+
return Components != null && Components.Any(c => c is T);
118+
}
119+
115120
/// <summary>
116121
/// Retrieve specific CompProperties of this def. Throws an error if it doesn't have it.
117122
/// </summary>

Assets/Scripts/BlockmapFramework/Base/SaveLoadManager.cs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Collections;
33
using System.Collections.Generic;
44
using System.IO;
5+
using System.Linq;
56
using System.Reflection;
67
using System.Text;
78
using System.Xml;
@@ -335,6 +336,28 @@ public static void SaveOrLoadList<T>(ref List<T> list, string label) where T : c
335336
}
336337
}
337338

339+
/// <summary>
340+
/// Save and load a list.
341+
/// </summary>
342+
public static void SaveOrLoadStringHashSet(ref HashSet<string> list, string label)
343+
{
344+
if (IsSaving)
345+
{
346+
string saveText = "";
347+
foreach (string s in list) saveText += s + ",";
348+
saveText = saveText.TrimEnd(',');
349+
writer.WriteElementString(label, saveText);
350+
}
351+
else if (IsLoading)
352+
{
353+
if (reader.ReadToFollowing(label))
354+
{
355+
string value = reader.ReadElementContentAsString();
356+
list = value.Split(',').ToHashSet();
357+
}
358+
}
359+
}
360+
338361
/// <summary>
339362
/// Save and load an int-keyed dictionary with objects as values.
340363
/// </summary>

Assets/Scripts/BlockmapFramework/Base/World.cs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1255,9 +1255,6 @@ public bool CanSpawnEntity(EntityDef def, BlockmapNode node, Direction rotation,
12551255

12561256
return true;
12571257
}
1258-
/// <summary>
1259-
/// Creates a new entity from a def, registers it in the world and updates the world, navmesh and vision around it.
1260-
/// </summary>
12611258
public Entity SpawnEntity(EntityDef def, BlockmapNode node, Direction rotation, bool isMirrored, Actor actor, bool updateWorld, int height = -1, System.Action<Entity> preInit = null, int variantIndex = 0)
12621259
{
12631260
if (actor == null) throw new System.Exception("Cannot spawn an entity without an actor");
@@ -1462,7 +1459,6 @@ public void AddWaterBody(GroundNode sourceNode, int shoreHeight, bool updateWorl
14621459
((checkDir == Direction.None || checkDir == Direction.S) && (checkNode.Altitude[Direction.SW] < shoreHeight || checkNode.Altitude[Direction.SE] < shoreHeight)) ||
14631460
((checkDir == Direction.None || checkDir == Direction.W) && (checkNode.Altitude[Direction.SW] < shoreHeight || checkNode.Altitude[Direction.NW] < shoreHeight))
14641461
);
1465-
Debug.Log($"node at {checkNode.WorldCoordinates} would be underwater? {isUnderwater}. shore height is {shoreHeight}");
14661462
if (isUnderwater) // underwater
14671463
{
14681464
// Remove drowned entities
@@ -1483,7 +1479,6 @@ public void AddWaterBody(GroundNode sourceNode, int shoreHeight, bool updateWorl
14831479
else { } // above water
14841480
}
14851481

1486-
Debug.Log($"water body would have {waterBody.CoveredGroundNodes.Count} nodes.");
14871482
if (waterBody.CoveredGroundNodes.Count > 0) AddWaterBody(waterBody, updateWorld);
14881483

14891484
}

Assets/Scripts/BlockmapFramework/Defs/GlobalSurfaceDefs.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public static class GlobalSurfaceDefs
1919
DefName = "Grass",
2020
Label = "grass",
2121
Description = "Short grass",
22-
MovementSpeedModifier = 0.6f,
22+
MovementSpeedModifier = 0.65f,
2323
RenderProperties = new SurfaceRenderProperties()
2424
{
2525
Type = SurfaceRenderType.Default_Blend,
@@ -33,7 +33,7 @@ public static class GlobalSurfaceDefs
3333
DefName = "Sand",
3434
Label = "sand",
3535
Description = "Sand",
36-
MovementSpeedModifier = 0.4f,
36+
MovementSpeedModifier = 0.5f,
3737
RenderProperties = new SurfaceRenderProperties()
3838
{
3939
Type = SurfaceRenderType.Default_Blend,
@@ -47,7 +47,7 @@ public static class GlobalSurfaceDefs
4747
DefName = "SandSoft",
4848
Label = "soft sand",
4949
Description = "Soft sand",
50-
MovementSpeedModifier = 0.3f,
50+
MovementSpeedModifier = 0.4f,
5151
RenderProperties = new SurfaceRenderProperties()
5252
{
5353
Type = SurfaceRenderType.Default_Blend,
@@ -198,7 +198,7 @@ public static class GlobalSurfaceDefs
198198
DefName = "Sandstone",
199199
Label = "sandstone",
200200
Description = "",
201-
MovementSpeedModifier = 1f,
201+
MovementSpeedModifier = 0.9f,
202202
RenderProperties = new SurfaceRenderProperties()
203203
{
204204
Type = SurfaceRenderType.Default_Blend,

Assets/Scripts/BlockmapFramework/Entity/Entity.cs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -332,10 +332,8 @@ protected virtual void CreateVisionCollider()
332332

333333
if (Def.VisionColliderType == VisionColliderType.FullBox || (Def.VisionColliderType == VisionColliderType.EntityShape && Def.OverrideHeights.Count == 0)) // Create a single box collider with the bounds of the whole entity
334334
{
335-
if (MeshObject != null) VisionColliderObject.transform.localScale = MeshObject.transform.localScale;
336335
BoxCollider collider = VisionColliderObject.AddComponent<BoxCollider>();
337-
if (MeshObject != null) collider.size = new Vector3(Dimensions.x / MeshObject.transform.localScale.x, (Dimensions.y * World.NodeHeight) / MeshObject.transform.localScale.y, Dimensions.z / MeshObject.transform.localScale.z);
338-
else collider.size = new Vector3(Dimensions.x, (Dimensions.y * World.NodeHeight), Dimensions.z);
336+
collider.size = new Vector3(Dimensions.x, (Dimensions.y * World.NodeHeight), Dimensions.z);
339337
collider.center = new Vector3(0f, collider.size.y / 2, 0f);
340338

341339
WorldObjectCollider evc = VisionColliderObject.AddComponent<WorldObjectCollider>();

Assets/Scripts/BlockmapFramework/Entity/EntityManager.cs

Lines changed: 29 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -111,14 +111,27 @@ public static Vector3 GetWorldPosition(EntityDef def, World world, BlockmapNode
111111
if (occupiedNodes == null) return new Vector3(basePosition.x, originNode.BaseWorldAltitude, basePosition.y);
112112

113113
// Else calculate the exact y position
114-
// Identify the lowest node of all occupied nodes.
115-
float lowestY = occupiedNodes.Min(n => n.BaseWorldAltitude);
116-
List<BlockmapNode> lowestYNodes = occupiedNodes.Where(n => n.BaseWorldAltitude == lowestY).ToList();
117-
float y = lowestY;
114+
float y = 0;
115+
bool isInWater = false;
116+
117+
// For moving characters (always 1x1, just take the center world position of the node)
118+
if (def.HasCompProperties<CompProperties_Movement>())
119+
{
120+
y = occupiedNodes.First().MeshCenterWorldPosition.y;
121+
isInWater = occupiedNodes.First() is WaterNode;
122+
}
123+
124+
// For static objects the lowest node of all occupied nodes.
125+
else
126+
{
127+
float lowestY = occupiedNodes.Min(n => n.BaseWorldAltitude);
128+
List<BlockmapNode> lowestYNodes = occupiedNodes.Where(n => n.BaseWorldAltitude == lowestY).ToList();
129+
y = lowestY;
130+
isInWater = lowestYNodes.Any(n => n is WaterNode || (n is GroundNode ground && ground.WaterNode != null && ground.IsCenterUnderWater));
131+
}
118132

119133
// Move position halfway below water surface if required
120-
bool placementIsInWater = lowestYNodes.Any(n => n is WaterNode || (n is GroundNode ground && ground.WaterNode != null && ground.IsCenterUnderWater));
121-
if (placementIsInWater && def.WaterBehaviour == WaterBehaviour.HalfBelowWaterSurface)
134+
if (isInWater && def.WaterBehaviour == WaterBehaviour.HalfBelowWaterSurface)
122135
{
123136
y -= (entityHeight * World.NodeHeight) / 2;
124137
}
@@ -209,7 +222,7 @@ public static Vector2Int GetTranslatedPosition(Vector2Int position, Vector2Int d
209222
/// <summary>
210223
/// Spawns an entity on a random node near the given point and returns the entity instance.
211224
/// </summary>
212-
public static Entity SpawnEntityAround(World world, EntityDef def, Actor player, Vector2Int worldCoordinates, float standard_deviation, Direction forcedRotation = Direction.None, int maxAttempts = 1, int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null, string variantName = "", bool randomMirror = false)
225+
public static Entity SpawnEntityAround(World world, EntityDef def, Actor player, Vector2Int worldCoordinates, float standard_deviation, Direction forcedRotation = Direction.None, int maxAttempts = 1, int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null, string variantName = "", bool randomMirror = false, List<string> forbiddenTags = null)
213226
{
214227
if (standard_deviation == 0f) maxAttempts = 1;
215228
int numAttempts = 0;
@@ -220,7 +233,7 @@ public static Entity SpawnEntityAround(World world, EntityDef def, Actor player,
220233
Direction rotation = forcedRotation == Direction.None ? HelperFunctions.GetRandomSide() : forcedRotation;
221234
bool isMirrored = randomMirror ? Random.value < 0.5f : false;
222235

223-
Entity spawnedEntity = TrySpawnEntity(world, def, player, targetCoordinates, rotation, isMirrored, variantName, requiredRoamingArea, forbiddenNodes);
236+
Entity spawnedEntity = TrySpawnEntity(world, def, player, targetCoordinates, rotation, isMirrored, variantName, requiredRoamingArea, forbiddenNodes, forbiddenTags);
224237
if (spawnedEntity != null) return spawnedEntity;
225238
}
226239

@@ -231,7 +244,7 @@ public static Entity SpawnEntityAround(World world, EntityDef def, Actor player,
231244
/// <summary>
232245
/// Spawns an entity within a given area in the world and returns the entity instance.
233246
/// </summary>
234-
public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player, int minX, int maxX, int minY, int maxY, Direction forcedRotation = Direction.None, int maxAttempts = 1, int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null, string variantName = "", bool randomMirror = false)
247+
public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player, int minX, int maxX, int minY, int maxY, Direction forcedRotation = Direction.None, int maxAttempts = 1, int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null, string variantName = "", bool randomMirror = false, List<string> forbiddenTags = null)
235248
{
236249
int numAttempts = 0;
237250
while (numAttempts++ < maxAttempts) // Keep searching until we find a suitable position
@@ -240,7 +253,7 @@ public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player,
240253
Direction rotation = forcedRotation == Direction.None ? HelperFunctions.GetRandomSide() : forcedRotation;
241254
bool isMirrored = randomMirror ? Random.value < 0.5f : false;
242255

243-
Entity spawnedEntity = TrySpawnEntity(world, def, player, targetCoordinates, rotation, isMirrored, variantName, requiredRoamingArea, forbiddenNodes);
256+
Entity spawnedEntity = TrySpawnEntity(world, def, player, targetCoordinates, rotation, isMirrored, variantName, requiredRoamingArea, forbiddenNodes, forbiddenTags);
244257
if (spawnedEntity != null) return spawnedEntity;
245258
}
246259

@@ -251,12 +264,17 @@ public static Entity SpawnEntityWithin(World world, EntityDef def, Actor player,
251264
/// <summary>
252265
/// Tries spawning an entity on a random node on the given coordinates with all the given restrictions.
253266
/// <br/>Returns the entity instance if successful or null of not successful.
254-
private static Entity TrySpawnEntity(World world, EntityDef def, Actor player, Vector2Int worldCoordinates, Direction rotation, bool isMirrored, string variantName = "", int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null)
267+
private static Entity TrySpawnEntity(World world, EntityDef def, Actor player, Vector2Int worldCoordinates, Direction rotation, bool isMirrored, string variantName = "", int requiredRoamingArea = -1, List<BlockmapNode> forbiddenNodes = null, List<string> forbiddenTags = null)
255268
{
256269
if (!world.IsInWorld(worldCoordinates)) return null;
257270

258271
BlockmapNode targetNode = world.GetNodes(worldCoordinates).RandomElement();
259272
if (forbiddenNodes != null && forbiddenNodes.Contains(targetNode)) return null;
273+
if (forbiddenTags != null && targetNode.Tags.Any(t => forbiddenTags.Contains(t)))
274+
{
275+
Debug.Log($"Not spawning {def.LabelCap} on {targetNode} because it has a forbidden tag");
276+
return null;
277+
}
260278
if (!world.CanSpawnEntity(def, targetNode, rotation, isMirrored, forceHeadspaceRecalc: true)) return null;
261279

262280
int variantIndex = 0;

Assets/Scripts/BlockmapFramework/MapGeneration/TerrainFunctions.cs

Lines changed: 25 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,29 @@
11
using System.Collections;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using UnityEngine;
45

56
namespace BlockmapFramework.WorldGeneration
67
{
78
public static class TerrainFunctions
89
{
910

10-
public static void SmoothOutside(BlockmapNode node, int smoothStep, List<SurfaceDef> ignoredSurfaces = null) => SmoothOutside(node.World, new Parcel(node.World, node.WorldCoordinates, Vector2Int.one), smoothStep, ignoredSurfaces);
11+
public static void SmoothOutside(GroundNode node, int smoothStep, List<SurfaceDef> ignoredSurfaces = null, List<string> ignoredTags = null)
12+
{
13+
if (ignoredSurfaces != null && ignoredSurfaces.Contains(node.SurfaceDef)) return;
14+
if (ignoredTags != null && node.HasAnyOfTags(ignoredTags)) return; // Skip if node has an ignored tag
15+
if (ignoredTags != null && node.GetAdjacentGroundNodes8().Any(n => n.HasAnyOfTags(ignoredTags))) return; // Skip if any adjacent node has an ignored tag
16+
17+
SmoothOutside(node.World, new Parcel(node.World, node.WorldCoordinates, Vector2Int.one), smoothStep, ignoredSurfaces, ignoredTags);
18+
}
1119

1220
/// <summary>
1321
/// Smooths the ground area outside the given parcel so there are no hard edges around the parcel.
1422
/// <br/>Starts with the ring outside the parcel and then goes more and more outside until there are no gaps left.
1523
/// <br/>Smooth step defines the targeted steepness along the smoothed area.
1624
/// <br/>Returns the modified area as a new parcel.
1725
/// </summary>
18-
public static Parcel SmoothOutside(World world, Parcel parcel, int smoothStep = 1, List<SurfaceDef> ignoredSurfaces = null)
26+
public static Parcel SmoothOutside(World world, Parcel parcel, int smoothStep = 1, List<SurfaceDef> ignoredSurfaces = null, List<string> ignoredTags = null)
1927
{
2028
bool anotherLayerRequired;
2129

@@ -44,8 +52,8 @@ public static Parcel SmoothOutside(World world, Parcel parcel, int smoothStep =
4452

4553
Vector2Int worldCoords = new Vector2Int(x, y);
4654
GroundNode groundNode = world.GetGroundNode(worldCoords);
47-
if (groundNode == null) continue;
48-
if (ignoredSurfaces != null && ignoredSurfaces.Contains(groundNode.SurfaceDef)) continue;
55+
56+
if (ShouldSkip(groundNode, ignoredSurfaces, ignoredTags)) continue;
4957

5058
// East
5159
if (isEastEdge && !isSouthEdge && !isNorthEdge)
@@ -196,8 +204,8 @@ public static Parcel SmoothOutside(World world, Parcel parcel, int smoothStep =
196204

197205
Vector2Int worldCoords = new Vector2Int(x, y);
198206
GroundNode groundNode = world.GetGroundNode(worldCoords);
199-
if (groundNode == null) continue;
200-
if (ignoredSurfaces != null && ignoredSurfaces.Contains(groundNode.SurfaceDef)) continue;
207+
208+
if (ShouldSkip(groundNode, ignoredSurfaces, ignoredTags)) continue;
201209

202210
// SW
203211
if (isWestEdge && isSouthEdge)
@@ -325,5 +333,16 @@ public static Parcel SmoothOutside(World world, Parcel parcel, int smoothStep =
325333

326334
return new Parcel(world, new Vector2Int(startX - 1, startY - 1), new Vector2Int((endX - startX) + 2, (endY - startY) + 2));
327335
}
336+
337+
private static bool ShouldSkip(GroundNode node, List<SurfaceDef> ignoredSurfaces, List<string> ignoredTags)
338+
{
339+
if (node == null) return true;
340+
if (ignoredSurfaces != null && ignoredSurfaces.Contains(node.SurfaceDef)) return true; // Skip if nose has an ignored surface
341+
if (ignoredTags != null && node.HasAnyOfTags(ignoredTags)) return true; // Skip if node has an ignored tag
342+
if (ignoredTags != null && node.GetAdjacentGroundNodes8().Any(n => n.HasAnyOfTags(ignoredTags))) return true; // Skip if any adjacent node has an ignored tag
343+
344+
return false;
345+
}
346+
328347
}
329348
}

0 commit comments

Comments
 (0)