Logic World Wednesdays: Steady Progress

by @MouseHatGames 2019-05-15
Jimmy
UI work

This week I did the first serious work on menu design for Logic World. I overhauled the Selection Menu, which you use to select the components that appear on your hotbar.

Before:

After:

I’m pretty happy with the overall design elements: rounded rectangles, mostly in neutral tones with some splashes of color for highlights. I’m using the selection menu as a study to figure out what I want the rest of the game’s menus to look like.

On the subject of the selection menu, I added the ability to search it. This can be really useful if you’ve got a lot of mods installed.

Pick Component

I added a new shortcut for managing your hotbar called Pick Component. Middle clicking on a component in the world will add that component to your hotbar if it’s not already there and select it.

Not shown in the video is two more advanced features of Pick Component. If you hold ctrl when you press the button, the picked component will replace the component in your currently selected hotbar slot, rather than adding a new one. Conversely, if you hold shift, the picked component will be inserted at the position of the currently selected hotbar slot, rather than being inserted at the end of the hotbar.

Rounding

In Logic World, the position and rotation of objects in the world are stored as floating point numbers. This makes them very performant, but floating point numbers have a disadvantage: they are subject to rounding. If you’re a programmer and you’ve worked with floats before you’ve probably seen them have a value of 0.99999823 when they should just have a value of 1.

This tiny amount of rounding is usually no big deal, but in logic world the errors were accumulating over time. Particularly in worlds where you have deeply nested chains of boards placed on other boards, the position of objects could sometimes be off by a noticeable amount.

Notice how the inverter in this picture is slightly offset from the grid.

To fix this, I’m now rounding the position and rotation of every object in the game: positions are rounded to the nearest millimeter (along all 3 axes) and rotations are rounded to the nearest tenth of a degree (again along all 3 axes). This extra rounding is too small to be seen in-game unless you’re looking closely, but it’s big enough that it cancels out any errors we get from floating point shenanigans. Everything in Logic World is now exactly where it should be.

Numeric Component Types

Each component in Logic World has a type. There are Inverters, Delayers, and XOR gates, to name a few. Before this week, component types were stored internally as pieces of text. That meant that, depending on the length of the type name, component types could take up 15 or even 20 bytes!

Now, however, I’ve refactored the system so that component types are all stored as two-byte numbers. Each save file has a unique relationship between component types and the numbers. For example, the number 18 might represent an XOR gate on one save file, but it might represent an inverter on another save file. This means that mod authors don’t have to make sure they’re not using the same number as another mod when they add a component type; the game will automatically give them a number that is not already in use by the save file.

As a result of this, save file size - and by extension, the time it takes to save and load the game - has been reduced by about 20%. The amount of bandwidth used when playing online has been similarly reduced.

Board Resizing Bug Fixes

If you watched the previous two videos on Board Resizing, you probably noticed that there was an annoying visual flicker whenever the board was resized. I’ve fixed that and board resizing is nice and smooth now.

Previously, if you resized a board that had components attached to it, the position of those components would get screwed up. This is because behind the scenes, resized boards are changing their position, and the attached components were not properly taking this into account. I’ve fixed the math and it all works nicely now.

Felipe (aka pipe01)

This week I wanted to polish out some things that I had left out on the website, those being emojis not rendering correctly and user pages not working. Whenever you inserted an emoji into a comment or a post it’d show a ? instead, which made me think that there was some encoding issues. I began investigating the database and found that they were being stored as question marks there, so the problem was in the database. I set the collation for all tables to utf8mb4_general_ci and tried again, and emojis were working properly now! I also fixed user pages requiring you to be logged in in order to see them, it was an easy fix.

On the game side, I’ve implemented synchronous RPC calls. Before this, whenever a mod called an RPC method it would be a fire-and-forget situation, where the mod had no way to know whether or not the server had received and processed the call. This is probably enough for most things, but there may be some cases where this is undesirable. Synchronous means that the mod code will now wait for the server to send back an acknowledgement before continuing execution, which allows for more complex synchronization between clients and server!

