Beta Testing

Let the testing begin!

So the game keys have been sent to the testers. If you have signed up previously, you should be receiving an email with the key.

The game should run well. But if you encounter any issues, feel free to send an email to feedback@laboratory.systems or post on the Steam forums. Coming closer to release things will get piled up and chaotic. So I am prioritizing potential issues in the following order:

  • Crashes.
  • Confusing places you get stuck or don’t know what to do. That is probably the issue with the game and should be fixed.
  • Non blocking bugs. Bugs that don’t prevent game progression.
  • Other improvements

The game has a functionality which allows you to take a screenshot with F2 key or record a webm video with F3 key by default, unless key bindings were changed otherwise. Whenever necessary, attach these recording files to help explain the in-game situation surrounding the issue you are trying to report.

Update week of 07/01:

  • Fixed unit collision avoidance bug: air mobile structure escapes small ground structures.
  • Tutorial panel improvements: additional panels later in the missions.
  • Added tooltip on the reason why a part is locked in sandbox.

sandbox_part_lock

Update 06/28:

  • Fixed some potential issues that may cause save/load to crash.
  • Input system mouse compatibility.

Update 06/26:

  • Fixed potential crash due to failed input detection.
  • Made continue button go to next mission when a map is finished.

Update 06/24:

  • The D3D issue has been fixed.
  • Fixed the challenge board in sandbox.
  • There is also a bug with the Return button once in sandbox. The sandbox is supposed to be a parallel universe sandbox which exists concurrently with the current main game. The return button is supposed to switch back to main game. But it always resets progress and goes back to main menu, losing the main mission progress before switching into sandbox. Now this has been fixed. Sorry if you encounter this during testing.
  • For the boss “level”, I have reduced the power of the Megacube boss. Now it has weaker lasers. Saved game still uses the saved version. I hope I didn’t make it too easy the other way. I also added a few hints:

boss1_hint1  boss1_hint2

 

Update 06/23:

  • Fixed docking site blocked problem. The checking was too sensitive on the blockage. The drops from the vehicle in “Transportation Line” can fall close to the docking site and make it undockable. Unless the player know he can send something there and clear it up. But this is not supposed to happen in the first mission.

dockingsite_blocked

  • I have added some emphasis in the hints and tutorials about the remaining use of projectile weapon in “Transportation Line” after the introduction of prism, fearing that some people might not understand remaining tactical advantage of projectile in some circumstances, making it a bit more difficult to defend against the “crushers” climbing up from cliff. Here is what I mean:

knock_back

  • Fixed some soundtrack volume inconsistency.
  • Found a D3D related low level bug. Must be fixed.

Survival Mode

The second survival map is almost ready. Still need some adjustments on balancing and events.

horizon_hub

This survival mode is the extension of the classic (tower) defense just like the demo. Everything can stay at the same place, focusing on defense contraption. There is no need to move base. Whereas the main campaign maps in the full game are long and exploratory. They contain several locations which the base can transit to. They can cover more than defense. Though it may still be played as defense with expansionary defense 90% of the time. Once the disc block is introduced, flying structures can be built and pure defense becomes optional.

horizon_hub2

In the second survival map, the so-called production system works like this. It mostly consists of a pipeline of blocks introduced in earlier missions. This is the content from the help panel:

duplicator

The duplicator mirrors the bare core of the template block from one side to the other, in this case the cube.

The octahedron block plays a maintenance role in the robotic shapes family. It can attract small objects making them orbiting around. The small object debris can be put back onto the core of blocks by octahedron, regaining their condition as if reversing the fallen shield from any previous damage. These two blocks together will create new blocks with brand new condition from the looks of it. The tube block’s air stream just provides some pushing to make the products more spread around without cluttering up the duplicator.

There are similar creations like this, such as one-way train gate which utilizes the automatic extension of pistons. If train comes and blocks lasers installed with pistons, the pistons will extend, pushing the door up and open. Once lasers unblock, the gate restores with pistons.

 

Aside from this there are some other nitty-gritty details of improving and fixing. Here are two of them.

Reverse Installation

