Contact Info / Websites
This article continues on our previous article (which can be seen here: http://duckbridge.newgrounds.com/news/post/900053). I recommend that you check that one out before this one, because it goes over the general idea of our spawning system for 15min Max (http://www.newgrounds.com/portal/view/641800).
(I do recommend checking out the first article and the game, so that you can get a general idea of the spawning system)
In this article I will talk more in-depth about our spawning system and provide some (pseudo) code with explanations to give you an idea of how it was implemented, the pseudo code given is not all the code, but it is the code that is more or less needed to get this to work.
So as I mentioned in part 1 there are three spawners; the base spawner, the normal spawner and the override spawner. I’ll start with the base spawner, this spawner serves as a base class for the other spawners (normal & override).
(For those who don’t know : the list with all the rooms is public because we use Unity, and Unity allows you to fill the objects in the list from the editor.)
This class is the Spawner class, and is the base class for the spawner(s) in our game, many of the functions are virtual because that allows the sub-classes to override them (but I will get into that later).
The interesting part of this class is the Spawn function; the Spawn is the only function that is not virtual. This is because the spawning should work the same for all spawners. Only some details of the spawning can be tweaked (hence the virtual GetRandomRoomType and FindRoomForRoomType).
But what the Spawn function actually does is, it uses the two functions to find a random RoomType and use that RoomType to find a Room object that belongs to it.
If (for some reason) a Room cannot be found with that room type by using the FindRoomForType then it just tries all the rooms and tries to find one that matches (this was very usefull during development because we didn’t have all rooms and stuff).
After it finds the room it basically spawns the room inside the game and it unloads old rooms.
The Room class is the class that belongs to all the rooms that Max runs through in 15minMax. The class itself is actually quite simple. It does contains some variables which are used by the sub-spawners so I’ll go over the Room class now.
You can see that the roomLevel for each Room can be set in the editor but also the score that they require to be spawnable.
The most interesting parts of this class are the OnRoomEntered() and OnPlayerExittedDoor() functions (these allow for custom behaviour (because they call the ExtraOnExit/Enter functions, which are virtual) . One way we use this is to control the behaviour of the clicking in each Room.
So now on to the first spawner, the ‘normal’ spawner, this spawner is the spawner that is used in the game (when we’re not testing). This class is a bit bigger so it will be exlained in parts.
The Normal Spawner can be seen above and the FindRoomForRoomType function is overriden and finds the score for the roomType that is given (You can implement this any way you’d like, we use the ‘RoomTypeManager’).
After we found the Room with that RoomType use the LinQ funciton of C# to find a Room within the list of allRooms with the same RoomType and a requiredScore higher than the room.minimumScoreRequired and lower than the room.maximumScoreRequired.
The GetRandomRoomType function is a bit more complex (or messy ha^^), but it does some interesting stuff.
At first we use the chooseRoomTypeThatStillNeedsToBeUnlocked to randomize the choice to:
* return a random room type that we have already unlocked
* return the newlyUnlockedRoomType, which is a new RoomType which has not been unlocked yet.This value is set somewhere else, we’ll get into that soon.
* return a random roomType which is already unlocked, if the randomRoomType is stil not set (which can happen when the spawner wants to spawn a newlyUnlockedRoomType but it has not been set. (a.k.a bugfix)
The last function of the NormalSpawner is the OnRoomExitted function, which is called when a room is exitted. The OnRoomExitted function is quite tricky/long so I’ll try to go over it as good as possible.
At first the RoomType that has just been exitted is removed from the Rooms that still need to be unlocked (remember the ‘unlocking system’ from part 1?).
All the Rooms that need to be unlocked are removed from the roomTypesLeft list untill there no roomTypesLeft left.
When that happens all the RoomTypes that are already unlocked are removed from list with the RoomTypes that still need to be unlocked.
Then if there are RoomTypes left in the roomTypesLeft list, then a new roomType is randomly chosen between them, otherwise a random room type is just selected.
If the chosenRandomRoomType is not unlocked already (so it’s a new RoomType that the player has not seen yet). Then the newlyUnlockedRoomType (which is used in the GetRandomRoomType() ) and that’s it.
(Maybe the code explains it better than words ^^)
So the last component is the Override Spawner which is used during testing to allow us to specify which roomType we want to spawn and from which roomLevel we would like it to start spawning.
And after seeing the code for this you can see that the two virtual functions are very usefull and allow for many different spawning behaviours (Without changing the core implementation).
Anways, this is how the override spawner looks:
You can see that this spawner is very small in comparison to the Normal Spawner, the reason for this is quite simple, because we provide the roomLevelToOverride and randomRoomTypeToOverride through the editor. (Because we already know what we want to spawn, so we don’t need any crazy behaviour for that)
And this made testing SO MUCH EASIER and you can see that the code change is very minimal. And this is how it looks in the editor.
So that’s it! I hope you learned something and can use some of the techniques we applied for our spawner for your own spawner!
I guess that the best part of the Spawner is that the Spawn() function is very core to the Spawner but its behaviour can be tweaked without chaning the core implementation! This will allow for many different kind of spawners and just subclass Spawner and code the functions correctly! (And then you could have some ‘SpawnManager’ which swaps between Spawners and stuff.
Well that’s it! Thanks for reading and if you have any questions/comments, just post them in the comments below, contact us at duckbridge.dev[@]gmail.com or tweet at us : @Duckbridge. (We also have facebook^^)
PS: We’ll release the game to mobile soon, so follow us to stay updated!
A spawning system that keeps our game interesting [p1]
For those who have played 15 min Max (http://www.newgrounds.com/portal/view/641800) will be aware that the rooms in the game are spawned randomly, however, this is not entirely true.
The spawning system for the rooms in 15min Max is a bit more complicated! The spawning system for 15min Max works by unlocking room types, this is done so that the player has to pass certain room types in order to play others. This was also done to make it easier for the player to get used to the room types.
In this blog post I will go over the spawner and in the second part I will also provide some (pseudo) code for the spawner and discuss it.
Unlocking room Types
With 15min Max we wanted to have a ‘random’ spawner for the rooms, but not entirely random, we wanted to have some kind of system in which you had to ‘unlock’ room Types in order to get other types.
What is meant by this is, in 15min Max, when you play for the first time, the only room types that can spawn are the‘JumpRoom’ & the ‘SlideRoom’. And after compleing both of them, you can unlock a new (random) roomType. This is more clearly explained in the image below.
And after you have unlocked a (new) room type, the spawner can spawn a room randomly within the unlocked room types. So at the start the spawner can pick between Jump & Slide, after that between Jump & Slide & Drop (for example) and so forth.
So besides that we have the unlocking system, we also have different ‘levels’ for rooms. This is done to keep the game interesting and to give the player a good challenge. So the way that the room levels work is that; each room has a ‘minimum room score required’ and a ‘maximum room score required’. The ‘room’ score is the amount of times that that room type has been finished by max.
So for example: Jump room level 1 could have a minimum score of 0 and a maximum of 2. So then when you manage to finish Jump room 2 times, your score for the Jump room will be 2. Then when the spawner wants to spawn a Jump room, it should spawn Jump room level 2, which has a minimum score of 2 and a maximum of 4, because you then have a score of 2 on the Jump room.
But for the other room types, your score could still be 0, so that means that the spawner will only spawn a level 2 room for Jump, but not for Slide, Drop & others.
We also have an additional manual ‘level’ setting for the rooms. But I’ll get into that later.
The ‘Override’ Spawner
Eventhough that the current spawning behaviour seemed to work pretty well, there was another problem. It was really hard to test certain rooms (for example if we wanted to test Jump 4 how would we ever do that?). So in order to solve this problem we made an additional spawner, which has the same basic behaviour of the original spawner but some behaviour is overwritten.
So that means we have three spawners; one base spawner, one normal spawner which overrides some behaviour of the base spawner and one override spawner which overrides some behaviour of the base spawner.
And the override spawner does the same as the normal spawner, but then you can select which ‘room type’ you would like to spawn and at what ‘level’ it should start. And when Max passes a room, the level is just counted up so that the same room is spawned, but with the next level. This is shown in the image below.
So that’s pretty much it for this post, In the next post I’ll go over some pseudo code so that you can get an idea of how this actually works. You can follow us on twitter: https://twitter.com/Duckbridge to stay updated on our next blog post
2014-06-30 15:29:06 by duckbridge
Hey dudes and dudettes,
I'd like to talk about the 'One Game A Month' approach to developing games, which we've used quite some and has helped us alot with developing games.
Before making our last game (15Min Max) we've been using this approach to game development called 'One Game A Month' which basically means that we've been making one game each month. This seemed to work really well at first, because our problem was that we always wanted to make BIG games (that we would never finish). And with this new approach we would force ourselves to make smaller games (which could be finished in one month ofcourse).
At first, this approach seemed to work really well, we managed to finish a game each month and we were doing pretty good (some games we're pretty okay, some we're pretty bad). Another really good aspect of this approach was the fact that we could 'try out' ideas for games (prototype) in one month, so even if the idea was really bad, it wouldn't be a problem because we'd only work on it for one month.
However, as we made more games, we realized that our games were not as 'good as they could be', the games could be WAY better than we made them, if we only had more time...
But we didn't have more time, because we sort of religiously followed this 'one game a month' approach. Untill one day we were discussing the fact that we should be focusing on making 'good' games instead of many games (quality > quantity), that lead us to creating '15Min Max', which we consider our 'best' game so far.
We've just finished 15 MIn Max a few days ago but we've spent almost 3 months working on it (trice as long as usual) and during development we found that polishing takes A LOT OF TIME. The initial game was done quite fast, but polishing and balancing and stuff took so long. We do believe that the polishing time paid of in the end.. Because we're more proud of this game than the others before.
So far we've gotten a lot of positive response to the game but we're still wondering if there aren't parts that should/could improve. So we're asking if you'd like to play it and provide us with some feedback (if you have any)
You can check out the game in the following url and judge for yourself:
So from now on, we'll take the time needed to make games we're proud of!
PS: If you are also thinking about adopting the one-game-one-month approach, feel free to! it worked well for us!