On the topic of waiting, I’ve added a loading screen for mods. Mods were being loaded in the main thread, which meant that the screen wouldn’t update until all mods were loaded. This worked fine, but it didn’t allow for any graphics in the meantime. Now, mods are loaded in a separate thread, allowing the game to monitor the loading and inform the user!


If you’d like to receive an email each time we post one of these blogs, you can sign up for our newsletter. Be sure also to wishlist Logic World on Steam, join the official Discord, and follow @LogicWorldGame on twitter.

See you next Wednesday!


22 comments
@shamus030 2019-05-16

Great update!

The blue color for the menu groups seems a little too strong. Have you experimented with a darker blue (closer to grey)?

Awesome idea to dynamically allocate numbers for components per-world! I’m interested in what drove the decision to use a custom storage format instead of some human-readable format. Was it just not practical in terms of performance?

In a similar vein, any plans/thoughts for some sort of component (or world) import/export in a human-readable format? I can see myself wanting to export some module I’ve made, manipulate it externally, and import it again (layering hundreds of components side-by-side, or making the same small tweak to hundreds of components simultaneously).

@Jimmy 2019-05-16

The blue color for the menu groups seems a little too strong. Have you experimented with a darker blue (closer to grey)?

I’ll be playing with the UI colors more this week, I agree the blue is not quite right yet.

I’m interested in what drove the decision to use a custom storage format instead of some human-readable format. Was it just not practical in terms of performance?

Yeah, the decision was made for three reasons, all related to performance:

  • it makes save file sizes small
  • it makes worlds save quickly; computers are better at writing binary than they are at writing text
  • it makes worlds load quickly; computers are better at reading binary than they are at reading text

However, I totally agree with you that having human-readable saves is useful. That’s why we have an option to save or load your game as SUCC, which is a markup language I designed to be as human-readable as possible. SUCC saves are much slower and larger, and they’re not officially supported (so they might break between game updates, for example) but I’m sure power users like yourself will find many uses for them.

@shamus030 2019-05-18

Thanks for the response! Really happy to hear you’ve already thought about power users :)

What are the primary differences between SUCC and YAML? From reading through the SUCC wiki I can’t spot any differences.

@Jimmy 2019-05-18

When I realized that I hate JSON, I went through the following process:

  1. Try a bunch of different C# YAML libraries, not being satisfied with the API for any of them
  2. Decide to make my own YAML library with a decent API
  3. Look at the YAML spec

Man, I don’t even have time to read a document that long, much less implement each and every tiny detail in it. So when I set out to make SUCC my goal was to make a subset of YAML with a better API (at least, better for video games).

For the most part, that’s what SUCC is, but now it also has Shortcuts, which make writing config files way, way easier than writing YAML config files.

@shamus030 2019-05-18

I would think you could use an existing YAML library just for its parsing logic and write your own facade with the API you want.

Shortcuts look awesome! I really like the idea of driving it through static properties (and after a second look I noticed it works with functions too!) The Vector example is great.

You could kind of emulate the static shortcuts in YAML with some clever use of anchors, but it wouldn’t be quite as flexible.

@Broyojo 2019-05-16

I really like the new inventory, hotbar, and block selecting. Maybe you could style the text boxes to not look like Unity default text boxes? I am being very picky

@Jimmy 2019-05-16

I really like the new inventory, hotbar, and block selecting.

Thank you, I’m glad!

Maybe you could style the text boxes to not look like Unity default text boxes?

You’re talking specifically about the search box, right? I forgot to change the font there, all the other text should look good though.

I am being very picky

Please continue to be picky. Being picky is how we’re going to get an awesome game!

@ForLoveOfCats 2019-05-15

Felipe how do the synchronous RPC work? Does the function calling it have to be async?

@pipe01 2019-05-17

Yup, using System.Theading.Tasks.Tasks

@ForLoveOfCats 2019-05-15

In what way does the search system rank entries? I’ve written a search system before and am very interested in how this system ranks and de-ranks entries.

