silverua / slay-the-spire-map-in-unity Goto Github PK
View Code? Open in Web Editor NEWImplementation of the Slay the Spire Map in Unity3d
License: MIT License
Implementation of the Slay the Spire Map in Unity3d
License: MIT License
Would you guys consider adding a round-style map? Imagine something like sectors on a galactic map, solar system, maelstrom, or anything where you would want a round map... like a 2D globe.
It appears that the package Newtonsoft.JSON for Unity no longer appears to be supported. Do you know if there is an alternative package that can be used?
Hello,
first thing first , Its a great tool for these kind of map generation .
Now, I just want to say that how can I generate the map layer one by one, like once user click(complete) a level/node then after completion only the next layer of map will get shown on the map and then after words it works like in same way till the boss stage.
I'm learning c# coding and I'm not good at English. Thanks for reading.
Hi,
Not sure if you wanted to add this as a feature, but I changed a line to allow the map to always be centred on the screen. MapView.cs, line 264. Might be worth adding it in as an option? Anyway, thought I'd send it on!
From:
firstParent.transform.localPosition += new Vector3(offset, -bossNode.transform.position.y, 0);
To:
firstParent.transform.position = new Vector3(-span/2, -bossNode.transform.position.y, 0);
Thanks,
Alan.
Trying to use Random.InitState(seed);
and i put it on top in the GenerateNewMap()
method but its still random each time i generate with the same seed.
Should i convert it all into System.Random instead?
I've imported the entire project package but I seem to be countering an issue with a missing Namespace
using OneLine;
More specifically it's causing issues with these lines of code:
[OneLineWithHeader]
public IntMinMax numOfPreBossNodes;
[OneLineWithHeader]
public IntMinMax numOfStartingNodes;
Am I missing a project file?
Hello I'm getting this error when i try to regenerate the map:
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.ThrowHelper.ThrowArgumentOutOfRangeException (System.ExceptionArgument argument, System.ExceptionResource resource) (at <437ba245d8404784b9fbab9b439ac908>:0)
System.ThrowHelper.ThrowArgumentOutOfRangeException () (at <437ba245d8404784b9fbab9b439ac908>:0)
System.Collections.Generic.List1[T].get_Item (System.Int32 index) (at <437ba245d8404784b9fbab9b439ac908>:0) Map.ShufflingExtension.Random[T] (System.Collections.Generic.IList
1[T] list) (at Assets/Scripts/ShufflingExtension.cs:29)
Map.MapGenerator.PlaceLayer (System.Int32 layerIndex) (at Assets/Scripts/MapGenerator.cs:77)
Map.MapGenerator.GetMap (Map.MapConfig conf) (at Assets/Scripts/MapGenerator.cs:33)
Map.MapManager.GenerateNewMap () (at Assets/Scripts/MapManager.cs:41)
Map.MapManagerInspector.OnInspectorGUI () (at Assets/Scripts/Editor/MapManagerInspector.cs:18)
UnityEditor.UIElements.InspectorElement+<>c__DisplayClass55_0.b__0 () (at <78f1ad0f25c84e3ca853e639f50d95f5>:0)
UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
I have added some new types of nodes and added to my MapConfig but I can't solve this problem.
Thanks.
Hey sorry if im missing something obvious here, but i've had a go at importing the UI map into one of my scenes, but its way too big!
If I adjust the scale or size of the Scroll View Horizontal / Viewport / Content in the editor, it messes up the placement of the nodes and lines:
If I do it at runtime after the map has already generated it's fine though.
Is there a recommended way of doing this in the editor or is it not currently supported?
Thanks for making and realeasing this btw!
In MapPlayerTracker I have Set up my nodes like this:
{
// we have access to blueprint name here as well
Debug.Log("Entering node: " + mapNode.Node.blueprintName + " of type: " + mapNode.Node.nodeType);
// load appropriate scene with context based on nodeType:
// or show appropriate GUI over the map:
// if you choose to show GUI in some of these cases, do not forget to set "Locked" in MapPlayerTracker back to false
switch (mapNode.Node.nodeType)
{
case NodeType.CommonEnemy:
// Load the scene or enable the UI game object for CommonEnemy
if (!string.IsNullOrEmpty(mapNode.Blueprint.sceneName))
SceneManager.LoadScene(mapNode.Blueprint.sceneName);
else if (mapNode.Blueprint.uiObject != null)
mapNode.Blueprint.uiObject.SetActive(true);
break;
case NodeType.MinorEnemy:
// Load the scene or enable the UI game object for MinorEnemy
if (!string.IsNullOrEmpty(mapNode.Blueprint.sceneName))
SceneManager.LoadScene(mapNode.Blueprint.sceneName);
else if (mapNode.Blueprint.uiObject != null)
mapNode.Blueprint.uiObject.SetActive(true);
break;
MapGenerator:
public static class MapGenerator
{
private static MapConfig config;
private static readonly List<NodeType> RandomNodes = new List<NodeType>
{
NodeType.CommonEnemy,
NodeType.MinorEnemy,
NodeType.EliteEnemy,
NodeType.RestSite,
NodeType.Treasure,
NodeType.Store,
NodeType.Mystery,
};
NodeBlueprint:
namespace Map
{
public enum NodeType
{
CommonEnemy,
MinorEnemy,
EliteEnemy,
RestSite,
Treasure,
Store,
Boss,
Mystery
}
}
For some reason, I continue to receive the error. Am I missing something?
ArgumentOutOfRangeException: Index was out of range. Must be non-negative and less than the size of the collection.
Parameter name: index
System.Collections.Generic.List`1[T].get_Item (System.Int32 index) (at <dc753a1061284f8e971ee88ee4826eee>:0)
Map.ShufflingExtension.Random[T] (System.Collections.Generic.IList`1[T] list) (at Assets/STSMap/Scripts/ShufflingExtension.cs:29)
Map.MapGenerator.PlaceLayer (System.Int32 layerIndex) (at Assets/STSMap/Scripts/MapGenerator.cs:84)
Map.MapGenerator.GetMap (Map.MapConfig conf) (at Assets/STSMap/Scripts/MapGenerator.cs:41)
Map.MapManager.GenerateNewMap () (at Assets/STSMap/Scripts/MapManager.cs:41)
UnityEngine.Events.InvokableCall.Invoke () (at <6f7018b8b8c149e68c4a65a05ac289be>:0)
UnityEngine.Events.UnityEvent.Invoke () (at <6f7018b8b8c149e68c4a65a05ac289be>:0)
UnityEngine.UI.Button.Press () (at ./Library/PackageCache/[email protected]/Runtime/UI/Core/Button.cs:70)
UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at ./Library/PackageCache/[email protected]/Runtime/UI/Core/Button.cs:114)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at ./Library/PackageCache/[email protected]/Runtime/EventSystem/ExecuteEvents.cs:57)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at ./Library/PackageCache/[email protected]/Runtime/EventSystem/ExecuteEvents.cs:272)
UnityEngine.EventSystems.EventSystem:Update() (at ./Library/PackageCache/[email protected]/Runtime/EventSystem/EventSystem.cs:530)
Why bother with both the node type and blueprint name, isn't a NodeBlueprint
sufficient?
Vector2Int
exists. If it didn't when you made this, that's understandable, but Unity added integer vectors and it makes things so much nicer not having to rebuild such a basic struct.
Re-type your extension to take in an IEnumerator<>
instead of a list and then you don't need to allocate memory for a new list that is immediately discarded. If you're going to take advantage of Linq, then make your Linq extensions compatible with Linq.
Ditto. Linq already has an IEnumerator.Last<>
slay-the-spire-map-in-unity/Assets/Scripts/MapView.cs
Lines 341 to 345 in f184b8c
Then you don't need this method either, as its only caller is the child class trying to get back the NodeBlueprint
reference you already had and didn't pass to the Node
constructor. I know you did this to make the class easy to serialize, but because you have the ability to lookup the NodeBlueprint reference by name, you can write a custom JsonConverter to do that during de/serialization; its pretty easy, example, albeit I need to rename it to Converter probably; lingering cruft from various refactors. And the bit that gets added to the JsonSettings, I'm using an attribute for my own classes, but the Unity classes I have to specify individually (and this might be why you made your own Point
class (cough, should've been a struct
and implemented the ==
operator), now that I think about it).
NodeType
isn't even referenced by anything anyway.
slay-the-spire-map-in-unity/Assets/Scripts/MapConfig.cs
Lines 21 to 27 in f184b8c
List<>
is sufficient here. Unity will already make the inspector wrap this in a ReorderableList
that allows it to be reordered.
IEnumerable<MapNodeType> RandomNodes = Enum.GetValues(typeof(MapNodeType)).Cast<MapNodeType>().Where(v => v != MapNodeType.Boss);
Bam. Make the code do that array for you. And not even bother making it a list, leave it as IEnumerable because of how you're using it:
slay-the-spire-map-in-unity/Assets/Scripts/MapGenerator.cs
Lines 274 to 277 in f184b8c
Replace with RandomNodes.Random()
slay-the-spire-map-in-unity/Assets/Scripts/MapGenerator.cs
Lines 187 to 196 in f184b8c
return config.GridWidth % 2 == 1 || Random.Range(0, 2) == 0
? new Vector2Int(config.GridWidth / 2, y)
: new Vector2Int(config.GridWidth / 2 - 1, y);
Couple other methods could be shortened similarly (like GetNode above it)
slay-the-spire-map-in-unity/Assets/Scripts/MapGenerator.cs
Lines 51 to 56 in f184b8c
This method can be written to cache the summed value in addition to the between value as such:
private static List<(float dist, float sum)> layerDistances = new List<(float, float)>();
//...
private static void GenerateLayerDistances(MapConfig config)
{
float totalDistance = 0;
layerDistances = new List<(float, float)>();
foreach (MapLayer layer in config.layers)
{
float nextDist = layer.distanceFromPreviousLayer.GetValue();
totalDistance += nextDist;
layerDistances.Add((nextDist, totalDistance));
}
}
//usage:
// layerDistances[layerIndex].dist - what layerDistances[layerIndex] previously held
// layerDistances[layerIndex].sum - what GetDistanceToLayer() returned
Rendering GetDistanceToLayer()
irrelevant and avoiding a repeated computation (layer x+1 will always be the total distance to x plus the spacing of x+1, so why compute x1, x2, x3, ..., x every time?). Anonymous tuples are fantastic.
slay-the-spire-map-in-unity/Assets/Scripts/MapGenerator.cs
Lines 117 to 118 in f184b8c
Per Microsoft's documentation on the usage of var you should not be using var here.
Don't use var when the type isn't apparent from the right side of the assignment. Don't assume the type is clear from a method name. A variable type is considered clear if it's a new operator, an explicit cast or assignment to a literal value.
I've actually seen that mistake result in a bug where the return type was a Dictionary<,>
of some kind and not a List<CustomObject>
(which was being returned by a rest API call) and the developer did a foreach over the contents and was comparing a searchKey
with the foreach_var.Key
value because the CustomObject
also had a Key
and Value
property. In a twist of irony I was fired for telling this developer (who was also the CEO) that I don't like var
because people don't use it correctly during casual conversation. He then linked the above documentation and I had to remind him of the bug he'd created because he'd used var incorrectly. He didn't like admitting he was wrong about anything.
This one might be a bit on the pedantic side, but the official coding convention exists, and I'd like people to actually follow it if they're going to use var. I only ever use var to avoid typing out a Type name but always do a replace-with-explicit refactor afterwards ([v][a][r][ctrl][.]
is fewer keystrokes than a lot of Type names).
Paths is only used by GeneratePaths
(as a return value) and SetUpConnections
(as a consumer). We can remove this static object allocation that lives forever and inline everything down to... foreach (List<Vector2Int> path in GeneratePaths(config))
We can also make the config
an object that's passed as a parameter to each function rather than storing a forever-reference to it as well as nodes
. Which makes GetNode a little funky, but we can turn that into an extension method super easily.
Is there a reason to pass this new empty list to the constructor rather than creating inside the constructor? It's used to hold the player's path through the map, so it doesn't seem like it should be created externally (or be both public
and not readonly
).
Aaaand that gets to a full refactor (albeit with a few renames, fekking hate it when Visual Studio imports random shit because of class names like Node
are used by dozens of packages).
Unity now supports the Newtonsoft JSON as a standalone package, and you can easily access it by following these instructions:
Visit the following link to access the Newtonsoft JSON package documentation: https://docs.unity3d.com/Packages/[email protected]/manual/index.html
Once you are on the page, you can learn more about the package and how to use it in your Unity projects.
To start using the package in your project, import it through the Package Manager. The package name is [email protected].
Only bringing it up as I wanted to remove the dependence on Analytics/In-app purchases packages.
Hi there,
I'm planning on using this map for a Twitch Chat Integrated game, was wondering what I could do to get access to the connecting nodes or if there is a way already,
And if there's a way to get the current node that I'm on.
Hey, me again. =)
How can I lock down the positioning of the parent window of the map? Ot keeps shifting all over and that is making it difficult to build the UI around it. It's probably something simple that I am not thinking of.
Hi Vladimir, thanks for creating this amazing asset!
I've been going through trying to fit it to my needs and found that the NumOfStartingNodes parameter does not consistently work to set the number of starting nodes to 1. I've tried going through the code to see what's going on and I have to admit the path generation logic flies completely over my head.
I'm not sure whether this is a bug or a feature, but I'd appreciate any tips you have on reducing the starting node count to 1.
Thanks
I got an error message when trying to open the project with the last Unity version:
Multiple precompiled assemblies with the same name Newtonsoft.Json.dll included or the current platform. Only one assembly with the same name is allowed per platform.
I tried to use that (since the error recommends it) but things stopped working. I am not a programmer. I use the AIs like Gemini and Bing Notepad (a new feature, if you haven't seen it, it is really nice.) Anyhow, the error:
Destroy may not be called from edit mode! Use DestroyImmediate instead.
Destroying an object in edit mode destroys it permanently.
UnityEngine.Object:Destroy (UnityEngine.Object)
Map.MapViewUI:ClearMap () (at Assets/STSMap/Scripts/MapViewUI.cs:35)
Map.MapView:ShowMap (Map.Map) (at Assets/STSMap/Scripts/MapView.cs:88)
Map.MapManager:GenerateNewMap () (at Assets/STSMap/Scripts/MapManager.cs:44)
Map.MapManagerInspector:OnInspectorGUI () (at Assets/STSMap/Scripts/Editor/MapManagerInspector.cs:18)
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)
Hello !
First of all, thank you for sharing your hard work !
I am not super strong at coding especially in C# ! :) I am tryning to implement a fog of war system that would hide the nodes after the next attainable ones.
I already coded something in the mapplayertracker + mapmanager to get the coordinates of the next attaible nodes each time the player moves. So basically i would like my sprite to translate with the player progress. I think that i have to work in the Mapview script to add the sprite.
But i don t understand how to modify the generated objects. For example, the background, i tested to make it appear in the front plan but i couldn t with the script. It works when i manually change the layer order during the run, but it is not what i want. If i understand this i think i can create my foreground but right now i can't...
Thanks !
Hi,
Thank you for sharing your code,
We wanted to generate similar map in our project and found this project but seems the path generation algorithm has some issues, the first one is that the generation can be failed after 100 attempts, also this attempts is not good from the performance point of view.
We designed an algorithm that resolves these issues.
Here is our algorithm:
Generate some random starting nodes.(same way you generate preBossPoints)
Generate some random ending nodes.
Connect these starting and ending points together by a random path.
Algorithm ends when all starting and ending points connected to each other.
The core point of the algorithm is that how to connect two predetermined nodes with random path.
We can generate candidate Xs such a way that the generated path finally land in specified location by imposing a simple rule.
The rule is that the horizontal distance of candidate position to ending node should be lesser or equal to the vertical distance of it to the ending node. In this way the points that the ending node is not reachable from will not be a valid candidate and will not contributed in random selection.
Our Path code is written with a simple for loop from the level of starting point to the level of ending point.
Hope this help you improve your code,
Good luck.
Hi mate, love you work.
I have imported the project as a package to my project but when i add the MapObjects to a new empty scene i get this error:
NullReferenceException: Object reference not set to an instance of an object
Map.MapNode.SetUp (Map.Node node, Map.NodeBlueprint blueprint) (at Assets/Scripts/MapNode.cs:37)
Map.MapView.CreateMapNode (Map.Node node) (at Assets/Scripts/MapView.cs:146)
Map.MapView.CreateNodes (System.Collections.Generic.IEnumerable`1[T] nodes) (at Assets/Scripts/MapView.cs:136)
Map.MapView.ShowMap (Map.Map m) (at Assets/Scripts/MapView.cs:88)
Map.MapManager.Start () (at Assets/Scripts/MapManager.cs:30)
Currently, an OuterMapParent is generated in the center of the scene on every launch. (Sorry for my mistake.)
However, I want to be able to generate and display only OuterMapParent on the Panel that can be prepared in advance.
Because OuterMapParent wants all the size and location of XYZ to depend on the parent UI Panel (I want it to fit the Panel size).
Hi!
Can I lead by saying I love this map and thank you for sharing it!
So, I'm having an issue when I build it for Windows and run the built file; it works fine in the editor. Seems to be related to json Serialize:
Any guidance would be great. Stacktrace below:
PlatformNotSupportedException: Operation is not supported on this platform.
at Newtonsoft.Json.Utilities.DynamicReflectionDelegateFactory.CreateDynamicMethod (System.String name, System.Type returnType, System.Type[] parameterTypes, System.Type owner) [0x00018] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Utilities.DynamicReflectionDelegateFactory.CreateParameterizedConstructor (System.Reflection.MethodBase method) [0x00029] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.JsonObjectContract.set_ParametrizedConstructor (System.Reflection.ConstructorInfo value) [0x00013] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateObjectContract (System.Type objectType) [0x000e5] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.DefaultContractResolver.CreateContract (System.Type objectType) [0x000e1] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.DefaultContractResolver.ResolveContract (System.Type type) [0x00038] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.GetContractSafe (System.Object value) [0x00016] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) [0x00028] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonSerializer.SerializeInternal (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) [0x00253] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonSerializer.Serialize (Newtonsoft.Json.JsonWriter jsonWriter, System.Object value, System.Type objectType) [0x00000] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonConvert.SerializeObjectInternal (System.Object value, System.Type type, Newtonsoft.Json.JsonSerializer jsonSerializer) [0x00028] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, System.Type type, Newtonsoft.Json.Formatting formatting, Newtonsoft.Json.JsonSerializerSettings settings) [0x0000e] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, Newtonsoft.Json.Formatting formatting, Newtonsoft.Json.JsonSerializerSettings settings) [0x00000] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Newtonsoft.Json.JsonConvert.SerializeObject (System.Object value, Newtonsoft.Json.Formatting formatting) [0x00000] in <97722d3abc9f4cf69f9e21e6770081b3>:0
at Map.Map.ToJson () [0x00000] in <967488ac67ea45468895b0576879d422>:0
at Map.MapManager.GenerateNewMap () [0x00013] in <967488ac67ea45468895b0576879d422>:0
at Map.MapManager.Start () [0x0006c] in <967488ac67ea45468895b0576879d422>:0
Hello,
Thank you for your work !
I just had an issue after importing this Asset Store Package which relies on Universal Render Pipeline and Shader Graph : the Scrolling Dotted Lines were not visible anymore.
I'm not used to unity shaders, URP or Shader Graph at all at the moment so I don't know if it's easiely solvable or not. I hope you have a better clue about this issue !
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.