silverua / slay-the-spire-map-in-unity

Implementation of the Slay the Spire Map in Unity3d
MIT License
273 stars 65 forks source link

Generate map layer one by one #6

Closed chouhandineshds closed 4 years ago

chouhandineshds commented 4 years ago

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.

silverua commented 4 years ago

Hello. Thanks for the kind words about the package. The way I would do this - I would still generate the entire map at once, then just show the nodes to the user selectively.

There would be a script, something like MapPresentation.cs with a method similar to ShowNodesThatPlayerIsSupposedToSee(). This method would be called right after the map gets shown in MapView.ShowMap(). The code in the method would deactivate all the elements of the map first (MapNodes, LineConnections).

Then it can go through all the elements again and activate them selectively based on the info that can be found in MapManager.CurrentMap.path. This list contains coordinates of all the nodes that the player has already visited. The last element in the list is the node where the player currently is. Based on this info you can activate all the nodes on previous layers and one layer after that.

chouhandineshds commented 4 years ago

Hello, Thanks @silverua for the help, I have done this by some other methods :P. I am sharing the screenshots of what is done.I intended to hide nodes and line connection both unless they are unlocked and after choosing a node then the sibling nodes should also gets hidden. One more thing,I'm the one that asked question about generating map from a single node via YouTube(if you remember LOL).I replaced the code with yours and no doubt that map is getting generated from single node but now there is no randomness in node count at each layer. Node count at each layer is equal to grid width now and is same through whole map.

Screenshot 2020-05-11 at 5 10 02 PM Screenshot 2020-05-11 at 5 10 14 PM Screenshot 2020-05-11 at 5 09 49 PM
chouhandineshds commented 4 years ago

Let me show you how map is looking now after generating map from single node.

Screenshot 2020-05-11 at 5 48 15 PM Screenshot 2020-05-11 at 5 48 24 PM Screenshot 2020-05-11 at 5 48 34 PM

What I need is each layer should have 3 or 4 nodes (50% chance for each), and every node should be link to every other nodes in next layer (for e.g. any node from previous layer should be linking to every node in next layer), can you help me with these ? Thanks

silverua commented 4 years ago

What you've described here is solved by making a bunch of modifications to MapGenerator. Basically, a custom MapGenerator implementation. It is quite different from what we did in this package because: you do not need to generate any paths, you do not need to remove cross nodes, your method SetUpConnections() will be different and much simpler. In MapGenerator.GetMap(): 1) The method PlaceLayer() should create either 3 or 4 nodes randomly for each layer, manually enforce 1 node on first and final layers. 2) You do not need to call GeneratePaths at all. You can delete this method. 3) SetUpConnections() should iterate through all the created nodes and manually connect each node to all the nodes on the next layer. There is no need to make any lookup in the paths list. You can just delete the paths list from the file completely. 4) You can delete the method RemoveCrossConnections() and you do not need call it at all.

I do not have the time to code and test all of this myself, but if you start coding this and run into any issues along the way, I'd be willing to take a look at the code.

chouhandineshds commented 4 years ago

Hello, I managed to connect each node to every other node.(see the images).I have done this from Path list in MapGenerator script, now my only problem is nodes at each layer are always equal to size for grid width in my case its 4. What I want is to generate 3 or 4 node randomly at each layer.Help me in this. Also I let the whole map generate from code only.I don't know how to do these thing manually.

Screenshot 2020-05-12 at 1 08 10 PM Screenshot 2020-05-12 at 1 08 20 PM

![Uploading Screenshot 2020-05-12 at 1.08.28 PM.png…]()

silverua commented 4 years ago

Nice. Maybe I picked the wrong word. By manually I meant hard - coded. You can achieve this by changing only your method SetUpConnections(). Because we have this code in GetMap():

// select all the nodes with connections:
var nodesList = nodes.SelectMany(n => n).Where(n => n.incoming.Count > 0 || n.outgoing.Count > 0).ToList();

and all the nodes that do not have connections are ignored.

So, you always have a grid of nodes with a constant width. That's what we start with after we place the nodes. Your code in the SetUpConnections() method should be similar to this (just the general idea):

// iterate through all the map layers:
for (var i = 0; i< nodes.Count - 1; i++)
{
    var nodesOnThisLayer = nodes[i];
    var nodesOnNextLayer = nodes[i+1];

    // first layer: 
    if(i == 0)
    {
        // select only one node in nodesOnThisLayer
        // select 3 to 5 random nodes in nodesOnNextLayer
        // connect your one node on 1st layer to selected nodes on 2nd layer
    }
    // boss node:
    else if (i == nodes.Count - 2)
    {
         // select only one node in nodesOnNextLayer
         // select nodes in nodesOnThisLayer that have incoming connections with Linq.
         // connect each of the nodes with incoming connections from nodesOnThisLayer
         // with one node that you have randomly selected from nodesOnNextLayer
    }
    // any other case:
    else 
    { 
         // select nodes in nodesOnThisLayer that have incoming connections with Linq.
         // select 3 to 5 random nodes in nodesOnNextLayer
         // connect each of the selected nodes from this layer 
         // to each of the selected nodes on the next layer
    }
}

And done. Only the nodes that you have selected will have connections, which means that only they will be shown on the map. And you have coded all your rules: 1) 1 node on 1st and last layer will have connections. 2) 3 to 5 nodes on each layer will have connections. And the line that I mentioned above will make sure that only nodes with connections will be saved into your Map object.

chouhandineshds commented 4 years ago

Hello, Thanks for the guidance, let me try it. Also i want to tell you that I'm generating complete map at once and afterwords I hide the node which are locked.So I think GeneratePaths() should be called and yeah I commented RandomizeNodePositions() method.

chouhandineshds commented 4 years ago

Hello, Truly speaking ,I'm trying really hard but all this is going over my head. Can you help me in this please. What I really want is

  1. Map should start with single node. (done)
  2. After then every map layer may have 3 to 4 nodes
  3. Boss node will be single node (done)
  4. Each and every node should connect with next layer nodes and so on (done) I have connected all nodes by doing this in Path list (please check this image) Screenshot 2020-05-12 at 4 25 52 PM

(forget about what I had mention earlier that map should generate one by one - this I will take care afterwords)

chouhandineshds commented 4 years ago

Hello, Thanks for the help mate. I tried your given code idea in SetUpConnections() method and put my head into it and at last I have done it. Map is now generating as desired. Many Thanks Again. KEEP DOING GOOD WORK.

silverua commented 4 years ago

Glad that you got it working! Thanks for letting me know.