Jump to content
  • Advertisement
Sign in to follow this  
  • entries
    8
  • comments
    0
  • views
    741

About this blog

Updates about the Leaf game project.

Entries in this blog

Seven Weeks Later

This weekly summary of daily progress would normally be very short, as I fell ill and had to sit out a few days of development as a result. I'm writing this from bed at the moment, though I'm already feeling a lot better. In any case, this week I "finished" the tundra tileset that I'd been frustrated over for a long time now. You can see it in the header. Then, partly because I couldn't settle on what else to do, and partly because it seemed like an interesting, quick project to do, I wrote a particle system. This is what I'll talk about in a bit more detail. The system that's implemented in Trial -- the custom game engine used for Leaf -- allows for completely custom particle attributes and behaviour. Before I get into how that's handled, I'll talk about how the drawing of the particles is done. For the drawing we consider two separate parts -- the geometry used for each particle, and the data used to distinguish one particle from another. We pack both of these two parts into a singular vertex array, using instancing for the vertex attributes of the latter part. This allows us to use instanced drawing and draw all of the particles in one draw call. In the particle shader we then need to make sure to add the particle's location offset, and to do whatever is necessary to render the geometry appropriately as usual. This can be done easily enough in any game engine, though it would be much more challenging to create a generic system that can easily work with any particle geometry and any rendering logic. In Trial this is almost free. There's two parts in Trial that allow me to do this: first, the ability to inherit and combine opaque shader parts along the class hierarchy, and second, the ability to create structures that are backed by an opaque memory region, while retaining the type information. The latter part is not that surprising for languages where you can cast memory and control the memory layout precisely, but nonetheless in Trial you can combine these structures through inheritance, something not typically possible without significant hassle. Trial also allows you to describe the memory layout precisely. For instance, this same system is used to represent uniform buffer objects, as well as what we're using here, which is attributes in a vertex buffer. If you'll excuse the code dump, we'll now take a look at the actual particle system implementation: I had to use a screenshot, as GameDev does not have Lisp source highlighting, and reading it without is a pain. In any case, let's go over this real quick. We first define a base class for all particles. This only mandates the lifetime field, which is a vector composed of the current age and the max age. This is used by the emitter to check liveness. Any other attribute of a particle is specific to the use-case, so we leave that up to the user. Next we define our main particle-emitter class. It's called a "shader subject" in Trial, which means that it has shader code attached to the class, and can react to events in separate handler functions. Anyway, all we need for this class is to keep track of the number of live particles, the vertex array for all the particles, and the buffer we use to keep the per-particle data. In our constructor we construct the vertex array be combining the vertex attribute bindings of the particle buffer and the particle mesh. The painting logic is very light, as we just need to bind the vertex array and do an instanced draw call, using the live-particles count for our current number of instances. The three functions defined afterwards specify the protocol users need to follow to actually create and update the particles throughout their lifetime. The first function fills the initial state into the passed particle instance, the second uses the info from the input particle instance to fill the update into the output particle info, and the final function determines the number of new particles per update. These particle instances are instances of the particle class the user specifies through the particle-buffer, but their fields are backed by a common byte array. This allows us to make manipulation of the particles feel native and remain extensible, without requiring complex and expensive marshalling. Finally we come to the bulk of the code, which is the tick update handler. This does not do too much in terms of logic, however. We simply iterate over the particle vector, checking the current lifetime. If the particle is still alive, we call the update-particle-state function. If this succeeds, we increase the write-offset into the particle vector. If it does not succeed, or the particle is dead, the write-offset remains the same, and the particle at that position will be overwritten by the next live, successful update. This in effect means that live particles are always at the beginning of the vector, allowing us to cut off the dead ones with the live-particles count. Then, we simply construct as many new particles as we should without overrunning the array, and finally we upload the buffer data from RAM to the GPU by using update-buffer-data, which in effect translates to a glBufferSubData call. Now that we have this base protocol in place we can define a simple standard emitter, which should provide a much easier interface. Okey! Again we define a new structure, this time including the base particle so that we get the lifetime field as well. We add a location and velocity on to this, which we'll provide for basic movement. Then we define a subclass of our emitter, to provide the additional defaults. Using this subclass we can provide some basic updates that most particle systems based on it will expect: an initial location at the origin, updating the location by the velocity, increasing the lifetime by the delta time of the tick, and returning whether the particle is still live after that. On the painting side we provide the default handling of the position. To do so, we first pass the three standard transform matrices used in Trial as uniforms, and then define a vertex shader snippet that handles the vertex transformation. You might notice here that the second vertex input, the one for the per-particle location, does not have a location assigned. This is because we cannot know where this binding lies ahead of time. The user might have additional vertex attributes for their per-particle mesh that we don't know about. The user must later provide an additional vertex-shader snippet that does define this. So, finally, let's look at an actual use-case of this system. First we define an asset that holds our per-particle buffer data. To do this we simply pass along the name of the particle class we want to use, as well as the number of such instances to allocate in the buffer. We then use this, as well as a simple sphere mesh, to initialize our own particle emitter. Then come the particle update methods. For the initial state we calculate a random velocity within a cone region, using polar coordinates. This will cause the particles to shoot out at various angles. We use a hash on the current frame counter here to ensure that particles generated in the same frame get bunched together with the same initial values. We also set the lifetime to be between three and four seconds, randomly for each particle. In the update, we only take care of the velocity change, as the rest of the work is already done for us. For this we apply some weak gravity, and then check the lifetime of the particle. If it is within a certain range, we radically change the velocity of the particle in a random, spherical direction. In effect this will cause the particles, which were bunched together until now, to spread out randomly. For our generator, we simply create a fixed number of particles every 10 frames or so. In a fixed frame-rate, this should look mean a steady generation of particle batches. Finally, in the two shader code snippets we provide the aforementioned vertex attribute binding location, and some simple colouring logic to make the particles look more like fireworks. The final result of this exercise is this: Quite nice, I would say. With this we have a system that allows us to create very different particle effects, with relatively little code. For Leaf, I intend on using this to create 2D sprite-based particle effects, such as sparks, dust clouds, and so forth. I'm sure I'll revisit this at a later date to explore these different application possibilities. For next week though, I feel like I really should return to working on the UI toolkit. I have made some progress in thinking about it, so I feel better equipped to tackle it now. 

