Hello again in 2015.
I sort of a had a week off over Christmas to go and visit family, plus catch up with things around the house. But I have also had a week of work since the last update.
I made a mock-up of a scoreboard for Scraps games. One that you can show by pressing a key while in-game, and also see after a game ends or you quit (click for full-size).
I just need to write some code to populate it with actual values instead of fake placeholders. In-game it's semi-transparent so you can also see what's going on while you're viewing it (like you're getting shot).
I also did some multiplayer work (like players can cleanly
quit the game now!), but I also seem to have been burdened with an unusual number of difficult to track down bugs this week. I think it's easy to look at a game and say "well it'd probably take about two weeks to do that feature and a month to do that...", but (and I'm guilty of this as much as anyone else) there are so many little things that can't be easily predicted. Weird and hard-to-track-down bugs are certainly a part of that. Some people choose to take an estimate and just double it.
You also sometimes hear comments like "programming is really hard - you can get just one letter wrong and the computer won't understand it!" I wish my bugs were that simple!!!
Highlights of annoying bugs I fixed in the dev version this week:#1Problem: Sometimes, rarely, when a vehicle should have been destroyed it would only lose its chassis and the rest would survive, which should never happen and would throw a whole string of errors.
Analysis: In the Unity engine you can
destroy an object, and any child objects connected to it will also be destroyed. The actual destruction happens at the end of the current frame.
I found this bug quite hard to track down. I discovered that if you destroy an object and then destroy one of its children in the same frame,
occasionally only the child will get destroyed. When a key part on a vehicle got destroyed, I was destroying the whole vehicle, but still destroying the part that got blown up as well, which was triggering the bug.
Solution: Made sure that if I destroyed the whole vehicle, I
didn't destroy the part.
#2Problem: I was checking if an object had been deleted, but the code was happily going straight past that check and trying to use it even if it was gone, throwing null reference errors.
Analysis: This is a technical one, but Unity
overrides the null operator, basically because when they delete some things they don't actually delete them, but they want to make it look like they did. I knew about this but I missed a special case.
I had a Unity class (a MonoBehaviour) that I was referencing
as an Interface. Because I wasn't looking at it as a MonoBehaviour,
== null wasn't overridden, causing it to say it was NOT null when it had been deleted.
Solution: Changed the
== null check to
.Equals (null). If you cast a MonoBehaviour to an interface and you delete it,
== null will return false but
.Equals(null) will return true!
#3Problem: I was getting frequent errors claiming that "
curSource->m_Channel != NULL" in the Unity console. Weird to get an error that something
isn't null for a change. This was coming from deep within the Unity engine and came with no indication of what was causing it and in fact no other text at all.
Analysis: An Internet search turned up that it was related to audio, but was officially "fixed" long ago. I tracked it down to being caused by assigning an audio clip and playing it when weapons fired, but I couldn't work around it (without not playing the sound at all), and I couldn't reproduce it in a separate test app when trying to replicate the conditions. Eventually I discovered that it was caused by calling that audio code from an
InvokeRepeating method. What.
Solution: Changed the InvokeRepeating to a
Coroutine that did exactly the same thing and ran exactly the same code. No more errors. I've reported this one to Unity but unfortunately I still can't reproduce it in a simple test app, so there must be more involved somehow.
#4Problem: Sometimes the AI wasn't firing the large cannon on all computers in networked games. It might fire on one PC but not always fire on another.
Analysis: The way the Scraps AI works right now, it tends to fire for one frame, the very first frame that a weapon is ready to fire again. This happened to be just the right scenario to show up an issue that human players don't usually trigger.
Scraps only sends player inputs over the network to control vehicles. It doesn't send "weapons 5, 7 and 9 fired", it just sends "player pressed fire" or "player released fire" and the vehicle is expected to do the same thing on all machines because it's an exact duplicate.
I'd quite like to avoid syncing things like "weapon fired" because:
1. It paves the way for hacks of fire rates etc. Like a player says they fired their gun 100 times at once.
2. There can be lots of weapons on vehicles and there's only one on or off "firing" state, so it's a lot less data to send over the network.
3. It's just simpler to send only the inputs!
But this was the problem: Imagine the AI presses Fire at time 0. Anther PC receives that message at time 100 due to latency. Then the AI releases Fire and they send that message too. The weapon fires on both machines (with a slight delay on the second one).
Say the weapon has a min time of 500 between shots. Now the AI presses fire again right when the weapon is next ready to fire, at time 500. The message is sent - but what if latency has reduced in the meantime to 95 instead of 100, so the message is received at time 595? 595 - 100 = 495 and the weapon isn't quite ready to fire yet!
If the AI kept holding Fire it'd be no problem, but right away in the next frame it releases Fire again, the message comes through as well, and the weapon never fires on the second machine.
Solution: Fixed for now by imposing a short minimum time for holding Fire before releasing it. This doesn't prevent all possible issues, for instance think of releasing Fire just before a weapon is about to fire again. I have a couple of better fixes for the future in mind, though in practice, any other issues like this are actually very rare.
By the way, I updated the Builder Demo slightly the other day. Weapons were taking on the heat they produced when firing for one frame before the cooling system would attempt to take it away. Mostly it wasn't a big issue but it meant that some weapons - particularly the Large Cannon - could end up taking heat damage even though the cooling system was well below max capacity. The
download is now version 0.3.1.1.