Search Unity

Games [WIP] GearBlocks - Build working physics based machines and mechanisms [DEMO]

Discussion in 'Projects In Progress' started by danger726, Mar 24, 2015.

  1. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Ah yes, the wheels. They were one of the many tricky physics problems I had to solve!

    As there are no cylinder colliders in Unity / PhysX, I use a mesh collider that approximates a cylinder for collisions between a wheel and other objects. However, I can't use this technique for collisions / contact between wheels and the ground, because (being faceted) mesh colliders won't roll smoothly across the terrain.

    I did a write up a while back on the solution I ended up with, you can check it out on my blog here: https://tmblr.co/ZzNKAt1D-zxlq
     
  2. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184


    Just updated GearBlocks to use PBR (physically based rendering), here’s the before and after.
     
    Last edited: Nov 1, 2016
    Venryx likes this.
  3. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184




    First pass of new “Desert proving ground” map for GearBlocks, this (and other maps too eventually) will replace the old procedurally generated maps.

    I’ll be adding more details to this map as I go, but for right now it has a variety of terrain types (sand dunes, rocks, large and small bumps), as well as (most importantly) a large flat area to build on!
     
  4. JoakimCarlsson

    JoakimCarlsson

    Joined:
    Aug 27, 2014
    Posts:
    65
    It's been a long time since I last visited this thread, and oh boy. The game has changed, it's looking way better now.
    This is insane, good work!
     
  5. Weird-Beard-Guy

    Weird-Beard-Guy

    Joined:
    Nov 10, 2013
    Posts:
    26
    :O This is insane. I think you can really make at least a few games. Historical as well as Futuristic. Good Luck with this
     
  6. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Thanks guys! Yeah, trying to figure out exactly what kind of game to make out of this is surprisingly difficult!
     
  7. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    New demo build



    New desert map

    At long last, I have done away with the old procedurally generated terrain. I decided that it made more sense to have a few decent “hand crafted” maps in the game, rather than an almost infinite number of crappy ones!

    So, now in it’s place there is the new desert map. This is still a work in progress, I have a lot of details still to add to it, but the main thing for now is that it at least has a flat area to build on without stuff rolling away. In the full game I plan on adding other maps based in different settings (e.g. forest, grassland, salt flat, snow / ice, etc. haven’t quite decided yet).

    Rendering improvements

    Having upgraded to Unity 5 this allowed me to make the switch over to physically based rendering (PBR). Besides making things look pretty, PBR serves a practical purpose in that you can now visually distinguish materials (e.g. metal actually looks like metal now). It also makes it much easier to achieve consistent lighting across the whole scene.

    I’ve also upgraded the time-of-day system, and tweaked the post effects too.

    Saved game format

    The saved game format has changed slightly, so old saved games won’t work in this build. However, saved constructions from the previous build version (0.4.6034) should still load OK. If you have saved constructions from versions earlier than that, I’d recommend loading them in build 0.4.6034, then save them back out, they should then load properly into the new build.
     
    Last edited: Feb 27, 2020
  8. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    It’s been a while since the last update, so I thought I’d do a quick post on what I’ve been up to! A couple of weeks were taken up with travelling back to the UK for a bit, and I was sick all last week which took me out of action unfortunately. I have been working on the game though over the past several weeks…

    First person controller

    The current first person camera controller in the game is basically a prototype implementation. It’s buggy and missing a lot of features, for example: camera smoothing, crouching, head bob, and so on. My plan was to switch over to the excellent UFPS from Opsive (available on the Unity asset store: http://u3d.as/2Jc) which has all these features and more. Unfortunately that didn’t work out, mainly because I couldn’t bring across only the code I wanted from UFPS (character and camera controller) without either modifying it or also including a lot of other stuff I don’t need (e.g. inventory, weapons, damage etc.)

    I think UFPS is great as a starting point for a first person game, but trying to integrate it in at this late stage of a project probably isn’t practical. So now my plan now is to keep what I have and gradually improve it, probably stealing code from UFPS as necessary!

    Deprecated networking API

    I have a rudimentary networked multiplayer mode for GearBlocks, and in fact even the single player mode runs through the same code paths. I want to keep this working so that I have a good starting point should I wish to revisit multiplayer in the future. Right now I’m using the old Unity networking API, which was causing a bunch of annoying “obsolete API” compiler warnings, because it’s recently been deprecated in favour of their new system, UNET.

    I looked into what it would take to upgrade to UNET, using their high level API (HLAPI). Unfortunately there were all sorts of awkward problems with this (like needing to derive from NetworkBehaviour, which didn’t play nicely with my generic singleton implementation for some reason). The whole thing was turning into a massive change that would break the entire game until I completed it. Not to mention it’s still fairly early days for UNET and it’s changing quite a bit as Unity continues to develop it.

    Besides, ultimately I might be better off using their low level networking API, but that would obviously take even longer to implement. Or, perhaps using a third party system like Photon Bolt would be a better way to go. I’d need to spend a lot more time on this to figure out the best thing to do, so I’m leaving it for now. Instead, I um…disabled those pesky deprecated API warnings, there you go, job done!

    What’s next

    So, it’s generally been a frustrating few weeks, hopefully I can get back to being more productive now! I’ve been prototyping something for the game, not sure if it’ll work out yet, but I’ll be continuing with that.

    Also, I’m going to work on improving the construction controls, in particular to help new players pick up the game and get started. Well, that’s the plan anyway!
     
  9. Pixelith

    Pixelith

    Joined:
    Jun 24, 2014
    Posts:
    578
    This reminds me of a more in depth G-Mod. Which is awesome!
     
    danger726 likes this.
  10. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Some of the amazing constructions the GearBlocks community has built over the past year or so!

     
  11. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Here we are showcasing some more awesome builds from the GearBlocks community, thanks everyone!

     
  12. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Something a bit different in this video, just a brief demo of a fun little rendering effect I've been messing around with. It doesn't work properly with all the parts because they don't all have UVs yet, but other than that I'm pretty happy with it.

     
  13. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Well, 2016 has certainly been, shall we say, an "interesting" year! Perhaps many people will be glad to the see the back of it, but somehow I've a feeling 2017 won't be any less eventful. Anyway, here's hoping the new year brings good things to you all!

    Back in my little GearBlocks corner of the world, in many ways things have progressed pretty well this year, getting through the Unity 5 hurdle was definitely a big step forward. I'm a bit frustrated to not be further ahead with the game generally by now though. I'll just have to keep chipping away at it, it'll get there eventually. I'm very appreciative to everyone who has played the demo, built some amazing creations, and given me really useful feedback. It helps motivate me to keep going!

    Over the past couple of months I've been working on a bunch of different things. I was looking at improving the construction controls, but kinda got stuck with "designer's / programmer's block" if you can call it that. So while thinking on this some more, to keep progress going I did several other smaller tasks:-
    • Made a load of new parts (gears, control wheels, suspension parts, connectors and more).
    • Added more user settings (e.g. mouse look sensitivity and camera FOV).
    • UI tweaks.
    • Rendering effects.
    • Unity upgrade.
    • Bug fixes.
    Next week I plan on going back to the controls improvements, mustn't procrastinate any longer!
     
    Last edited: Jan 1, 2017
  14. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    I've been playing around with a translucent PBR shader in GearBlocks over the weekend. It's "paintable" like other materials except the paint colour is used as a tint. Should work nicely for glass, transparent plastic etc!

     
  15. JoakimCarlsson

    JoakimCarlsson

    Joined:
    Aug 27, 2014
    Posts:
    65
    Still going strong with this project! It's exciting to see all the new updates.
     
    danger726 likes this.
  16. prasadpatil290

    prasadpatil290

    Joined:
    Feb 23, 2017
    Posts:
    1
    i in trouble.....it showing only grey screen....and also not showing any part after pressing q (hold)...plz help !! block.jpg
     
  17. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    OK, time for a long overdue GearBlocks progress update. As I've mentioned in previous posts, I wanted to improve the construction controls, to try and make them a bit more approachable and accessible, and this is what I've mostly been working on over the past couple of months.

    Failed ideas

    I wanted to explore some new ideas in an attempt to improve part positioning and alignment, and also part resizing.

    So I tried making a prototype of a "snap to" grid aligned to the overall frozen construction (instead of to the currently highlighted part as it is now). While the player is positioning the selected construction ready for attachment, I had a 2D planar grid aligned to the frozen construction that the selection snapped to at unit intervals. The player could then move this plane up and down along its normal (also at unit intervals) using the mouse wheel, thereby allowing snapped positioning in full 3D space. There would also need to be some provision for snapping to half unit intervals, although I didn't get that far with it. This seemed promising initially, but what killed the idea for me in the end was the realisation that (unlike the current system) it doesn't easily allow for attachment at arbitrary angles, everything has to be aligned at 90 degree intervals relative to the frozen construction. At least I couldn't think of a practical way around this, and I certainly didn't want to make it less flexibile than what I already have.

    As for part resizing, I thought about separating it out into another tool (with handles that you drag around to resize the part), but not only is this more complicated to implement, I actually think it would be less convenient to use. Every time you want to resize a part you'd have to deselect it, switch to the resize tool, do the resizing, switch back to the builder tool, and select it again.

    So in the end I decided against making any radical changes to the current construction controls, and instead focus on improving what's already there. Let's go over the changes I ended up making.

    Construction alignment

    One issue with positioning parts is that the alignment grids aren't always easily visible. Also, because they're drawn on top of the parts themselves, it sometimes makes it hard to tell which parts are in front of each other, or even which part you're about to attach to. So I changed the grid textures to make them clearer, and modified the shader to fade them out slightly where drawn "behind" objects. You can see the difference between the old and new grid below.





    Another problem is that when you're aligning parts together, you don't know where the individual attachments will be created. So now during alignment, indicators are shown for the attachments that will be created, an example of this is shown below.



    Lastly, rotating the selected construction can be kind of awkward at times, and I wanted to see if could improve this in any way. I tried making the rotation be limited to one axis at a time during alignment, and that turned out to help a quite lot because it prevents "drift" away from the player's intended rotation.

    Part resizing

    One of the main problems with the current resizing controls is that they're non-obvious, particularly to new players, because there's nothing showing them what to do. As a first step towards improving this situation, I've now added a resize indicator that shows the available resizing directions (colour coded for the horizontal and vertical directions).



    I'm also going to add a new tool UI display that (among other things) will show which keys to use to resize in each direction. Hopefully both of these changes together will make resizing a bit clearer for the player.

    Attachment indicators

    The attachment indicators also suffered from not being very visible a lot of the time, so I modified their textures too, and also tweaked them to ensure visibility from all angles. Here’s an example showing before and after these improvements.





    Other improvements

    I've also worked on several other bits and pieces, for example:-
    • More user settings (such as mouse sensitivity for selection translation and rotation).
    • Better in game context sensitive hints.
    • Lights can now (optionally) have a key bound to switch them on and off, just like motors.
    • The construction frozen state is now saved / restored from saved games.
    • A whole bunch of bug fixes (many of these you guys found and reported back to me, so thank you!)
    Next up

    I'm fairly happy with how things turned out after the changes I made, yes the construction controls could still be better, but they're acceptable, and at this point I need to move on to other stuff really. There are one or two more small tweaks and bug fixes to do, but apart from that I'm done with the controls and ready to tackle the next thing.

    I want to get another demo build out fairly soon, but I still have a laundry list of small tasks to sort out before I can do that, so those are what I'll be looking at next!
     
    Last edited: Mar 1, 2017
  18. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    That's odd. The pink text at the top is curious to me too, that happens to be the only thing left in the game drawn with the old GUI Text component. You can see the font texture is there, it almost looks like the shader failed to compile, I've no idea why that would happen though.

    Can you let me know your machine specs? OS version, CPU, system memory, GPU, and video memory? Thanks!
     
  19. woodsynzl

    woodsynzl

    Joined:
    Apr 8, 2015
    Posts:
    156
    I've been silently following this project for a while! It just keeps on getting better, keep it up!
     
    danger726 likes this.
  20. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Over the last couple of weeks I've done some more work on the in game UI.

    I've removed the old text overlay that showed the name of the highlighted part, as it was positioned near the cursor and kind of in the way. Now I have a new overlay in the bottom right corner that shows not only the part name, but other details such as its mass, whether it's paintable or resizable, and info on its behaviour status.



    I've also added a similar overlay for when you're hovering over an attachment in a frozen construction. It displays the available attachment types that you can cycle between (highlighting the current attachment type), and it’ll also show info on other things like attachment integrity (if damage is enabled).



    During part resizing, rather than add yet another UI display to show which keys to use to resize in each direction (as I was originally thinking), I decided instead to just colour code the relevant parts of the hints text.



    Finally, to help the new UI elements fit, and clean up the look of the UI generally, I've also made the whole thing scale based on the screen dimensions. This means that (in full-screen mode), the UI elements appear the same size regardless of the screen resolution. I think this is a big improvement, especially at lower screen resolutions.
     
  21. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Here's just a brief update on what I've been up to over the past few weeks. Most of the work has been focused on further improving the usability of the game (better UI, controls, customisation, etc.)

    Construction controls improvements

    I've redone the part resizing input code so that now when you press a resize key it responds immediately (before it was kinda sluggish to respond).

    I've also made a tweak so that you can now freeze the selected construction in place while aligning to another construction, this can be useful to check positioning and so on before committing to attachment.

    Configurable key and mouse button bindings

    The main thing I've been working on recently is a complete overhaul of the input system. You can now fully customise key (and mouse button) bindings to the various actions in the game. There's now a new tab in the controls settings where you can set this up. You click the button for the action you want to configure, it'll then wait for a key press, that key then getting bound to the action.



    I've also modified the player controllable parts (e.g. motors) that have configurable key binding to work in the same way. This means you can now bind any keys to them, not just letters and numbers.

    The only thing still left to do here is to allow configuration of joystick / controller inputs, something I'll revisit at a later date.

    Improved graphics settings

    The other customisation improvement I've made is to the graphics settings. I've done away with the (vague and too high level) "quality settings", and set up proper options that'll give you more fine grained control when configuring the graphics quality vs. performance of the game.



    Other things

    Some other bits and pieces I've also done:-
    • More UI design tweaks and improvements.
    • Better audio mix, updating sounds, etc.
    • Various bug fixes.
    I'm working hard on getting another demo release out so that you can try all this new stuff out. Unfortunately there always seems to be something that gets in the way! Currently I'm in the middle of upgrading to Unity 5.6 which has broken some rendering stuff, so that's what I'm working on right now, hopefully I'll get this sorted soon.
     
    Last edited: May 18, 2017
  22. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Gah, I can't believe it's been a month already since the last blog post! It's been a frustrating time to be honest. I've been planning on setting up a company for a while, to put GearBlocks on a more official footing (it's something I should have done a long time ago really). The trouble is I'm having a hell of a time trying to think of a name for the company (all the ideas I've come up with seem to be already taken)! It seems ridiculous that a relatively trivial thing like this is holding me up, but hopefully I can figure it out soon and move on.

    In the meantime I have made some progress with the game though. The Unity 5.6 upgrade is now done, the rendering issues I was having weren't too bad to sort out in the end. Also, I was tired of having old placeholder part assets still left in the game, so I've finally removed / replaced / reworked the last of these.

    These are the new seat models I've made so far, I plan on adding more types & variations of seat later (any suggestions welcome!)



    Here are the new lights (again, at some point I plan on adding more styles / types of light). Their lenses are now paintable, so you can have any colour lights you like!



    It was a small change to make the wheel rims paintable too, so I decided to do that while I was at it.



    Well, the next demo release is pretty much ready to go now, it's just waiting on me getting the company set up, as I want to have that all sorted first!
     
  23. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184


    Playing around in GearBlocks today, built a tractor with a working piston engine & push rod steering. It could do with some proper wheels and the steering would work better with the ball & socket connectors, but I was limiting myself to parts available in the demo.
     
  24. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Selection points

    Over the last few weeks I've been working on fixing something with the construction controls that’s been bugging me for ages. I wasn't happy with the range of positions at which you could select a part, you could select it anywhere within its bounds, which wasn't really restrictive enough.

    Here's an example. You could select anywhere on a wheel, even though it only has one point that can attach to anything.



    Much better to restrict the selection point to always be at this attachment point as shown below, that way it feels more natural when attaching the wheel to another part.



    This next example is even worse. You could select anywhere on a seat, and then translate it so that the selection point was completely outside the seat which is just plain stupid.



    So now I restrict the selection point to be somewhere in the region on the bottom of the seat where its attachment points are, so you always have it selected in a suitable place ready to attach to another part.



    To accomplish this I had to rework some code so that it now automatically calculates the selection region based on where all the part's attachment points are located. The upside to this was that I could do away with explicitly specifying the allowed translation directions on each part. The less I have to manually setup per part the better!

    I also had to implement some new math functions to find the closest point on the part's selection region to the player's eye "ray". Took a while to do, but it's never a bad thing to add more stuff to my math toolkit I suppose, could come in handy for other things in the future.

    All this took way longer than I expected, it was only supposed to be a couple of day's work, sigh.

    Prop parts

    I've also added some new "prop" parts. Props are a new category of part that are the simplest objects in the game, they don't have a behaviour and they don't attach to any other part. The idea is that they can be used with the machines and vehicles you build or placed in the world to set up a scene to play in. For example, traffic barriers could be laid out to form a race track, the ball could be used in a Rube Goldberg machine.



    As with all the other parts, I’ll be adding more props as I go, any suggestions for these are welcome!
     
    Zeblote likes this.
  25. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Last week I decided to take another look at the wheel physics implementation, in particular the tire friction model. First let's quickly recap how the wheel physics works in GearBlocks.

    Wheel physics recap

    Every update I find the contact point on the ground directly below the wheel and position a configurable joint there. This joint is then connected to the wheel at the closest point on its outer edge to the contact point on the ground. The joint has a linear limit set up to prevent the wheel going below the ground, which provides the wheel to ground collision response.

    For friction between the tire and ground, I set up the configurable joint’s velocity drive to constrain the wheel's velocity at the contact point to zero, with the maximum force on the drive being set to the friction force. To calculate the friction force, I use a method inspired by the Coulomb damping model, where the friction force equals the product of a friction coefficient and the normal force at the contact point (i.e the force preventing the wheel from sinking into the ground).

    Previous tire friction hack

    To find the normal force I need to know what force the configurable joint's linear limit is applying to keep the wheel above the ground. However, it used to be that in Unity there was no way to access this (even though it was available in PhysX), so I had to estimate the normal force by taking the total mass of the construction, dividing it by the number of wheels, and multiplying it by the acceleration due to gravity. Basically a total hack, because it assumed the vehicle's weight was always distributed exactly evenly over each wheel.

    Improved tire friction

    Well the good news is it turns out that fairly recently the joint force was made available in Unity (via Joint.currentForce), so I've now switched the implementation over to use this to find a proper normal force. This means that in a vehicle, weight distribution now affects tire grip, and because the normal force is now being calculated dynamically, weight transfer also affects grip in the way you'd expect, which is pretty cool. This all sounds great, and is a definite step in the right direction, but there's a problem.

    Formula magic

    By using Coulomb damping I'm effectively assuming that tires are rigid (i.e. non-elastic) which of course they're not. In reality a tire's grip changes depending on how much it is sliding across the ground (tires actually develop peak grip when sliding slightly). Not only that, the longitudinal (forward and back) and lateral (side to side) grip of a tire behaves slightly differently. So most driving simulations instead use some form of "friction curves", equations that you plug slip amounts into and get friction forces out. The industry standard is the Pacejka tire models, sometimes known as "magic formulas", these are empirical models that have been made to fit real world measured data, the equations themselves don't have any basis in real physics as far as I can tell.

    Sounds simple enough, so why not use the magic formulas? Well, after looking into this for a bit, I can see several problems:-
    1. The equations for the Pacejka curves themselves are complicated and have a ton of tuning parameters, something I'd prefer not to have to deal with. Probably overkill for what I need anyway.
    2. The slip values used to lookup into the curves are actually slip ratios. The upshot being that at low velocities numerical instability becomes an issue (and at zero velocity you've got a divide by zero - the slip ratio is undefined!)
    3. Because you need to evaluate longitudinal and lateral slip separately, there's the question of how to combine the resulting separate friction forces. You can't just add them together because a tire can only develop so much grip at any one time, the more longitudinal grip you "use up", the less lateral grip is available, and vice versa. This effect is sometimes known as the tire's "traction circle".

    I'm sure there are ways around all of these problems. The Pacejka equations could be substituted with something simpler for example, and I've seen various ideas out there that attempt to properly combine longitudinal and lateral slip. The slip ratio numerical instability issue I'm less sure about at the moment, apparently a lot of driving sims switch to another simpler friction model at low velocities to get around it, seems a bit hacky though.

    Another related issue is that I'm not even differentiating friction levels between different surfaces (e.g. tarmac vs. dirt) yet, so perhaps a realistic tire friction model isn't worth it at this point? Anyway, something to keep thinking about and revisit again in the future.
     
  26. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    So, um, that demo release I've been promising, where is it you might ask? The good news is, it's ready to release (has been for a while actually). The last thing was to set up an installer for it and that's all done now (if you're wondering, I used Inno Setup for this, found it a super easy tool to use, with great results!)

    Unfortunately, I can't release it just yet as I'm still working on getting my company set up. This is turning out to be more complicated and expensive than I first realised. Incorporating the company itself is easy, but because I've already been developing GearBlocks for a while, I'll need to transfer GearBlocks IP to the company, which complicates things and adds to the cost (accountant fees on top of the lawyer fees!) Anyway, I'll keep plugging away at this and hopefully get it done in the next week or two.

    In the meantime I've been adding more parts - some new sliding rack gears with integrated ball joints / hinges (makes for neater steering systems), more lights, and a seat. I've also implemented limited slip functionality in the differential gear, with configurable "locking strength", should keep that wheel spin under control!

    I plan on adding various types of sloped / curved beams and plates to the game, this will make constructions look a lot better (and save on the number of parts needed in a lot of cases). Next week I'll start work on what should be the simplest of these, a resizable sloped beam.
     
  27. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Here's what I've been up to over the last couple of weeks. I'm still working on the company set up stuff, it's unfamiliar territory for me, so I had to do a bit of research and get advice from some people. I won't bore you with the details, but it seems there's no getting around the complexities that require both an accountant and lawyer. This is going to cost me a lot of money, so I want to be sure before going ahead with it!

    Upcoming demo

    I'll upload the demo update as soon as the company is sorted (should be soon now), but in the meantime, here's a sneak peak at the changes that will be in it:-
    • Improved builder tool controls and usability:-
      • Changed alignment and attachment indicators for improved visibility and clarity.
      • Improved part selection (restricting selection location to where part can be attached).
      • Better selection rotation behaviour during alignment.
      • Improved part resizing response to key presses.
      • Added part resizing indicator to show available resize directions.
      • During alignment attachment indicators are now shown for any attachments that will be created.
      • Selected construction can now be frozen in place during alignment.
    • More user configurability:-
      • Configurable key bindings for the various actions in the game.
      • Replaced single graphics "quality level" setting with individual settings for more fine grained control.
      • Added many other options (such as mouse look sensitivity and invert, camera FOV, etc.)
      • Improved sound options (volume controls and speaker configuration).
    • UI improvements:-
      • Improved screen layouts and UI elements.
      • UI is now scaled based on screen resolution.
      • New part and attachment info UI overlays.
      • New game stats UI overlay.
      • Improved in-game context sensitive hints.
    • Updated and improved parts:-
      • Improved part behaviour key binding.
      • Differential gears now have limited slip behaviour, with tweakable "slip limit strength".
      • Lights can now (optionally) have a key bound to switch them on and off, just like motors.
      • Beams now resizable down to 1 unit in length, and plates from 1x1 to 25x25 units in area.
      • Better wheel friction behaviour.
      • Increased max spring rate and damping values for spring dampers.
      • All part models (except wheels) now textured.
      • New light parts (now with paintable lenses).
      • New seat models (replacing old ones).
      • Wheel rims now paintable.
    • Rendering changes:-
      • Construction materialise / dematerialise effect.
      • Part paint application fade in / out.
      • Corrected part paint colour (de-gamma'd, it now visually matches colour shown in UI).
      • Upgraded time-of-day system.
    • The construction frozen state is now saved / restored from saved games.
    • New and improved sound effects (toolbox, footsteps, ambient loop).
    • Minor tweaks to desert proving ground map.
    • Bug fixes.
    As usual I've updated any parts that were already in the demo, but I'm not adding any additional ones, all the new parts I'm making are for the full game only!

    Slopes and wedges



    On the subject of new parts, I've now implemented resizable sloped beams and plates, as well as resizable wedge plates.



    Designing their shapes was a bit of a challenge because I had to find a compromise between these three competing requirements:-
    1. Be easily representable by box colliders for efficient physics.
    2. Have plenty of room for attachment points.
    3. Look good when combined with other slopes, plates, etc.
    The wedge shape was the trickiest to represent with box colliders. I contemplated using a convex mesh collider for it, but I wanted to avoid this as they are generally less efficient for physics, and I also have part intersection tests in the game that only work for primitive colliders. So instead I created a system to dynamically add box colliders, three for the wedge edges, and then recursively adding more to fill in the wedge interior (the larger the wedge, the more interior colliders are needed). An example of this can be seen below.



    All resizable parts in GearBlocks use procedurally generated meshes, so I had to implement mesh generation for these new slope and wedge parts. This wasn't too difficult but did require a fair bit of refactoring of my procedural mesh system to allow for these more intricate shapes.

    Here's a comparison of the Desert Buggy construction, the original version vs. one I made using the new slope and wedge parts.



    Not only does the slopes and wedges version look way better, it uses nearly 50 fewer parts than the original!

    In the future I want to add a compound sloped plate (i.e. a "corner" piece), as well as curved beams and plates. The trouble is, the colliders for these will be even more tricky to set up. I might need so many box colliders to represent these shapes that it wouldn't be practical, so I may well have to resort to convex mesh colliders for these. Anyway, something I'll come back to later.

    Construction interface problems

    The sloped plate part is the first part in the game that is resizable along all three axes. Unfortunately this particularly highlights the awkwardness of the current part positioning and resizing interface. I'm not sure what I'm going to do about this yet, but I think I'll have to revisit the construction controls yet again. There has to be a way I can make this better, but I'm just not seeing it right now!
     
    Venryx likes this.
  28. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    New demo build



    Well, at long last the new demo build is out!

    This dev diary highlights some of the changes:-



    SmashHammer Games

    My company is now incorporated, SmashHammer Games is born! I’m still waiting on the accountant to do his part of the process, hopefully this will be sorted soon, but I don’t think this should hold me back from moving forward with the game in the meantime.

    Bugs and memory leaks

    I was actually ready to release the demo a couple of weeks ago, but I was doing some last minute testing, and noticed some performance slowdowns in certain situations (for example, when highlighting a part). I also noticed some memory leaks and several bugs that I hadn’t spotted before, not good!

    So I decided to hold off releasing it, to fix these issues first. This ended up requiring fairly significant refactoring and reworking of some of the code, so took quite a while unfortunately. Oh well, at least it’s done now!

    Saved file location

    The saved file locations have changed (they’re no longer in game folder). The new locations are:-
    • Saved games: %USERPROFILE%\AppData\LocalLow\SmashHammer Games\GearBlocks Demo\SavedGames
    • Saved constructions: %USERPROFILE%\AppData\LocalLow\SmashHammer Games\GearBlocks Demo\SavedConstructions
    Saved games and constructions from the previous build (0.4.6095) should still load, but you’ll need to copy them into these new locations.
     
    Last edited: Feb 27, 2020
  29. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    It's been a few weeks since the demo release, so it's high time I think for an update on what I've been working on since then!

    Rotation controls

    As I've mentioned in the past, I'm still not entirely happy with the construction interface. One aspect of this is the way you rotate the selected part while aligning it to another part prior to attaching it. The current method of using the mouse to rotate around various axes is OK once you get used to it, but I worry that it's a bit awkward to use, particularly for people new to the game.

    So I tried prototyping a system where you use a key to cycle between the available orientations. The trouble is, there can be up to 24 possible orientations (e.g. 6 sides on a block, and 4 orientations per side, so 6 x 4 in total). I found this to be way too many to cycle between and was rather frustrating to use.

    So I tried breaking it up into cycling between alignment axes (e.g. the 6 sides on a block) with one key, and cycling between the 4 possible orientations around the current alignment axis with another key. This was a bit better than using just one key, but still didn't feel good to me. Perhaps this was because it was sometimes hard to tell which way the part had just rotated, or which way it was about to rotate on the next cycle.

    I'm not sure that these ideas offer much, if any, improvement over the current mouse based method of rotating. Oh well, another failure! I guess you have to try these things, but I'm gonna leave this for now.

    Game events

    In order to keep the different code modules in GearBlocks decoupled from each other, I used messages (i.e. Unity's SendMessage) to communicate between them. I wasn't that happy with the way SendMessage uses a string lookup for the method name though - not very efficient, and there's the possibility for name mismatches.

    So I switched all of these messages over to use Unity's event system. Events are now specified in interfaces that derive from IEventSystemHandler, and any code that needs to receive a particular event implements the relevant interface. To send an event to a game object, I use Unity's ExecuteEvents helper functions. I created a system that multiple game objects can register themselves with to receive a particular event, to allow for efficient event broadcasting.

    UI events

    Not to be confused with the event system, Unity also has something called UnityEvents. These are great for when you want to hook up event handlers to events in a scene or prefab, rather than via code. I found these perfect for my UI code, so I switched this code over from using C# events to instead use UnityEvents.

    Code architecture

    The GearBlocks code was long overdue for some reorganisation, in particular I wanted to divide all the modules up into relevant namespaces. This is really valuable because it can highlight bad or unexpected code dependencies, and helps enforce a clear code hierarchy. Once I did this I found one or two suspect dependencies that I had to fix, but nothing too bad fortunately. It definitely feels better to have the code nicely organised now!

    Worm gears



    Finally, last week I implemented worm gears in the game. Happily, my plan for how to set up the physics constraints for this worked out first time! The implementation still needs one or two tweaks, but I'm pleased with how it turned out. As part of this effort I also simplified the existing gear engagement code somewhat, which should make it slightly more efficient.
     
  30. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Apologies for the lack of updates lately! I've been working on implementing pulleys and belts in the game, and I was hoping to get them finished before posting an update. However, as always seems to be the way, they're taking longer than I expected. They're not quite done yet, but I have made enough progress now that it's worth talking about where things are at.

    Pulley physics

    The first thing I had to figure out was how to physically constrain a pair of pulleys together such that they would transfer motion and torque correctly. My plan was to use PhysX constraints (as exposed by Unity's ConfigurableJoint) to accomplish this, in the exact same way I do for gears.

    However, pulleys differ from gears in two important respects:-
    1. Pulleys transfer motion and torque over a distance, through the belt that connects them (unlike engaged gears, which must always be adjacent to one another).
    2. A pair of pulleys linked by a belt rotate in either the same direction or opposite directions, depending on whether the belt is in an open or cross configuration respectively (unlike a pair of engaged gears, which always rotate in opposite directions).
    The first idea I tried was to set up a constraint whose anchor points were positioned on the edge of each of the pulleys, with motion locked along the tangent vector as shown below for two pulleys A and B:-



    However, this didn't work well at all because the constraint anchor points were separated by such a long distance. The pulley motion was unstable at anything other than very low RPMs.

    So the next approach I tried was to instead calculate the two circles centered on each of the pulleys, whose radii are in the same proportion as the pulley's, and whose edges touch each other. Then I placed the constraint anchors on the edge of these circles, represented by the dotted lines in the diagram below for the two pulleys A and B (again, motion is locked along the tangent vector):-



    Note that these dotted circles are only used to position the constraint anchors, they aren't visible and don't interact with the world in any other way!

    This method seems to work pretty well, it also easily allows for a cross configuration belt in a similar manner (by calculating proportioned circles whose edges instead touch in between the two pulleys, and positioning the anchor points where they touch).

    Implementing pulleys in game

    Actually getting the pulleys functional in the game required a lot more work beyond just the physics constraints. I wanted to allow the player to link an arbitrary number of pulleys together in whatever order they like, to form a chain that determines the route the belt takes through the pulleys.

    For this I created infrastructure to associate or "link" parts together (or more specifically: link their part behaviours together). This needed to generalise beyond just pulleys, because I plan on also using it to link other parts together in the future (e.g. batteries, switches, motors, and eventually, more advanced control systems). It also needed to facilitate restrictions being applied (for example, in the case of pulleys, only allow linking if the pulleys are coplanar, and only allow each pulley to be linked to a maximum of two others).

    Based on the order the pulleys are linked together, I also implemented a system to automatically calculate the belt routing (i.e. which side of each pulley the belt should go), which is then used to determine whether to use an open or cross configuration for the constraint between each pair of pulleys, as well as for positioning the visual representation of the belt.

    I wanted pulleys to be able to move around slightly when the construction is unfrozen, but obviously there's only so far a belt can plausibly stretch! So I wrote some code to deactivate the belt (both constraints and rendering) when any of the pulleys move too far from their original position, giving the appearance that the belt "broke".

    This work is complete now, and the pulleys are working in game. There are still a couple of major pieces left to do however:-
    1. Right now the links between the pulleys are hard coded just so I have something to test with. I still need to make a linker tool to allow the player to create and destroy the links themselves, as well as a UI to show these links.
    2. Currently I'm just using debug draw lines to visual represent the belt, so I need to implement some code to generate a proper render mesh for the belt.
    But for now, here's an example of some pulleys linked together, the yellow debug lines showing the links, and the black ones representing the belt:-



    So lots left to do, but this should be really cool once it's done, and I'm excited about the possibilities that the linker tool will allow for with other parts in the future!
     
  31. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Part 1 of a series of videos demoing some of the fantastic GearBlocks community builds from last year. I meant to do this at the end of the year, but I was working on adding a third person camera to the game and I wanted to wait until that was in, as it better shows off these creations!

    Parts 2 and 3 will be coming soon…

     
  32. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    New demo build 0.5.6628

    Time for another long overdue demo release, and an update on what I've been working on recently!

    Linker tool

    After the last update where I talked about the pulleys and linker tool that I was working on, I have since completed the first pass implementation of the linker tool, and links between pulleys can now be set up by the player (rather than being hard coded).

    However, the linker tool goes far beyond just pulleys and belts, my intention is that it'll be a general way to associate various part behaviours together (e.g. batteries, switches, motors, and eventually, more advanced control systems), and this introduces the one major wrinkle I still have to figure out.

    The thing is, parts can potentially have multiple behaviours associated with them, which means in theory there could be multiple links between two parts. I need to decide whether to either prevent multiple links (and in which case, how to do this in a way that makes most sense), or allow for them (in which case, how to represent them to the player via the UI, and if the player should have the ability to create links between individual part behaviours).

    I also still need to add UI indicators, both to show those links already existing, and a link as it's being added or removed (right now I'm still using debug lines).

    At this point I decided to have a break and work on some other stuff instead, but I will be getting back to the linker tool very soon.

    Third person camera



    I've now added third person cameras to the game, both for when the player is walking around, and for when they're seated. I debated doing this for a while actually, because I don't currently have a proper player model, but I finally relented mainly because it's so much fun to be able to see vehicles from the outside as you're driving around!

    The player models and animations I'm using are just placeholders that I put in ages ago for the prototype multi-player mode. Of course this now forces the issue - I now have to decide what the player character(s) should look like, as well as source the models for them, and put in better animations. Looks like I've just created a load of more work for myself!

    Wheel physics revisited



    OK, this is the big one. It wasn't supposed to be a big deal, but ended up taking several weeks to sort out! I wanted to build on the "proving ground" aspect of the desert map in the game, so I added some bumps and ramps (for testing vehicle suspension and so on). However this highlighted a significant problem with the wheel physics.

    Let's briefly recap how the wheels worked up until this point. First the wheel finds where it contacts the ground, by firing a Raycast towards it (perpendicular to its rotational axis) to find a contact position and normal. Then, it uses a ConfigurableJoint connected to the wheel's rigidbody, that every update gets repositioned using the contact data, and has a linear limit set up to provide the collision response. If you're interested, I did a detailed write up on this a while back: http://tmblr.co/ZzNKAt1D-zxlq

    Using a Raycast to find the ground contact point was acceptable on terrain with a smoothly changing gradient, but fails once other collision shapes besides the base terrain are introduced (such as boxes, spheres, etc.) for the wheels to roll over.



    You can see here in this example that the Raycast can't "see" the box, so the wheel inter-penetrates it. But worse, if the wheel continues to move in the direction shown, the Raycast will eventually hit the box, causing the contact point's height to change instantaneously, pushing the wheel up with a large impulse.

    So I wanted to come up with a new technique to find the contact point that would meet some important criteria:-
    1. It should ensure that the contact point's position changes smoothly with no discontinuities.
    2. It should allow the wheel to accurately roll over box, capsule, and sphere colliders.
    3. It should not change the wheel's behaviour on the base terrain (this can be very sensitive, particularly for vehicles traveling at high velocities).
    4. It should not incur any additional performance cost over the existing solution.
    I experimented with many alternative ideas, including using a bunch of BoxCasts to approximate a cylindrical shape, but everything I tried failed one or more of these criteria. That is, until I eventually settled on using a single CapsuleCast in the downward direction, whose radius is the same as the wheel's.

    However this clearly has similar problems to just simply using a CapsuleCollider for the wheel. For example, if the wheel is tilted to one side relative to the ground, we get a contact point outside of the wheel, coming from one of the capsule's "end caps". To get around this, I effectively clamp the contact point to be within the wheel's outer rim, as shown in the diagram below (this time viewing the wheel end on):-



    This assumes that the terrain's gradient doesn't change too much between the found contact point and the final clamped point!

    Another problem is shown here, where the CapsuleCast would find a contact point on the box in this example, not the point on the ground that we actually want:-



    To get around this, I simply discard any contacts coming from colliders outside the planes indicated by the dashed lines in the diagram above. So in this example the box's contact point would be discarded, and the ground contact point is used instead.

    So all in all, this technique is a bit of a kludgy approximation of a true cylindrical collider, but it actually seems to work quite well. I'm pretty happy with the results!

    Other stuff

    I've also done load of code refactoring, bug fixes, UI improvements, rendering improvements (post processing effects, lighting), and other miscellaneous stuff over the past few months. Check it all out in the new demo build, have fun!
     
    Last edited: Feb 27, 2020
    Edy likes this.
  33. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Here's part 2 of this player creation's series, some very cool stuff in this one. The final part will be uploaded very soon.

     
    Last edited: Mar 10, 2018
  34. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    The last video in this series showcasing GearBlocks player builds from last year, this one themed mostly around cars and trucks.

     
  35. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Wow, the past few weeks have been rough as far as productivity goes! First my PC blew its power supply, so I couldn’t work for a couple of days while I was waiting for a new one and then installing it. Then this week I was totally wiped out by a nasty cold and got pretty much no work done all week. I guess that’s the way it goes sometimes, really frustrating though.



    Anyway…I have now finished the pulleys and belts, barring a few minor bugs here and there. The belt rendering is now done and working nicely, the belt automatically routes its way around pulleys based on how they are linked together, and seeing the belt really makes the behaviour of the pulleys appear more convincing. Have to say I’m pretty pleased with how it all turned out!



    I’ve also added a “pulley whirr” sound that changes based on the pulley’s RPM, and a “belt snap” sound for when the belt breaks (this happens when pulleys move too far from their original position). These details all add to making the pulleys and belts seem “real”!
     
  36. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Sorry for the radio silence over the last couple of months. Here's an update on what's been happening, there's a lot to talk about!

    Collision impacts, and damage

    I've simplified and optimised the construction modification code and the way attachments are handled. This means that adding or removing parts from large constructions is now noticeably faster, but there's still more optimisation work to be done in this area.

    Being able to quickly break attachments without causing frame rate drops is a requirement for the damage system, and I've been revisiting this too, fixing a few bugs that had crept in. It still needs more work, but here's an example of the damage system in action as it is right now.



    On a related note, the collision impact sounds have been a source of complaint for some, and I agree! There are too many collision sounds when parts are merely sliding past one another. I'm currently working on overhauling the collision impact system to make the sounds behave better, and the plan is that this will improve the damage system at the same time.

    Servo and stepper motors

    It's been suggested that you should be able to set the servo motor target to angles greater than +/- 90 degrees, this was a perfectly reasonable request and sounds like it should have been an easy thing to do! However, due to the way I was interpolating between the servo's current and target angle, it would always rotate through the smallest possible angle. Which meant that for a range of greater than 180 degrees it could easily end up rotating in the wrong direction towards the target angle.

    I've now completely re-implemented the angle interpolation code to work a different way, so that it maintains the correct rotational direction. Now a servo motor's max angle can be set to +/- 180 degrees.



    Likewise, the stepper motor's step angle can also now be set up to 180 degrees. Here are a couple of examples, one with a step angle of 45 degrees, one with a step of 180 degrees.



    I've also fixed a bug that would sometimes cause a servo motor's centre "resting" angle offset to be incorrect after loading a saved game. And finally, I've lowered the minimum speed for servos and steppers to 1 RPM, as I think it's sometimes useful to be able to go that low.

    Linker tool

    I've continued work on the linker tool, creating the first pass implementation of an indicator for it, this can be seen below with some pulleys (notice also the automatic belt routing, sweetness!)



    I think I now have a solution for how to handle parts that have multiple linkable behaviours, but I need to start implementing it to really see if it'll work out.

    Resize indicator

    I've added a new indicator to show the selected part's bounds during resizing, this was particularly needed for parts that can resize along all three axes (e.g. sloped plates) to make things clearer for the user.



    UI stuff

    Up until now each part behaviour has had a specific pre-created UI with all of its elements (key bindings, sliders, checkboxes, etc.) laid out ahead of time. This was very inflexible and made it awkward to add or change which user adjustable parameters a part behaviour exposed. So I've now removed these hard-coded UIs and replaced them with a generic part behaviour UI implementation that automatically populates itself based on what parameters a particular part behaviour exposes. This will make adding new part behaviours (and modding support!) much easier in the future.

    I've also modified the world tool construction UI to allow for multi-selection, this allows you to select multiple constructions at once and perform an operation (such as delete, freeze, etc.) on them all in one go.

     
  37. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Collision exposition

    As I mentioned in the last dev update, I've been working on re-implementing the collision contact system, which is used for triggering impact sounds and applying damage to constructions. I've now finally completed this work, not without some challenges along the way though, and it ended up taking far longer than I was hoping. Not to mention my video card died and my Internet connection went down last week, fun times!

    Apologies for the wall of text, but here's my attempt to explain what I've been up to.

    Impact overload

    The old collision code dated from the early prototype days, and simply played an impact sound (and applied damage to the construction) directly in the OnCollisionEnter() event handler. This event gets triggered once for every collider pair that makes contact, which can end up being a lot particularly if there are many moving parts in a construction, and meant that way too many impact sounds were being triggered concurrently.

    Also, I've been working on adding sliding sounds for when parts slide past one another. This requires continuously tracking collision contacts, for which I use the OnCollisionStay() event. Again, this event gets triggered once for every contacting collider pair, except that unlike OnCollisionEnter(), it gets called every fixed update for the duration that the colliders are contacting one another, so the performance cost of any code in the event handler becomes a real concern.

    Unity performance woes

    On the subject of performance, the overhead for Unity to collect the collision contact data is one thing, but what I find even more frustrating is the way it must be accessed. For every single collision contact, a call from the Unity engine (unmanaged C++ code) into the C# script is made via an OnCollision...() event, with an attendant GC alloc for the collision data being passed into the event handler. This means in my "worst case" tests where I had thousands of collision contacts per update, I was seeing a performance cost in the tens of milliseconds, and thousands of GC allocs totaling a few MB. This cost is just for reporting the collision contacts, and does not include the physics sim update or anything else.

    I wish it were possible to access all of the per update collision contact data in one call, preferably into a pre-allocated buffer, but for now we're stuck with the OnCollision...() events. Hopefully at some point Unity will improve this situation!

    I tried to find a way of eliminating OnCollisionStay() while still keeping the sliding sounds working. It seemed like it should have been possible because you can still keep track of what colliders are currently contacting by using OnCollisionEnter() / OnCollisionExit(), and then get the velocities from their rigidbodies. Unfortunately what you don't have is the new contact position and normal each update, which are required to calculate the relative velocity at the point of contact, necessary for the sliding sounds to work properly. I tried fudging my way around this by estimating these values, but couldn't come up with a solution that worked reliably.

    In the end I resigned myself to keep using OnCollisionStay(), and turned my attention to optimising the code inside the OnCollision...() event handlers as much as possible, and consolidating the collision event data into something more manageable.

    Discard and merge

    The first step was to discard any collision contacts whose separation is larger than a small threshold value, happily this eliminated most of the spurious impact sounds that were being triggered when parts were merely sliding past one another.

    The second part was to merge collision contacts such that for each update, only one contact is considered per Rigidbody pair / PhysicMaterial combination. This means that, for example, a construction with a large number of parts all made of the same material and all rigidly attached together will only generate one impact or sliding sound. The most important thing was to perform this merging as efficiently as possible because the OnCollision...() events can be called so frequently; it was crucial to avoid any computation, conversion, GetComponent...() calls, etc. inside the event handlers.

    To keep track of the currently active contacts, the system now uses a dictionary whose keys are a struct containing the two Rigidbodies and the PhysicMaterial (these are all available directly from the data passed into the event handlers). The dictionary's values are a struct containing the contact position and normal, the merging happens by only keeping this data for the contact with the smallest separation, the rest are discarded. Then every update this dictionary of active contacts (of which there aren't that many due to the merging) is looped over, calculating the required relative velocities, and updating the sliding sounds accordingly.

    To mitigate the OnCollisionStay() performance overhead further, I also added an option in the game-play settings to disable it, for players with low end machines and / or particularly complex constructions. This effectively disables the sliding sounds, but the impact sounds still work, so it's not the end of the world.

    Audio materials

    Once ready to trigger an impact or sliding sound, I wanted to add some variety and sophistication to the sounds, while also making configuration easier. So now, rather than each part explicitly referencing which AudioClips to use, the system automatically maps from the PhysicMaterial to an "audio material". Each audio material specifies the AudioClips to be played on impact and during a slide. The pitch of these sounds are scaled based on the mass of the part that is colliding, and there can be different AudioClips chosen based on the pitch scaling factor.

    I also added support in the audio materials for a "rolling sound" (played based on the angular velocity of a part when it's contacting something). This allowed me to make the wheels (which have had sliding and rolling sounds for some time now) use the same unified system. I do love me some unification!

    AudioSource pools

    Despite the aforementioned reduction in number of collision sounds being triggered, there's still no real limit on how many could be triggered concurrently. Also, each part behaviour might have a sound playing (e.g. motor whine, gear whirr, propeller wash, etc.) which is only limited by the number of active part behaviours.

    To bring this situation under control and place a hard cap on the number of AudioSources, I implemented a pooling system. This pre-creates a fixed number of AudioSources and keeps track of which ones are currently in use. The collision contact system and the part behaviours can request to play an AudioClip via the pool, and if a free AudioSource isn't available the request is ignored. Once an AudioClip has stopped playing, the corresponding AudioSource in the pool is automatically freed up to be available for a future request.

    Damage propagation

    In the game, damage (based on the collision impulse) is only dealt with in the OnCollisionEnter() event handler, not OnCollisionStay(). However I still wanted to optimise this as much as possible, so rather than applying damage directly in the handler, it is now accumulated over an update. The total damage is then applied once per update (this is where the damage is divided up and propagated out to part attachments).

    I still have some work to do on the damage system but this at least moves the code out of the event handler, and means that if I need to increase the complexity of the damage propagation code, it shouldn't affect performance too much. This is a topic I'll be revisiting in a future update.
     
  38. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Glitch fixes, demo update soon

    Last week I fixed a problem that someone found while playing the demo, player feedback is so valuable and always much appreciated by the way! Here's the scenario; the player deletes a jointed attachment (e.g. rotary, slider, etc.) between two intersecting parts, but the parts still belong to the same construction after the deletion. Physics will consider these parts to be inter-penetrating, and if the construction is unfrozen, it'll try to force them apart. This can sometimes cause your constructions to jump all over the place like they're possessed. Here's an example of the problem.



    The solution I came up with was to keep track of the intersections left after attachment deletion, and prevent the construction from being unfrozen until they are resolved. The player can do this by deleting other attachments until the intersecting parts are no longer part of the same construction. Any unresolved intersections are now shown by a red cross as can be seen below.



    I've also been working on a bunch of bug fixes, mostly regressing issues introduced by recent changes. Another more serious problem was a crash that sometimes happened when quitting the game, the Unity error log didn't point to anything obvious in my script code, and I couldn't find any other devs on the forums having a similar issue. After a lot of trial and error I found which version of Unity introduced the problem. So I rolled back to 2017.4.2 for now, any 2017 version after this seems to have the crash (I haven't tried any 2018 releases yet). I don’t know what was changed that caused this crash, I didn't find any clues in the Unity change logs. After the next demo release, I'll just upgrade to the latest 2018 build and with any luck the issue won't reappear.

    Speaking of the demo, I should be ready to put the next update out in a day or two. I finally got my new video card today to replace the one the died, so I'm now able to do some final testing before the release.
     
  39. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    I had to fix a few last minute issues as is usually the way, but finally here’s the new demo release as promised. Enjoy!
    This video goes over some of the changes in the new build:-

     
    Last edited: Feb 27, 2020
  40. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Optimisations and explosions

    As I've alluded to in previous updates, the damage system is still a way off from completion, so that's what I've been working towards over the last month or so. One challenge is to design a system to propagate and accumulate damage in a way that is, if not realistic, at least plausible, as well as making sense to the player (without being frustrating or annoying).

    Before I can get to this though, there is a more fundamental problem. Breaking parts off a construction due to damage requires efficient construction modification code, and the existing system just isn't fast enough.

    UI Optimisations

    The first problem I looked at was with the construction list in the world tool UI. Whenever a construction is created or destroyed, this list in the world tool UI gets updated accordingly. When a part gets broken off a construction, it's re-parented under its own new construction GameObject, and this process was getting slowed down by the world tool UI being updated.

    So now the UI elements in this construction list are held in a pre-allocated pool and used / reused as needed, which avoids the performance cost and GC alloc of instantiation when a new entry is added. Also, the UI update code now queues up any new constructions and only adds one element to the UI per frame, this results in a slight visible delay as the player sees the UI updating itself, but avoids a single frame performance spike. In fact I made these changes to all other UI screens too that have a large list of entries (for example, the saved game screens).

    Construction modification code optimisations

    I've now also optimised the construction modification code (actually I had to completely restructure it) to be simpler and more efficient. It now uses fewer server-to-client RPC calls, only one per player operation (operations being things like attaching a part, deleting an attachment, etc.) There are less GC allocs too, as it now reuses many of the temporary data buffers these operations require.

    These changes so far have made a big difference. I hacked in a key so I can trigger the deletion of all attachments in a construction for testing purposes, as you can see in the example below. In this example the cost of breaking the attachments went from around 60ms to less than 25ms on my machine, still a significant performance spike, but definitely moving in the right direction.



    The major remaining performance cost is with instantiating new construction GameObjects, and also the Rigidbody GameObjects that live under them (as I mentioned before, parts get re-parented to these when they're broken off an existing construction). So, just like with the UI elements, to solve this I'm going to need pre-allocated pools of these GameObjects. However before I do this, to make life simpler, I need to remove all references to Unity networking stuff from the constructions. Which brings me to another issue...

    Unity networking API woes

    GearBlocks is still using the old RakNet based Unity networking API, which has been deprecated for a while (and now completely removed from Unity 2018.2). I was waiting for Unity's replacement for it - UNET, to be a bit more mature before I switched to it, but sadly UNET has now also been deprecated. Apparently there's another replacement solution coming at some point in the future. Anyway, I guess it's a good thing I never switched to UNET, it will be supported for another couple of years I believe, but there doesn't seem much point using it now. So the upshot is, I'm probably going to have to look for a third party solution.

    Whatever networking solution I end up using, one thing is for sure, I really need to abstract the networking API away from the rest of the GearBlocks code as much possible. This is something I should have done in the first place really, it'll make changing networking APIs much easier in the future.

    So to allow for pooled construction GameObjects, and as a first step towards this abstraction, I've now implemented my own world object ID system. This allows GameObjects to have a unique ID consistent across the server and all the clients, and is now used by construction and part GameObjects. This allowed me to remove the Unity NetworkView from the construction GameObject (which will make pooling them easier), and move all code for state synchronisation out of the construction and into a central manager that synchronises the state of all constructions together.

    The next step in this abstraction effort will be to wrap all the RPC calls (currently scattered throughout the code) behind another interface. As well as meaning there will then only be one place in the code to modify when I change networking APIs, it will also allow me to remove the NetworkView from part GameObjects too.

    Explosives go boom

    My future plans for GearBlocks mean that the damage system needs to apply damage not only from collision impacts, but also from explosives. So I had some fun adding a simple placeholder explosive that'll serve as a good test for now. Right now it only applies a force to nearby objects, it doesn't do any damage yet, that's something I'll have to work on soon!

     
    woodsynzl likes this.
  41. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Networking and optimisations

    Sorry for the lack of updates for the past couple of months, I was away visiting family and things for some of that time, but I have also made a lot of progress on the game. So let's dive in!

    Networking layer

    Most of my time lately has been spent on networking code. As I discussed in the previous post, the Unity networking API situation at the moment is unfortunate to put it mildly. To mitigate against this, I've now built a new networking abstraction layer. This wraps and hides away all direct access to the deprecated Unity RakNet based API that I'm currently using, and should facilitate easier migration to a different networking API in the future.

    This was a big task as it touched code throughout the game. There are four major aspects to the networking API that needed to be eliminated from the game code: Network static API, network messages, NetworkView, and NetworkPlayer. In more detail:-
    1. Network static API, e.g. Network.isServer, Network.SetSendingEnabled(), etc. These are now only used inside the networking layer (or where absolutely necessary, wrapped behind a new API for use in game code).
    2. Network messages, e.g. OnServerInitialized(), OnPlayerConnected(), etc. These are now only used inside the networking layer, and where necessary propagated out to the game code via events.
    3. NetworkView, used for remote procedure calls (RPCs) and state serialization:-
      • RPCs. The new layer now allows game code to register methods, then remotely call, and receive them. Internally this currently is still implemented using a NetworkView and RPCs.
      • State serialization via OnSerializeNetworkView() and BitStream. I've now implemented a system within the networking layer to synchronize state across the network. Internally this is still implemented using a NetworkView, OnSerializeNetworkView(), and BitStream, but none of this is exposed to the game code.
    4. NetworkPlayer, used to uniquely identify a connected player. Now the new networking layer assigns its own ID for each player, and keeps a reference to each player's NetworkPlayer for use internally only.
    After of all of these changes, the Unity networking API is no longer directly referenced anywhere in game code. The next step will be to actually change the networking layer's internal implementation from using the Unity API to something else. This will likely still be a painful task, but should be far more manageable now than it would have been before.

    Construction modification optimisations

    In the previous blog post I talked about the optimisations I'd done to the construction modification code (this code deals with attaching and detaching parts). The performance of this code is particularly important in the context of the damage system which can require a large number of parts to be detached at once.

    I have now implemented a GameObject pooling system, which eliminates the last major remaining performance cost, that being the instantiation and destruction of construction and Rigidbody GameObjects. In the example I showed in the last post (shown again below), the cost of breaking the attachments is now down to less than 10ms (prior to doing any optimisations, it was around 60ms!)



    There are still more optimisations I can do. For example, the instantiation and destruction of the attachments between parts are contributing some performance cost (and GC allocs). Plus, associated with the attachments are the physics ConfigurableJoints between Rigidbodies, which also have to be created and destroyed. Maybe I could pool these too, something to look at in the future for sure.

    But for right now I'm happy enough with the performance that I can get back to working on the damage system.

    Damage system

    On which subject, I'll be returning my focus to this next. I still need to decide how to propagate collision forces to cause plausible breakage of parts. Also, I'm leaning away from the idea of damage accumulation and attachment "health", towards more of a probabilistic method, but I'm not entirely sure yet.
     
  42. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Yet more optimisations

    OK, it seems I spoke too soon when I said in the last blog post that I was done with optimisations to the construction modification code! When working on the damage system, I found that detaching parts off large constructions with lots of parts could still be really slow, so over the last few weeks I've been working to resolve this.

    Setting transform parents

    When modifying a construction (i.e. attaching or detaching parts), I need to change transform parents in order to manipulate the construction's transform hierarchy, and by far the biggest performance cost I found was with this re-parenting. Even when setting worldPositionStays to false when calling SetParent() so that Unity doesn't have to recalculate world transforms, it's still really slow when you call SetParent() a lot, due to Unity internally updating the physics colliders. When modifying a large construction, in the profiler I was seeing Physics.HandleColliderHierarchyChanges and Physics.SyncColliderTransform costing many tens, sometimes hundreds of ms!

    So now I've done everything I can to get rid of unnecessary re-parenting, thereby minimising the number of SetParent() calls, specifically:-
    • When fixedly attaching parts together, all the parts have to be re-parented from their current rigidbodies to a single rigidbody. Now, parts from the rigidbody with the smaller number of parts always get re-parented to the rigidbody with the larger number (without re-parenting the larger number of parts).
    • Similarly, when deleting fixed attachments, parts need to be re-parented to separate rigidbodies. Now, after determining the groupings of parts left after attachment deletion, the largest group always stays under their original rigidbody, and the rest get re-parented to other new rigidbodies.
    • Lastly; I was parenting rigidbodies that were part of the same construction to a container gameobject, this was handy for clarity and debugging purposes, but not strictly necessary. I changed the code to maintain the rigidbody-to-parent-construction relationship a different way, rather than relying on the transform hierarchy for this. After that I was able to eliminate setting of the rigidbodies transform parents entirely.

    Other optimisations

    I was using List<T> to hold temporary lists of parts and rigidbodies when determining how to reorganise a construction hierarchy after deleting attachments. If there were a large number of things in these lists (e.g. parts), then calling Contains() or Remove() on them would be noticeably slow because these are O(n) operations (a linear search). So I switched over to using a HashSet<T> instead, for which these operations are O(1).

    After a construction is modified, its rigidbodies bounds and mass properties (e.g. centre of mass, inertia tensor, etc.) need to be recalculated. I've now optimised the code that does this, mostly by caching data that doesn't change (e.g. for parts that haven't been re-parented to a new rigidbody).

    Also after a construction is modified, a few GetComponentsInChildren() calls were being used to cache references to rigidbodies and parts. These calls were quite slow (and also caused some pretty sizable GC allocs), but after restructuring the code a bit, I was able to eliminate the need for them.

    Results

    All of these optimisations added together have made huge gains, at least in the test case I was using (a construction with over 2000 parts). It used to be that detaching a single part in this test could take well over 300ms(!) which caused a noticeable frame rate hitch, now it takes less than 37ms.

    Around 22ms of this remaining time is taken by updating rigidbody mass properties (assigning to mass, centerOfMass, inertiaTensor, and intertiaTensorRotation), which there’s not much I can do about. I can’t understand why this would be so slow, something odd seems to be happening under the hood in Unity. Maybe this issue is fixed in Unity 2018, but for now I’m stuck on 2017.4, due to the Networking API issues I’ve discussed in previous posts. Another 12ms out of the ~37ms total is taken by Unity in Physics.UpdateBodies, which I don’t think I can do anything about either unfortunately.
     
    Last edited: Nov 21, 2018
  43. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184


    Damage is done

    Well, it took me long enough, but finally the damage system is complete! Most of the time was actually spent doing optimisation work, which I've discussed before in previous posts, the damage system itself didn't take that long to do.

    On the idea scrapheap

    My original idea for damage was that each attachment between parts (fixed, rotary, linear, etc.) would have a "health" value. Then upon a collision contact with a part, some damage amount would be propagated out to all of that part's attachments. For each attachment, damage would effectively accumulate over time as its health value gradually reduced, until it reached zero at which point the attachment would be deleted.

    However, there were problems with this method:-
    • Deleting individual attachments due to damage would lead to inter-penetration issues, just like when you manually delete attachments with the builder tool.
    • Each attachment having a health value would need to be conveyed somehow to the player via a UI, and I couldn't think of a way which wouldn't be messy and confusing.
    • Because damage is applied for every collision contact (of which there can be many), the code is quite performance sensitive, and so needs to be as lightweight and simple as possible, which this method wasn't.
    Binary break

    So in the end I went with a simpler solution that just uses a "strength" threshold. When a part receives a collision contact, I simply compare the impact force with the part's strength value, and if the force is greater than this value, I break the part off (i.e. delete all of its attachments), otherwise I leave it attached. In other words, a part is either entirely broken off or it isn't, there's no intermediate damage state or health values to deal with.

    Happily, I found was that there was not really any need to explicitly propagate the damage force to neighbouring parts to achieve a convincing effect. Direct impacts seem to be enough, I think because as parts break off they hit other parts and the damage sort of propagates organically.

    I've also finished the implementation of explosives that integrates with the same damage system, in this case the damage force is simply derived from a linear fall off from the explosion centre. The resultant bits that are broken off then have an explosion force applied to them to push them around, seems to work pretty well.

    Lastly, I've also added a per-construction setting to enable / disable invulnerability (i.e. immunity from part breakage), as sometimes it could be useful to disable damage for those particularly "experimental" constructions that might try and smash themselves to bits.

    Still to do

    As I mentioned, each part has a strength value which basically determines how hard it is to break off. A part's strength value is intended to reflect the material it's made from (e.g. steel is stronger than wood or plastic), and I still need to fine tune these strength values to get the balance correct and hopefully give a nice trade off between the various materials.

    Also, I'm thinking I might bias each part's strength value slightly based on the number of attachments it has, so that the more other parts it's attached to, the harder it is to break off. Again, hopefully giving the player further interesting trade offs to choose between when building their constructions.
     
  44. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    New material tool, and a new year!

    Hey all, hope everyone has had a good holiday break. I thought I'd give a quick update on what I've been working on over the past few weeks.

    Toolbox code refactoring

    Up until now, the code for the various tools (builder, linker, painter, etc.) was pretty much all in one (very large) source file. This was driving me crazy as made it a real pain to to fix bugs, or add new features. So I finally took some time to do something I'd been wanting to do for ages, which was to refactor this monolithic beast into separate source files for each tool.

    There are still things I'd like to improve and clean up (further code decoupling, mainly), but it's much better than it was, and makes it easier to add new tools, on which subject...

    Material swapper tool

    After the refactoring, I started work on a new tool that allows you to swap the material on certain parts (such as beams and plates) after they've been spawned, and even after they're already part of a construction.

    The first step was to add a material definition that encapsulates all the various part material properties (i.e. the rendering & physics materials, density, strength, and "is it paintable"). Next I had to refactor the part descriptor code to allow parts to use this new material definition (seems like I've been doing a lot of code refactoring lately!)



    Then on to the material tool itself, which I'm still in the middle of building. Right now I have a first pass implementation working, with the basic UI done, and the ability to change material on the highlighted part. There's still more to do however; for example, save / load (including converting old save files to the new material swappable parts), and probably more refactoring as I'm not quite happy with how the part descriptor code is structured just yet.

    Anyway, it shouldn't take too much longer to finish up, once it's done I'll reveal more about how it works. After that I'll probably get back to finishing up the linker tool, as that's been on the back burner for way too long now.

    In the meantime, I'd like to say a big thank you for following my progress, particularly to those of you that have been following for a long time, and who continue to play the demo and give me feedback. I know development of the game is frustratingly slow, but I will get it done eventually, I hope!

    Happy New Year, and all the best for 2019.
     
  45. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    ScriptableObjects For Fun and Profit

    Well, it's been a while, so time for a progress update I think! The material tool is now done, and I'll show it in action very soon, so watch out for that. Most of my time however has been occupied with a massive code re-architecture effort, and that's what I'm going to go over in this update.

    From a high level perspective the GearBlocks game code is quite well laid out in terms of separating various subsystems (e.g audio, graphics, player, UI, etc.) via namespaces and so on. However, there was still a lot of code coupling (i.e. direct dependencies) between areas of the game code that should really be completely independent. This made it impossible to reuse or test parts of the code independently, and it was only going to get worse as development progressed.

    ScriptableObjects to the Rescue

    I'd been using ScriptableObjects in Unity for a long time, but only in a select few cases as data containers, I certainly hadn't been using them to their full potential.

    I watched these two excellent presentations a while back:-
    Ever since, I'd been wanting to adapt the ideas presented in these talks to the game to improve the code architecture, and so I finally decided to take the plunge. This was a huge endeavour, but well worth it I think.

    ScriptableObject Events

    Previously I was using Unity's ExecuteEvents system as the basis for events in the game. This was helpful for code decoupling, however it still had some disadvantages:-
    • In order to add a new event, a new interface has to be written (derived from IEventSystemHandler), and then implemented in all the MonoBehaviours that need to receive the event.
    • It's necessary to explicitly call ExecuteEvents.Execute() on every GameObject with MonoBehaviours that need to receive the event. To me, this makes ExecuteEvents more like messages than true events, but perhaps that's just semantics.
    • Only MonoBehaviours on GameObjects can receive these events, ScriptableObjects can not.
    So I replaced these with a new system, where each event is now a ScriptableObject asset. Here's a simplified version of the code:-
    Code (csharp):
    1. public class EventAsset : ScriptableObject
    2. {
    3.     public delegate void EventHandler();
    4.     public event EventHandler Handler = null;
    5.  
    6.     public void Raise()
    7.     {
    8.         if( Handler != null )
    9.         {
    10.             Handler();
    11.         }
    12.     }
    13. }
    The real implementation is slightly more complex, but follows the same principle. It's implemented using C# generics to allow for different event argument types, and has support for logging and listing the current event subscribers. This is used by a custom editor I wrote to display this info while the game is running in the Unity editor, here's an example of it in action:-



    To use an event it can simply be assigned to a variable in the Unity inspector, then to receive it, just subscribe to Handler:-
    Code (csharp):
    1. public class Receiver : MonoBehaviour
    2. {
    3.     [SerializeField] EventAsset somethingHappened;
    4.  
    5.     EventAsset.EventHandler onSomethingHappened;
    6.  
    7.     void OnEnable()
    8.     {
    9.         onSomethingHappened = () => { Debug.Log( "I hear that something happened!" ); };
    10.         somethingHappened.Handler += onSomethingHappened;
    11.     }
    12.  
    13.     void OnDisable()
    14.     {
    15.         somethingHappened.Handler -= onSomethingHappened;
    16.     }
    17. }
    Or to raise the event, just call Raise() on the event:-
    Code (csharp):
    1. public class Sender : MonoBehaviour
    2. {
    3.     [SerializeField] EventAsset somethingHappened;
    4.  
    5.     void SomethingHappened()
    6.     {
    7.         Debug.Log( "Something happened, telling everyone!" );
    8.         somethingHappened.Raise();
    9.     }
    10. }
    This setup has some useful advantages over the old ExecuteEvents system:-
    • No need to write any code to add a new event, just create a new event asset and assigned it in the inspector where needed.
    • No need to explicitly refer to specific GameObjects to send the event.
    • Don't even need to be using GameObjects, these events can be used by ScriptableObjects as well as MonoBehaviours.
    • The events are more easily debuggable via the custom editor.
    ScriptableObject Variables

    Events aren't always the most appropriate pattern for sharing data between subsystems, for example sometimes it's necessary to store a value somewhere and allow it to be read a later point, perhaps continuously polling it to watch as it changes.

    Previously I was doing this by having my subsystems be singletons, and then directly reading / writing properties in them where needed, thereby tightly coupling different areas of the code together, not good! To solve this I made a new "variable" system, where each variable is a ScriptableObject asset. Whereas events can be thought of as radio broadcasts, the variable system is conceptually more like a noticeboard (with each variable being a notice pinned to the board).

    Here's a simplified version of the code, it's implemented as a generic class to allow for different variable types:-
    Code (csharp):
    1. public abstract class VariableAssetBase<T> : ScriptableObject
    2. {
    3.     [SerializeField] T value;
    4.  
    5.     public T Value { set { this.value = value; } }
    6.  
    7.     public static implicit operator T( VariableAssetBase<T> variableAsset )
    8.     {
    9.         return variableAsset.value;
    10.     }
    11. }
    For example, a bool variable type:-
    Code (csharp):
    1. public class BoolVariableAsset : VariableAssetBase<bool>
    2. {
    3. }
    Again, the real code has a bit more going on. It has an event delegate that code can subscribe to, in order to be notified when the variable value is assigned to (this saves having to use a separate event for this). It also has support for serialisation so that I can use these variables for things like game settings (e.g. controls, gameplay, video) and allow the player to save / load them. Plus I made a custom editor that allows variable values to be viewed or even modified while the game is running in the Unity editor. At some point I might implement a debug console that would allow this to be done even in standalone builds, which would be super cool!

    To use a variable it can be assigned in the inspector, then written to / read from. Notice that Assigner and Watcher in this example are completely independent of one another:-
    Code (csharp):
    1. public class Assigner : MonoBehaviour
    2. {
    3.     [SerializeField] BoolVariableAsset isThingTrueVar;
    4.  
    5.     void ThingBecomesTrue()
    6.     {
    7.         isThingTrueVar.Value = true;
    8.     }
    9. }
    10.  
    11. public class Watcher : MonoBehaviour
    12. {
    13.     [SerializeField] BoolVariableAsset isThingTrueVar;
    14.  
    15.     void Update()
    16.     {
    17.         PollThingTruthiness();
    18.     }
    19.    
    20.     void PollThingTruthiness()
    21.     {
    22.         Debug.Log( "Thing is currently " + isThingTrueVar );
    23.     }
    24. }
    I replaced data in my subsystems that needed to be shared with these new ScriptableObject variables. This allowed me to remove a lot of code dependencies, and eliminate the need for singleton references in most cases.

    One example being the UI overlay that displays the player's speed, acceleration, and altitude. It now just reads variables for these values and displays them, completely independently of the player code that updates them.

    ScriptableObject Dictionaries

    There's one slight wrinkle with the ScriptableObject variable system, in that there is only one global instance of each variable. For example, sometimes I need one instance of a variable per player (in multi-player games). To solve this I implemented a simple ScriptableObject dictionary, here's the implementation pretty much in full:-
    Code (csharp):
    1. public abstract class DictionaryAssetBase<TKey, TValue> : ScriptableObject
    2. {
    3.     Dictionary<TKey, TValue> dictionary = null;
    4.  
    5.     void OnDisable()
    6.     {
    7.         if( dictionary != null )
    8.         {
    9.             dictionary.Clear();
    10.         }
    11.     }
    12.  
    13.     public TValue this[TKey key]
    14.     {
    15.         get
    16.         {
    17.             if( dictionary != null )
    18.             {
    19.                 TValue value;
    20.                 if( dictionary.TryGetValue( key, out value ) )
    21.                 {
    22.                     return value;
    23.                 }
    24.             }
    25.  
    26.             return default(TValue);
    27.         }
    28.  
    29.         set
    30.         {
    31.             if( dictionary == null )
    32.             {
    33.                 dictionary = new Dictionary<TKey, TValue>();
    34.             }
    35.  
    36.             dictionary[key] = value;
    37.         }
    38.     }
    39. }
    Then for example, a dictionary with byte keys and bool values:-
    Code (csharp):
    1. public class ByteBoolDictionaryAsset : DictionaryAssetBase<byte, bool>
    2. {
    3. }
    The only part I left out here is some code for listing the entries currently in the dictionary, used by another custom editor I added for debugging while the game is running in the Unity editor.

    A dictionary is used in much the same way as a ScriptableObject variable:-
    Code (csharp):
    1. public class Assigner : MonoBehaviour
    2. {
    3.     [SerializeField] byte thisPlayersID;
    4.     [SerializeField] ByteBoolDictionaryAsset isThingAboutPlayerTrueVar;
    5.  
    6.     void PlayerThingBecomesTrue()
    7.     {
    8.         isThingAboutPlayerTrueVar[thisPlayersID] = true;
    9.     }
    10. }
    11.  
    12. public class Watcher : MonoBehaviour
    13. {
    14.     [SerializeField] byte thisPlayersID;
    15.     [SerializeField] ByteBoolDictionaryAsset isThingAboutPlayerTrueVar;
    16.  
    17.     void Update()
    18.     {
    19.         PollPlayerThingTruthiness();
    20.     }
    21.  
    22.     void PollPlayerThingTruthiness()
    23.     {
    24.         Debug.Log( "Thing is currently " + isThingAboutPlayerTrueVar[thisPlayersID] + ", about player with ID: " + thisPlayersID );
    25.     }
    26. }
    Replacing Singletons

    The game has many self contained code modules providing utilities and functionality used by other parts of the code. Previously these were either static classes or singleton MonoBehaviours, both having their disadvantages:-
    • Static classes can't have variables serialized by Unity or edited in the inspector.
    • Singleton MonoBehaviours need to live on a GameObject somewhere in the scene (or at least in a prefab).
    So now I've re-implemented most of these as ScriptableObjects which have neither of these downsides. They work well with the new ScriptableObject events too, these modules being able subscribe to or raise events, which helps with code decoupling.

    Other Uses of ScriptableObjects

    I found many more places to use ScriptableObjects, far too many to go over in detail now, but here's a brief summary of a few of them:-
    • Added ScriptableObject "delegate objects", making use of the strategy pattern where different variations on a theme implement a common interface. For example I use this for the procedural generation code for the various different re-sizable parts in the game.
    • Replaced some enums with ScriptableObject assets.
    • Implemented ScriptableObject data assets with built in functionality for better separation of concerns. For example, I implemented a "sound asset" ScriptableObject that handles random AudioClip selection and playback, and then created a whole bunch of these assets for all the sounds in the game.
     
    Edy likes this.
  46. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Here's a quick demo of the new material tool, showing how the tool is used, and how the different materials affect both visuals and physics.

     
  47. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Better building for multi-player

    Most of my time over the past few weeks has been spent on a major reworking of the code for all of the tools in the game (builder, material, painter, etc.) in order to improve the building experience for networked client players in multi-player games.

    Previously the tool code that responded to player inputs in order to perform various actions (such as attaching a part, breaking an attachment, applying paint, and so on) would always run on the server for all players, with each client simply sending their inputs to the server for it to deal with. This setup made it relatively easy for the server to handle things like arbitration between players, seeing as they were effectively all running locally as far it was concerned.

    However this approach was flawed, the most significant problem being the latency between client player input and an action happening, which made building really awkward to say the least.

    So I've now re-implemented every tool so that player input is processed locally on each client. In some cases the client must still request the server to complete certain actions, so that the server can validate and arbitrate where needed (for example, while one player is attaching one part to a second one, at the same time another player could be deleting that second part; the server needs to have the final say on the outcome in this scenario). In many situations however, it is not necessary for the client to check with the server first (e.g. moving or resizing a selected part, painting a part, etc.), instead the client just informs the server of the change made so that it can be broadcast out to the rest of the clients.

    The result is that the building experience for networked clients is now basically the same as it is in single player games. The other benefit of these changes is that because input is processed locally for each player, it simplifies the code and makes it a bit easier to modify and improve the tools.

    Builder tool tweaks

    On which subject, I've made a couple of minor improvements to the builder tool thanks to some suggestions I've received.
    • Remove actions (delete part, destroy construction, etc.) are now delayed, during which time the action key has to be held down. This should hopefully prevent annoying accidental deletions from mis-clicks!
    • I changed the default key binding for duplication from "Q" to "Left Alt + LMB", by default "Q" is now dedicated just to opening the tool menu.
    The usability of the builder tool controls is still an ongoing concern, and something I'll have to keep plugging away at over time, but at least now it'll be easier to implement any further improvements I need to make.

    New demo coming soon

    Finally, I'm getting close to releasing another demo build, and I've been fixing a bunch of bugs in preparation for this. There have been a ton of changes to the code since the last demo, so I'm slightly paranoid that some as yet undiscovered bugs might have been introduced. Time to do some more testing I think, hopefully I don't encounter any last minute issues!
     
    Flurgle likes this.
  48. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    New demo build is up. A lot of code “under the hood” has changed since the last one, so I’m really hoping I haven’t broken anything!
     
    Last edited: Feb 27, 2020
  49. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Linker tool, power, and more

    Here's a quick update on what I've been working on over the last month or so!

    Linker tool

    After a long hiatus from working on it, I finally went back and completed the linker tool. The first attempt at this tool that I did a while back was hard-coded to work with the pulleys, so I had to generalise the implementation to support different link types. A part can now have one or more link nodes that are associated with its part behaviour(s). When the linker tool is active these link nodes can be highlighted by the player, which they can then click on and drag to another link node to create a link between them.

    These are the different link types that I've done, or am planning to do:-
    • Pulley - used to route belt between pulleys, implementation now complete.
    • Power - used to link motors, batteries, solar panels, this is also now done (see "Electric Power" below).
    • Data - allows one part behaviour to query data from another linked part behaviour, an example could be a screen that can be linked to a motor to display its current RPM.
    • Control - allows one part behaviour to control another part behaviour, an simple example being a switch that can be linked to several motors, lights, etc. to turn them on / off together.
    In this example you can see some pulley links and a power link being added between a motor and battery:-



    As there are now different link types, I've made a few tweaks to make it easier to manipulate them. The indicators for each link type are colour coded so that they can easily be distinguished from one another, and there is now a linker tool UI that allows links of different types to be shown or hidden.

    Electric power



    As I mentioned, I've now implemented "power" links so that motors, lights, and so on can be linked to batteries. I implemented code in the motor and light part behaviours to calculate a power value that is then used to discharge energy from the linked battery / batteries. Also, when braking, a motor will now regenerate energy back into its linked battery / batteries.

    The battery part behaviour itself does very little other than tracking the battery's current state of charge.

    I've also added solar panels, these have a simple part behaviour that calculates a power value based on the panel's surface area and its current angle relative to the sun. This is then used to charge energy into its linked battery / batteries.

    It's fun to play around with this stuff in conjunction with the day / night cycle in the game, using solar panels to charge a battery during the day which then powers your lights at night:-



    Knuckle joints

    I've also just added a new type of hinge connector, what I'm calling a "knuckle joint", where the parts connect in line with one another like this:-



    I made two versions of the knuckle joint connector, one that can rotate through 180 degrees and another that is limited to 90 degrees. Here's an example of using the 90 degree version, as well as the ball and socket connectors I added ages ago, to make a ragdoll in the game:-

     
  50. danger726

    danger726

    Joined:
    Aug 19, 2012
    Posts:
    184
    Text decals, data links, and electronics

    I've been wiped out with a nasty bug over the last couple of weeks which slowed productivity somewhat, still got quite a few things done though!

    Text decals

    I implemented a decal shader that can modify material properties in the g-buffer independently of normals. This allows for rendering over the top of objects already rendered in the scene, modifying albedo, smoothness, etc. while leaving the underlying normals as they are, which gives a "painted over" look. I wrote this shader specifically to work with rendering font text from the Unity UI.

    Then, I added a Canvas in World Space mode and a UI Text component to the resizable plate part, and implemented a new text label part behaviour to configure the text string to be shown.

    With a “painterly” font, it's quite a nice effect, here's an example of what it looks like:-



    And here's the part behaviour UI the player can use to configure the text string:-



    This will be handy for labelling things on constructions, and I’m thinking I might make use of it in future challenge game mode scenarios / tutorials.

    Data links

    I refactored the part behaviour linking code using various interfaces to better decouple the code and make it easier to add new link types. I also made some minor fixes and improvements to the linker tool.

    I then implemented a new data link type, which allows part behaviours to expose "data channels" that can be accessed by other linked part behaviours. Where appropriate, I added data channels to all the part behaviours already in the game, for example the electric motor now exposes its current RPM, torque, and power values.

    Electronics

    Now the dawn of a whole new category of parts, electronics! I hope to expand on this a lot more in the future but here’s what I’ve done so far.



    Putting the text decal shader and the data links together, along with a LCD display font, I implemented some text display screen parts that show the data channels of the part they’re linked to.

    Here you can see the new data link type being used as we link a display to a motor:-



    The display screen showing the motor’s data channel values while it runs:-



    These displays have a part behaviour that lets the player assign a data channel to each text line on the display. Here's the UI for this, it needs some improvement but is functional for now at least:-



    I also added some "sensor" parts which are little modules that calculate their own speed, acceleration, or attitude (i.e. orientation in the world) and report these values via data channels. These can then be linked to from the LCD displays to show their current values.



    The speed sensor in action, as well as speed it also reports its altitude and rate of climb (RoC):-



    The accelerometer sensor, reporting longitudinal, lateral, and vertical acceleration separately, as well as overall acceleration:-



    Finally, the attitude sensor, which reports heading, pitch, and roll in degrees:-



    I have loads of ideas for more sensor modules I could add in the future, e.g. for reporting angle, angular velocity, proximity (think radar / lidar) and so on. Let me know if you have any ideas too! Combining these with the control links I have planned will really open things up to some very cool possibilities I think.

    Anyway, for now I’ve just been enjoying messing around with these parts, like adding some sensors and LCD screens to the Mosquito flyer for flight instruments!