Protobound Day 2

Protobound Day 2

So I started off adding some collision to my interior maps by making specific parts of the walls collide. Furniture and the like will be placed free-hand as objects in the map, this way I can attach behaviors to them or animate them as I see fit.

The next thing before I start making objects is to make the more important objects, area warps. While I could do a streaming system and just load the map in chunks I think it would fit better if I had area changes. This way I could make varied maps without having to worry too much about transitions between the styles.

The key thing with this is I need to persist data across scenes. There are a few ways I could do this, one way is with a singleton that stores player and party data, then sets it up every map change. Another way is serializing the player and party on warp and sending it across to another warp to de-serialize and setup the player and party on the next map.

What I am thinking about doing is storing all persistent data in a singleton that will double as the save function for the game. This way I can kill 2 birds with one stone. I think it should be fairly easy to do so, no? Just grab the player object and serialize it to JSON, yeah? The party will be attached to the player as a child so I can just store everything on the PC and use the singleton to make sure it is persistent across maps and on save/load.

Singletons are an interesting pattern but easily abused to the detriment of the project, so I had to write it out here and think about it to make sure it's the right pattern for the job and it seems so. The warps will just have to communicate the place to spawn the player at on the new map to the Singleton. Or at least flag the player so the map knows which warp the player came from to set the transform properly.

There are a lot of ways to do this but I think this way will certainly save me some time later on down the road when I have to write the save/load function. This will certainly lessen the Week 3 load if I do it right. So, next thing to do is design a singleton for player/party state persistence to be used with warping and save/load. Then wire up my warps to it and create a new map, then warp the player back and forth with some arbitrary information on it and make sure it all gets across safe and sound.

Some research has yielded inst2dict and dict2inst. I will probably use this for the save system, but I am pretty sure I can just take an object, store it with the singleton as a variable and spit it back out onto a map when we load in. There may be some inherent flaws that I am unaware of as yet but hey, implement and iterate, see what happens.

Alright, so each map will have a script with a load_player() function. I was going to have an area2D for spawning the player on but I think having the map handle it itself would be smarter, perhaps. This way I can read flags on the player and do any setup for the map that might be required.

As it turns out the singleton loses it's data when the scene changes for... some reason? The player object is deleted, so I guess we are passing the player by ref, not by val. So instead of a copy we just have a pointer in the singleton. I could create a save file now I guess and save every time a player changes maps, then load on the next map but that's a bit costly as far as cycles and OS access goes. I think I need to find a way to copy the instance of the player object.

This was fixed with the power of .duplicate() on the player object. Since the base player object will be destroyed on scene change, I just use player.duplicate() in the DataManager singleton and now I have a deep copy that is not destroyed on scene change. It works kinda like a teleported, destroying you and replicating you somewhere else. But are you still you? I'd say probably not but the player doesn't need to know that.

Now I need to set the global_position of the player on the new map. I suppose I could do this with a node2D on the map for each exit point named Exit_<LastMap>. Then I set the map name in the warper. Then just find the node with get_node("Floor/"+DataManager.map_history[0]) having added a function to track the last 10 maps the player was on with an array.

Tested it out, seems to work so far. Given that interactable objects is something I have done before and am not terribly worried about implementing I will focus on creating a third map to further test the warp system and give me a place to put the first npc which will allow me to then start on the party system.

I will have to figure out how to deal with the cyclic reference, I did not realize for whatever reason that the packed scene is preloaded rather than loaded on demand. I will have to load the maps in code via path rather than as PackedScenes.

That's got it. Luckily there's a context menu option to copy path in the project explorer, eh? Saves me a lot of typing and checking paths.

Just spent entirely too much time trying to locate tiles in the tileset I am using, in reality I should probably spend less time on this and more time on functionality right now.

I can now warp between 3 maps. There is a bug where a player will appear on the initial map and you can stack a bunch of players. Kinda funny, but game breaking so... gonna get rid of that.

Quick, make a map!

Hacky solution to the double player problem, but solved it. Got a tight schedule here. I believe that marks the end of that issue. I can now navigate through 3 maps. All I need is collision on the outdoor one and maybe some figuring out how the Y-Sort works. Perhaps having the player and all things on top of the ground having a Z of 1 while ground is 0? Then having Y-sort on all those layers? Well... better see if that works.

Maybe if I broke all the tiles into single tiles it would work... mmm how annoying, well live and learn. I have made multi-tile high chunks into banded chunks. I will have to remake the power posts too.

I really think Godot's level design tools are in need of quite a bit of improvement. I really need to find a way to reliably import tilemaps from Tiled or some other level design software. I have spent so much time fighting these tools, it's really slowing me down. For now I will just leave the maps as they are. If I am to use Godot for anything going forward I will need to find a way to import Tiled maps.

That reminds me, I will probably do the third prototype as a full 3D game and might do it in Unreal engine just so I can have one prototype in each of the major engines and then make an informed decision as to what I will be doing for game dev going forward.

Also I do realize I could quickly make this very project in RPG Maker and be done with it inside a week. The point is to learn more about Godot by creating something somewhat complex with it, not so much to make a game I will sell. It's an exercise for my problem solving skills. So far it has been effective, I did find that I do really hate the level design tools for Godot and will be needing to replace them for any future projects. I don't know if I will have the time to experiment with that for this one so I guess I will just bang together some jank and call it a map for now. I think maybe I just have a bad understanding of how the tilemap tools work but that's beyond the scope of this project.

On to NPCs.

There's an NPC, I just need to set bounds on distance it can travel from it's spawn.


Kinda hit a wall with the bounding box, probably need to rewrite the way the npcs move around to be a choice of places within range, then set state based on velocity. This way I can prevent the npc from walking off into the void. I could also create collision layers that the npc could collide with but that would be per npc and if there were a lot of NPCs it would get to be a lot of work.

It's 5pm anyway, not much time to go and redesign the rudimentary AI on the npc so I will leave it here for today. I was hoping to have enough time to work on my 3D printer today but here we are. I could have called it after I finished the map warps and that would have been fine, though I did not, because I am an idiot and wanted to push to get ahead by the smallest margin.

Well, I'm off to make some food and let my brain cool down for tomorrow. I will be finishing the basic NPC AI and hopefully adding conversations.