These objects would be placed in the level, and feature both as a method of closing the outside world whilst loading, and look outside without people noticing. It was originally designed to support two hands, but could have more hands in case the user wants to stick the entire camera in the blinds.
Making these blinds was very nice. It makes use of vertex colors to define what areas can be moved. Each panel has their own material with parameters. Different channels would move differently. The green channel would move the vertices horizontally, allowing the edges to move inward during interation to maintain their length. Red vertices freely move towards the position defined in the parameter, which is a fixed height above, or below the hand, depending on if the hand started above or below the panel.
Whilst working on an older project I have learned that too many dynamic material instances slow down the game. That is why I maintain a cache of instances. The system allocates these instances to blinds that are currently interacted with, and prefers the instances closer to the hand. If a blind is 'released' the instance is maintained, but a lower priority, allowing it to be reused for a different panel. Also when a panel has been declared unused, it shares the same non-dynamic material as most of the panels.
Unreal Engine 4 makes it easy to build on top of their serialization methods. At the time of development the game was not fully designed yet, so I came up with a very flexible save system that can be utilized using Blueprints.
It works by having your objects inherit from an interface. And on saving and loading, it would collect all objects that use this interface, and run a set of steps.
Additionally, objects can register themselves as global objects. They are persistent across all saves, and do not need to be destroyed and reconstructed. Also objects can use the interface for other purposes as well, such as removing itself from the level upon loading.
A common problem with saving is object relations. Pointers break, so we need to fix those issues since we have objects spanning multiple levels. To do this we have a registry. Objects can register themselves, or others, using identifiers. When serializing we store the identifier on saving, and lookup the identifier to find the matching object during loading.
Finally, there is a master save that is used for keeping track of all save games. This file can also contain additional information per save slot, such as time played, the level, or more.
These steps would run upon saving:
- List all objects that inherit from the interface
- For each object, check if they want to be saved, and do the following if true:
- Check if the object is complex, or default constructed is enough
- Serialize the class pointer of the object we need to store
- Get and serialize the identifier if it needs to register on load
- Get the additional data, if complex, and write that as well
- For each global object, serialize like any other object
- Save the game using the save slot feature
- Load the master save
- Replace the additional information for this slot
- Save the master save
These steps would run upon loading:
- For each global object stored on disk:
- List all objects that inherit from the interface
- For each object, do the following:
- Run the pre-load event, this allows objects to register or remove themselves
- For each object stored on disk, do the following:
- Construct an object based on the class
- If it has a data object, construct it as well
- Register the object, if desired
- List all objects that inherit from the interface and do the following:
- Run the PostLoad event, they can all link up safely.
The end result is a very flexible system that makes it easier to serialize references, makes use of UE4 as intended, and can be considered as robust (if used right).
In Project Abby you are supposed to walk around in a room, and you can analyze a couple of objects. If you think you have explored enough you can leave the room, and answer questions. Depending on your earlier answers, and which objects you have analyzed, different questions and answers might pop up. Each time you return to the room, it could be different, since each room visit is on a different day.
Next I wrote a tool that converts a Twine story to bytecode, which I then ran on specific events in game, and would continue to run until the bytecode returned with a question and a list of answers, or a different command.
This topic intrigues me very much, and I definitely want to do more research in lexers and syntax.
This project gave me the chance to implement audio for the first time, and I chose to do ambient audio. My goal was to keep the ambience present, but always in the background. It should not sound like it is looping, but it should never sound out of place.
My solution is a system that would have a list of assets, and their properties, and schedule them. It would make sure that sounds do not play too often, and because the volume is known for each sample, it would make sure that loud sounds will not overlap.
To prevent samples from growing familiar, sounds would vary in pitch and volume.
The properties a sound asset could have are:
- Min/max frequency
- Min/max volume
- Min/max time between
- Sound loudness
- Sound shape
- Narrow Bell (used for a helicopter flying by)
- Gaussian (fast fade in/out, used for longer rain samples)
- Pow (thunder, gunfire, ect)
Note that the min/max time between samples is just a suggestion, if a sample does not fit, it does not play. If desired the min/max time could be set to 0, and the priority to 0 as well, causing the sample to always be audible, but other samples can always go first.
I wrote a program that could load .wav files, displayed their loudness, and suggest a value for the sound loudness, and a shape. Trying to do this leads to a whole lot of papers and arguments on how to measure loudness, and human perception of loudness.
To cut that short I ended up implementing Root Mean Square, since that one looked do-able to implement. The curves I found looked accurate.
If I had more time, this is definitely something I would expand on. The system could output to multiple audio sources, but they would play the same. In our New York settings a helicopter flyby, and the barking dog sound approprioate, but either the heli is in your neighbours apartment, or the dog is abseiling. Separating the sources meant that the systems may overlap.
Variety is still a concern. Improvements could be made in grouping sounds together, so that the dog sometimes barks once, and sometimes three times, without featuring multiple sound assets.
In the picture on the right you can see a wireframe, and the scene. What has happened is that I just tossed a bunch of nuts and bolts around, and the old bolts are not visible in the wireframe. Because I baked them in the floor texture. Kind of exiting to allow for so much detail to appear without any issue. This was part of my first project in Unreal Engine 4.
In the game I toss quads with textures around, and when they land on the floor they bounce until coming to a complete halt. I then update the texture data in RAM. After a bunch of quads are processed, I commit the textures to video RAM, and delete the quads.
Updating textures can be quite expensive, so I subdivide the texture into multiple textures of 256x256. Performance was negligible.
Shadertoy and Raymarching ways for me to create cool stuff. It allows for geometry we are not used to seeing in video games. Demonstrating raymarching to artists I am familiar with breaks their minds in no-time.
I used this tool to experiment with shapes, rendering, soft shadowing, and color spaces. More on the last one later. I think this can be best summized in a bunch of images. Shadertory Profile
Log color space
I always enjoyed working together with artists. I do not often get the opportunity during a project to work with artists, but I try and have the technical knowhow on how different features work in engines. UE4.15 came with a new tonemapper, and that triggered me to perform research on log color space, and the merit it has for video editing.