First Tech Demo: Shattered Lands
Hi, my name is Chris, and this is my first Dev Log for a game I've started working on! I have a background in Software Development, so my expertise is outside of games itself, but I've learned a lot about developing code and shipping products and updates over the years. I still work full time, so features here might seem to trickle out, or randomly have a lot of development, depending on my availability.
That said, let's get to the game: Shattered Lands! Or at least tentatively that is the name... About a year and a half ago, I picked up the Minifantasy Assets from Krishna (https://krishna-palacio.itch.io/), and started work on a DIFFERENT game that I was calling the same name. That game was turning out fine, but I realized, after a lot of work, that I should probably not try to release an MMO as my first game. That was about 6 months ago. Since then, I had been thinking on WHAT I wanted to do, and thinking about what sorts of things I wanted to put into a game.
That brings me to my 'pillars' of what I wanted out of making a game:
- The game needs to be Multiplayer, over the browser: I had been demoing my game with my brothers and friends, and wanted to keep doing that without installers accessibly!
- Use Minifantasy assets: I have been contributing monthly to the fantastic Minifantasy assets, I should use them!
- Make a game I could simply release without infrastructure: This was the main problem of an MMO, I'd have to risk the game not being available if I couldn't pay for the infrastructure to run it! Instead, wanted to make a game that people run on their own to play.
- Make a game that I enjoy playing: There is a variety of games I like, but I really have always enjoyed the mix of Survival and RPG.
That leads me to Shattered Lands. The premise I want for the game is a Survival/RPG game, where you go from world to world, and can play with friends in the browser (or the game if they have it) even if they do not own the game. I think not forcing everyone in a friend group to own a game for their friends to play will be fun for the group, and makes a decision to try out the game much easier (For AAA games, at $60, if you and 4 friends want to play, that is a total of $300! Same strategy it would be only $60 to at least try it out with you and the 4 friends). Plus, if someone said 'yea, come join my game, just boot it up in the browser and play', you are not likely to just say no if you've never tried it, and if you like it, you might just buy it for yourself!
For the gameplay elements I want, I like the idea of going from world to world, using generation based upon 'coordinates' that you might put into a gate. The idea here is that you could generate the same sort of location that any other player would, by going to the same coordinates. Additionally, these small worlds can be quite small compared to some open world games, allowing me to really not worry too much about huge world size and making sure the game works across it. And lastly, the tech I'm using for multiplayer allows for multi-core runtimes when players are on different worlds within the same server (will explain below, in tech section!).
For the survival/rpg element, I want to allow the player to place/pickup any tile (aside from one specific one, to prevent them from falling into infinity and such!), and to have a semi-complex skill based systems. So far, I've only gotten to making tiles, and having those tiles show up and interact (more on this in tech discussion below), but have been having some thoughts around other systems. I want to create frameworks to do activities in the world: magic, melee, and ranged combat, farming, crafting, etc. These frameworks I want to provide many things with small benefits/drawbacks, and combining things in complex ways can lead to unique ways of playing the game. This can be most easily thought up in a magic system, where you could make spells by combining things like Power runes (for raw damage) with Fire runes (fire element) and Projectile runes (for ranged) to create a small fireball. Graphics could be based upon certain overridding or combining of these elements within the various systems. Its still very much just an idea, we'll see if it gets too complex and isn't fun :)
Now for the Tech! If you aren't interested in software and how I've designed some of the system, then no need to keep reading!
TODO: tech showing:
First, some videos showing some of the tech:
First, for the framework. I'm a Software Dev, and I like programming, and I (weirdly) like Javascript. I like the idea of using a single language for backend and frontend, and being able to avoid some types of compilation. I know it has some performance disadvantages in comparison to other languages, and when it comes to frontend WebAssembly. I'm familiar with many others including Java, C, C++, ARM Assembly, even Typescript. I don't know, I just like the weird stuff you can do in Javascript.
I decided that I wanted the game to be able to run as a standalone system or in the browser. I was looking at some alternatives so I could avoid a full Chromium runtime, but just ran into a few issues of simply not being mature solutions, so I just ended back up at ElectronJS (https://www.electronjs.org/). Not necessarily ideal, but it works quite well nonetheless, and a number of other apps use it. Maybe I'll revisit it one day, but I looked through I believe some 4 or 5 others, but their solutions were just missing pieces that I'm sure they'll get to some day to make it viable (simple things like dynamic interaction between browser and backend, or lack of documentation that would add days to do something simple that took a few minutes in Electron because of mature docs).
I also spent time on a system that I figured would be good to start implementing early: Modding. Specifically, I've set up a rudimentary system for it that is split into basically equivalent 2 parts: Plugins and Mods. The concept for Plugins are js modules that can be loaded at app startup time that affect the entire game, from the starting menu all the way through. For Mods though, these are added per save, and affect only that save. I've stored things like main menu navigation in the default plugin, and the actual game logic runs in the default mod, meaning that theoretically you could change the entire way the game is played within a mod.
For plugins, these would be stored in a folder at the game's location. Mods are stored in folders on the save, however when a new save is created, and mod in the 'mods' folder at the game's root location will automatically be copied into the save as defaults. I'll later change this to be that it will do this copy and then a secondary copy of any mods with the same name on every startup, to allow for changes to the core mod to be updated automatically on next load of the game. When I finally have demo's widely available, I will be doing hardcoded naming and hash checks within unmodifiable base code (well, not EASILY modifiable...) to prevent any mods not created by me from being loaded. I want to avoid this system being used while heavy development is happening, but definitely want it to open up closer to a full release. I figure for now, I'll eat my own dog food to improve the system :)
As one of the tenants above, I wanted browser-based multiplayer support. This is mainly to play with my IRL friends over the internet to show things off, but I figure it would be a cool feature of the game to allow one person to have the game, and their friends can just play. To accomplish this, I'm using Colyseus (https://colyseus.io/), a JS websocket based system. The system is made for lobbies with dynamic room generation, that can be loaded across multiple systems. I think I could eventually open up the system to be able to do that, allowing for a large multiplayer network to exist for servers, but for now I've just set the room limit to 1 (per config) and set up max players based upon whether you are playing 'singleplayer' or not.
For the game itself, on the backend I'm using 3d Rapier (https://rapier.rs/) to do physics, with tiles and entities placed in 3d space. These 3d objects are sent to the frontend, which is written in Phaser (https://phaser.io/), a 2d game engine. I then process the tiles and entities to show a 2d game. This also allows the flexibility to have a completely 3d experience in the future, without even touching the backend, as an option. The game itself should not play differently on the backend as a result, which is precisely what I want. Additionally, Rapier is either 2d or 3d, based upon what you pull in, and is very nice in that the only thing that changes with the API between the 2 is the amount of values in a point (2 or 3, obviously). Such flexibility will allow me to switch easily if I decide I do not want to do 3d physics on the backend (although that is not very likely).
In order to translate 3d points to a 2d scene, we need to extrapolate their positions from the coordinates. Since the camera is basically intended to be at a 45 degree angle facing toward the north, the 'x' value remains unchanged. I didn't want to mess with actually creating a 'camera angle' at 45 degrees, so I simply made the 2d 'y' coordinate of every object be the 'z' coordinate minus the 'y' coordinate from 3d space. This puts objects that are physically higher in 3d space further up at a constant rate, which looks natural for a 45 degree camera angle. This did lead to some other problems, namely that not calculating a camera angle means that the 'width' of objects (their size on the 'z' coordinate) are way smaller for entities vs tiles, so that the entities can appear to stand in front of the sprites for the tiles (and each other). As for the 2d depth, I simply set this to the 'z' coordinate, further south means more depth for that object, means drawn 'on top' of other objects of lower depth.
For the tiles on the frontend, when determining the 'look' of a tile, I have a system that processes tiles around the one deciding to change its 'look', which is only done when that tile is added, or a tile around it is added or removed. This system allows for complex definitions of what look for the tile we should use. Additionally, there is an idea of 'overlays', which are small overlays 'borrowed' from nearby tiles, based upon whether those tiles have higher priority than the tile they would put it on. That allows grass and dirt to cover up nearby tiles slightly when they are next to those tiles, which should reduce complexity of some of the dynamic tiles. I've worked pretty hard to get this whole dynamic mess to be rather performant, allowing for hundreds to thousands of tiles in a map to be loaded in just seconds.
Lastly, as you might have seen in the demo videos above, I've implemented a 'tile shader'. This is using actual shading with glsl, and is applied to tiles individually, a bit of work went in to make this performant by not spawning additional 'shader' instances, and not flushing unnecessarily. Each object can only have 1 shader though, so this shader's job is 2 fold: brightening or darkening based upon the tile's 'y' level (3d) in comparison to the player (brighter is higher, darker is lower), and making 'foreground' tiles transparent when they are covering up the player to allow them to see.
The height shader is pretty easy to understand. We simply apply a shade to the rgb of the tile based upon how far up/down the tile is. To complement this, 'floating' tiles (those with no other tile under them) get a small hanging 'shadow', which has nothing to do with the shader. I found these 2 pieces to be necessary to be able to tell apart tiles that look basically the same from each other but one is higher in the air sort of looming over other tiles. This is crucial to giving a look of 'depth' to the 2d scene.
The foreground 'cave' shader as I've called it is a bit more complex. The main crux of it is that I wanted to accomplish the following: tiles under your feet will ALWAYS be fully visible (no alpha), tiles taller than you will have alpha applied when they are blocking your view so you can see, tiles that meet this criteria and are further south have more alpha applied than those north to give you a sense of depth on the screen, and lastly tiles get alpha applied based upon how 'covered up' you are (with not being covered up meaning no alpha applied to anything). I accomplish this by basically being able to check how the player sprite is covered up by objects with greater depth, and the higher percentage the sprite is covered up, the bigger the circle to a max size. However, the 'sprite' with the player in Minifantasy is actually 32x32, even though the player only takes up the middle 8x8. So, to get a good approximation, I made it a 2 step process for uncovering: the first 40% of the circle takes into account the player visible sprite (the 8x8 in the middle); once that visible sprite is 100% covered, we use the amount of the ACTUAL sprite (32x32) to account for the whole circle (that sprite should be 40-70% covered by the time the entire middle 8x8 is covered). This gives a sort of expanding visibility as you enter a cave, based upon how far you are in it.
So that is basically what I've got for my first dev log for Shattered Lands. As you can see, right now it is all about getting the game world going, so a lot of functionality will be missing. For my next 'demo', I want to have tiles being manipulated by the players, to make sure my dynamic tile modification system is sound. I also want to have a couple more tiles from Minifantasy Forgotten Plains (I have '3' right now), especially ones which are not completely solid to play with the physics system a bit. For now, demos are going to focus around the terrain and its modification, and then will expand into other systems of the game. I'll think about making a devlog that shows more of my planning process, but right now it is rather rough as I'm mostly just prototyping for fun. Thanks for taking the time to read through all of my tech rambling, and hope you enjoyed!
Shattered Lands
Survival crafting game that you can host for play in the browser with your friends
Status | Prototype |
Author | jollychristopher |
Genre | Survival |
Languages | English |
More posts
- DevLog #2: Tile manipulation and 3D demoMay 09, 2024
Leave a comment
Log in with itch.io to leave a comment.