During extension building, when you cut the extension and build backwards. The physics joint type may not be correctly determined. Then you will find issues like cylinders, tubes or planes unable to rotate.

In the following example the structure on the left side is created up from ground, sideways then down with the cylinder. If I remove the cube as shown in the middle. Confirm the modification and then put it back. The joint type of the cylinder need to correctly detected. Because only one of the two joints on the cap side of the cylinder is the rotatable one with a motor. And the other one does not have any rotation capability.

reverse_install

The example above needs the rotation joint at the top side, different from normal installation order where the rotation is at the bottom side. This can be detected in code and is now fixed. It happens not often as most people don’t build this way. Now this has been fixed.

 

Unit Hotkey

Often times, micro controlling of units(structures) can be greatly effective and fun. The interface for the unit commands (aggregated commands for the structure) is on the bottom right of the screen. Apparently controlling the selected structure with hotkey is more convenient. Now these keys are added to the pool of other key bindings. So now if you have a ship with extendable parts, it will be easier.

lop_buttons

Actually, for smaller changes near release I am also considering supporting Steam Leaderboard. It’s not complicated to integrate. I will find a little time. This is not in high priority now.

I am trying to aim for August release. Months after that will be the busy months, less suitable for release. So I need to get the map finalized and start testing ASAP.

Getting Ready for Release

 

capsule_topdown_wide2_650

It’s been a few years since the last blog post. Quite a lot of things have happened in real life. A few months after last post, I had an international relocation. I moved back to my hometown in my home country. After the messiness involved with moving countries, I had a new place as base of operation. Development has been going OK later in 2015.

But, game development like this can be depressing sometimes for a lone wolf like myself, especially with a bit of financial struggling. In terms of how an adult should be planning for his career it is neither a very good option. It did also cost some very good opportunities. Felt stuck, I took a break at the beginning of 2016 and went for an AAA 3D programmer job. So less time was available for this project. It was an extremely hopeless situation and I had to do what I had to do by stepping away for a while.

Some blog readers are probably too frustrated. I am very sorry for this.

Then during the busy days, I went back and revisit this project from time to time like some people. During the free days I had more time devoted to the project. I still had the urge to finish this as every revisit shows an interesting game. I can’t take it slow forever. And it would be a huge disappointment to entirely abandon it.

The planetary concept was developed during part time. We have rockets transferring materials, some large environment structures surrounding atmosphere mining (visual), clouds in background, etc. There is also a planetary transition which will be useful for possible space missions as an extension. During this time, the music for the game was also complete. Some bugs were fixed (there was even a memory corruption due to a C++ compiler bug)

labtd_x64 2018-05-20 16-43-58-92.avi_snapshot_01.30_[2018.06.02_01.26.32] lab_2018_5_17_003300 

There will also be a survival mode with two hardcore defense missions where the enemy should be coming in hordes(gradually). In one map you will be using the duplicator block and octahedron block for production of supplemental source materials. This map still needs work. It should be on time for release.

lab_2018_6_2_022121

Now we have a Steam page. Once the last map is settled, a release date will be finalized. The old demo was hidden to avoid confusion as it is too old, after discussing with Steam. You should still be able to install it with this steam url however.

About the keys, I don’t know when it is a good time to send out these keys. But it will definitely come before official release. Sorry for the waiting, you will get it.

Timeline System

This time line system resembles me the multiverse event branches. It is essentially a save game system, with the tracking of snapshots at past time points. It also allows branch a new series of time points. Think of at one point in the past you made another choice, then you have 2 time line of events from then on. Here is what it looks like when you try to load game from it. You choose a save point and load. Most of the time the save will not likely be this complicated with quite some branches. And most likely you will end up deleting useless ones. This is just a demonstration.

timeline1_t

When combined with auto saving, this is perfect. Because it tracks your history and if you mess up at one point, you can go back and start a new branch from there. No need to worry about autosave overwriting the previous ones.

When saving, the system can suggest the default save point to be appended. You can also choose your own if you desire. If you try to save to a slot that is not the history of the current game session, it will be treated as overwrite, like that last slot below.

timeline3_t