@Jimmy 2019-05-15

Nothing fancy, they’re sorted alphabetically. It might not look like this, though, because the alphabetic sorting uses the component’s internal text ID rather than its display name.

@ForLoveOfCats 2019-05-17

So I’m assuming it only matches entries where one of the search terms is an exact substring of the entry’s searchable name?

@Jimmy 2019-05-17

Components can be searched based on the following criteria:

  • the internal text ID of the component
  • each sub-section of the component’s internal text ID, divided by the . character
  • the entire name of the component, localized into the current language
  • each word of the name of the component, localized into the current language
  • the column the component is in, localized into the current language
  • the category the component is in (if any), localized into the current language
  • any custom search tags

So, for example, you can search for Panel Display using any of the following:

  • Tung.PanelDisplay_1x1 - the internal text ID
  • Tung and PanelDisplay_1x1 - the internal text ID split into sections
  • Panel Display - the name of the component (in English)
  • Panel and Display - each word of the name
  • Output - the column this component is in (in English)
  • Panel Displays - the category this component is in (in English)
  • light, lamp and screen - the custom search tags of this component. Currently search tags are not localized.

When you perform a search, the game generates search criteria for each component, as described above. If any of a component’s search criteria start with the text of the search, that component is listed in the search results. Searches are not case-sensitive.

Also, as shown in the video, you can do multiple searches at once by separating the search terms with a comma. In this case, a component can match one of their criteria with any of the search terms.

@ForLoveOfCats 2019-05-18

Yes the comma separated terms are what I was referring to by one of the search terms.

What I meant is that you are not giving all entries a score and then sorting by score, instead anything which does not have any of the search terms as an exact (case insensitive) substring of any of the searchable string data points. Is that correct?

@Jimmy 2019-05-18

Correct. Search results are ordered in the same way they are outside of search; currently there is no search ranking system.

@ForLoveOfCats 2019-05-18

I would suggest that rather than excluding non-matching items, give all items a ranking score based on how closely they match the search (could only take into account the search tag which has the highest rank or maybe average them all out? I dunno, would take some playing with it), prioritizing letters at the beginning of words, increasing the score awarded for each character match for each consecutive match, ect. Proper fuzzy search. It would be much more inefficient but give such better results, the most correct items will be closer to the top than currently, and it would be much more tolerant of mistyping. Either way any type of search is a win in my book ;)

@Jimmy 2019-05-20

Lots of good ideas there, thank you. Fuzzy search would be great to have!

@ForLoveOfCats 2019-05-15

Very nice animations on the section hide/expand arrows ;) Perhaps some smooth scrolling to seal the deal?

@Jimmy 2019-05-15

Excellent idea, thank you! I’ll look into smooth scrolling this week

@Jimmy 2019-05-15

Felipe claims he added emojis to the website, but he neglected to post any himself. Let’s see if it actually works:

Lorem 😂😂 ipsum 🕵️‍♂️dolor sit✍️ amet, consectetur adipiscing😇😇🤙 elit, sed do eiusmod🥰 tempor 😤😤🏳️‍🌈incididunt ut 👏labore 👏et👏 dolore 👏magna👏 aliqua. Ut enim ad minim 🐵✊🏿veniam,❤️😤😫😩💦💦 quis nostrud 👿🤮exercitation ullamco 🧠👮🏿‍♀️🅱️laboris nisi ut aliquip❗️ ex ea commodo consequat. 💯Duis aute💦😂😂😂 irure dolor 👳🏻‍♂️🗿in reprehenderit 🤖👻👎in voluptate velit esse cillum dolore 🙏🙏eu fugiat🤔 nulla pariatur. 🙅‍♀️🙅‍♀️Excepteur sint occaecat🤷‍♀️🤦‍♀️ cupidatat💅 non💃 proident,👨‍👧 sunt🤗 in culpa😥😰😨 qui officia🤩🤩 deserunt mollit 🧐anim id est laborum.🤔🤔

@Jimmy 2019-05-15

Hey look it worked, good job Felipe