Shinmera

Shinmera

Six Weeks Later

In this week of daily game development, I worked on two larger features. The first is a pathfinding, so that NPCs, and the player character, can move to designated positions in the map. That'll largely be useful for cutscenes and making NPCs move around a bit while idle. I might even extend it to allow creating full routes for NPCs to take, to implement daily routines or something like that. a.webm The other large feature is a new user interface toolkit. This is still in its infancy at the moment, so there's nothing to show for it. I expect that it'll take me a few weeks to complete this, so the next few updates might not be very fancy, I'm afraid. I'll try to do other, minor work on the game in-between though. Mostly working on assets and such, so hopefully I'll at least have one or two screenshots to post.

Shinmera

Shinmera

Five Weeks Later

And another week of daily gamedev gone by. The improvements implemented in the last week are not too exciting visually. I finally implemented a proper world storage format, including for the new quest system, as well as save states for the whole shebang. The framework used for that should be general enough to survive future expansions of the games as well, or in the very least I strongly hope that's the case. Other than that I added a crawling mechanic to allow the player through tighter gaps. And just today I completed an auto-tiling mechanism in the editor, which allows prototyping new levels very quickly. edit.webm I'm also still thinking about UI toolkit theory. Hopefully I can dig into the meat of that soon, though it'll probably be a multi-week endeavour.

Shinmera

Shinmera

One Month of Daily Streams Later

That didn't feel as long as it was. A month ago I promised to do daily streams of game development. So far I've held true to that. I'm sure I won't be able to hold that true forever, but I'll try to keep going for as long as I can. In this one month alone, a lot has changed for the game though! A new architecture for map organisation was implemented, including a new save file format for that. As part of that work I also completely rewrote the tilemap rendering as well. The game has a lighting system now, too, based on signed distance functions to compute precise light areas. In terms of physics, collision detection was revamped to properly support slopes and moving platforms, giving much more freedom for level design. All of the art assets that existed previously were also dropped and replaced with new ones. I'm still working on that part, since I'm not quite happy with the current set of tiles. I'll also have to add more animations, and of course repeat the animation and character design work for any NPC I might add to the game. That's a bit of a ways out though, as I'll need to think about world building and story writing first before I can really get into that. Now there's a hard challenge! Finally, in the last week I designed a new language for writing dialogue with branching, choices, looping, and so forth. To support this I extended the syntax of Markless, and added a compiler to transform the Markless AST into a simple assembly language, which is then executed in a simple, suspendable VM. Added on to that there's now a quest system that should be general enough to allow writing any kind of quest I'll need. Currently though it's lacking a way to conveniently write these quests, so that's a task to work on in the near future. I intend on writing a simple UI to create and edit these quests. I'm not sure yet what I'll use for that, though. I'm most well-versed with Qt, but maybe I should finally cave in and give CLIM a shot. Or perhaps LTK. We'll have to see. There's still about two months left in my summer break before university resumes. I hope to keep going with this until then, so expect further daily streams and more progress! As before, the stream still happens every day at 20:00 CEST, on https://stream.shinmera.com, or https://twitch.tv/shinmera. I've tremendously appreciated all the people that stop by in chat to watch, and even talk with me during work. It's made things so much more enjoyable for me. Really, thank you so much! a.webm

Shinmera

Shinmera

Three Weeks Later

This week the weather has been much more amenable, but unfortunately not too much visible progress has been made. I rewrote some engine internals to allow a much better representation of GL uniform buffer objects. Moving platforms and simple elevators were also added, which proved much more frustrating to implement than I ever expected. I also started work on a new tileset, though I haven't completed it yet -- I'm still unsure about the colouring choices, and will definitely have to expand it a lot still. Finally, just yesterday I cobbled together a specification for a dialogue markup that should allow branches, choices, and all manner of things that I expect I'll need. In the coming week I'll work on putting that specification into practise, adding other physics objects like water, and if time permits, adding environmental effects. In any case, the daily development streams will continue for the next week as well. I hope to see you in chat some time!

Shinmera

Shinmera

Two Weeks Later

This week central Europe was a hellfire, and the resulting heat did not help with productivity. Regardless, the daily development streams at least continued. Newly added to the engine are horizontal slopes and a lighting system. I'm working on a new tileset and should hopefully be able to get to adding more gameplay mechanics now. out.webm

Shinmera

Shinmera

One Week Later

It's been a week of daily game development streams, and the project is now about back to where it used to be before I started redoing large parts of it last Monday. There's still a lot left to fix and smoothen out, but so far the progress has been alright. Hopefully I'll be able to move on to adding new features within this week. I hope to see you in the stream chat again! leaf-update.webm

Shinmera

Shinmera

Sign in to follow this  
  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!