Notice the 2 similar slots in this image, the second one is a clone. You will only want to clone rarely, or clone from an autosave because it creates duplicated history and may confuse you. If you don’t like this kind of saving system, there is the Traditional Mode, which is just like common load/save as you see in other games.

This was yet another backlog in the development system. Cleared.

Everything Is Connected: The Crazy Serialization

Saving and loading the game is a fundamental feature in many video games. This saving process is a form of serialization, converting game states to a byte sequence that can be stored/transmitted.

In the case of a chess game, it can be quite simple: the chessboard, a plain surface to be saved. In some first person shooters the positions of players and NPCs are stored, perhaps with some extra level progression information. But in a strategy/simulation game, the information that need to be stored can be more complex. Such as in Roller Coaster Tycoon, there are many peeps in the park, all having different behavior and short term goals. And these goals are connected with other objects in the game, such as a ride, or the restroom when they need to go somewhere. The laboratory system had a similar challenge because everything is connected.

ser_graph_t

This is a visualization of a save for a simple scenario with 3 ground structures, which are just towers. The icons mean the objects in the game. And the lines are the connections. The items in the 3 gray area are approximately the items that make the 3 towers.

ser_graphlocal

When parts stick together they will have connections to each other. Lets take a look at the smaller example shown above. A cube block has a port on each of its 6 faces. These ports connect to the ports on other parts. That is how parts build on other parts works. You can see many “BlockPort” surrounding the cube icons and connecting to each other. All together, the entire structure is considered a unit, which can follow commands the player gave based on its capabilities. Despite a ground tower can not move, one command is like move to a position, called a waypoint in the game system. As you can see the UnitObject and the WaypointNode on the left.

The software system rebuild these connections when loading a saved game. It does so by mapping old pointer addresess to new pointer addresses. And mostly due to the usage of objects from external libraries, the pointer resolution is a multistep process. I am not going to get into too much tech details about that. But it need to be reliable, because an unresolved pointer is invalid and will make the game crash.

 

In addition to the connections, each of these nodes has its own data. The number below the name means the size of the data in bytes. Think of parts have their health points, positions etc that need to be stored. Different types of items store different things, and can have vastly different sizes. A GridPlane consists of the grids on a buildable surface. It has information for each individual cell.

Here is another challenge. There are 100-200 different types of things and I need to write code to handle each one. And each one may have 10-100 different attributes(data member). Unfortunately, in c++ you do not have reflection information to do this automatically. So I wrote code to handle them all.  Here is the loading/saving code for a debris in the game:

void BlockDebris::deserialize(Deserializer* des, ObjectDataStorage* data)
{
	SO_READ(m_mass);
	SO_READ(m_lifeTime);
	SO_READ(m_level);
	SO_READ(m_position);
}
void BlockDebris::serialize(Serializer* ser, ObjectDataStorage* data)
{
	SO_WRITE(m_mass);
	SO_WRITE(m_lifeTime);
	SO_WRITE(m_level);
	SO_WRITE(m_position);
}

Just to give a simplified example. 2 operations, serialize and deserialize. 4 attributes in a BlockDebris. Occasionally I make mistakes. If I accidentally missed one attribute, some issues arise. This is what it looks like if I forgot to load the position. Things collapse to the origin point.

ser_bug

To make this easier, I wrote a meta data class to store meta data about these attributes, and select appropriate read/write routine at compile time using meta programming. How this class works is a different story. But the purpose of this is to merge the 2 repeated workflow to one. Then I will not accidentally miss one in one of operations. This meta data is stored by type, so no memory overhead on class instances.

const ClassDataFieldGroup BlockDebris::MetaData =
{
	MD_FIELD(BlockDebris, m_mass),
	MD_FIELD(BlockDebris, m_lifeTime),
	MD_FIELD(BlockDebris, m_level),
	MD_FIELD(BlockDebris, m_position)
};
usage: MetaData.ReadAll(this, data);

If things are not going well, I may take a step further by generating this list automatically using a tool. But that will need some extra work writing the tool and tagging data members in c++ headers.

This serialization challenge has been a backlog item for quite a while. Now it has been finally worked out. At this point there is no tricky features anymore, so gameplay development will be smoother next.