Skip navigation

Category Archives: Unity 3D

The train setup menu now displays a preview of the engine you are purchasing.  It also allows you to edit already purchased trains.

screenshot2

Train with smoke stack moving South.

screenshot1

Train with smoke stack moving North.

screenshot2

Just a quick update.  A train’s boxcars now fade in as they pull out of the station.

Before:

traincarsnofadein

After:

traincarsfadein

Today’s task was to create boxcars that follow the engine and each other in turn. Once again I had to catch myself from making the problem too difficult.  I set up a test scene that I could quickly iterate on (instead of having to place track and stations and buy a train every time I wanted to test).  That was smart.  This was dumb:  I started out by trying to make the boxcars behave like real physical objects that have a forward and backward attachment point and tried to “figure out” where they were on the track based on the boxcar (or engine) they are attached to.

After floundering with that for a while I had a thought: I have the engine working correctly, why not just have each boxcar behave like the engine but delay it the correct amount of time before sending it down the track after the engine.  A little bit of programming later I had a much simpler solution and it looks great.

traincars

Please excuse the height miss-match.  I will fix that later as I polish the train code.  I think I might have each boxcar fade in as it pulls out of the station…

When I first sat down to implement train path finding on placed tracks I had an overly complicated model in my head of how tracks connected and how one might sniff out a path on the track.  It involved allowing “turning around” at a station that was not the train’s destination – how do you indicate that it’s “OK” to be traveling the same path but now the other direction… Then, in the spirit of MVP and my original “simplify it if you can and the game is still fun” mentality I realized that trains don’t need to be able to turn around at stations.  The rules I put in place for track layout guarantee that a train can get from any hex to any other hex without backtracking on hexes it has already visited.  With that understanding there are no circumstances where turning around at a station nets a shorter path or opens up solutions that wouldn’t have otherwise existed.  It was just me wanting to solve the hardest, juiciest problem.

After throwing out the idea of non-destination station turnarounds the entire problem got way easier.  A simple “bucket fill” path solving algorithm nets all possible solutions and then I just ask for the one that costs the least.  Cost is a combination of distance and type of terrain the solution has to pass though.

Here we see a train following a solved-for path from Charlotte to Donald’s Tree Farm.  Sorry about the gif artifacts, those are not there in the real rendering.

engine

 

Next steps:

  • Box cars
  • Supply/Demand netting from train deliveries
  • Player Goals

Working down the list of MVP requirements I have done a lot of work.

Resources are now labeled on the map. I had to do this so I could show the label in the train’s stop list, so why not add it to the map while I had the information on hand.

Stations can now be placed.  When in station placement mode, hexes that are available for station placement are highlighted in blue.

screenshot1

A station has been placed in “Tulsa” and confirmation is about to take place:

screenshot2

 

A few more stations are placed and the player can now buy a train.  The player selects the type of engine and the different stations a train will visit:

screenshot3

After selecting “Add Stop” (need a better name for “stop”. “Way point”?) the map is available and all hexes with stations on them are highlighted in blue, indicating they are available for selection.  Hexes with a stop already placed on them for this train are highlighted in yellow as a reminder to the player that the train is setup up to stop there already, but these stations can be selected again if the player wants a train to visit any particular station more than once in it’s loop:

screenshot4

The stations are listed in order that the train will visit them.  Ordering and deleting of rows is available:

screenshot5

I have spent the last two and a half weeks working diligently on my MVP for project Cat Phone.  The plan I described in my first MVP post has been paying off.  I have worked on the project casually and have focused on my MVP one item at a time.

I purchased a hex framework a long time ago when I first got interested in re-booting this project and have been sitting on it ever since.   This gave me a very easy way to implement item number 1 on the MPV list: a hex map.  From there, I have added random resource nodes around the map, and most importantly, added path finding and track layout.   I have put into place rules like: Only one branch or resource node per hex tile.  The hex map and these rules allow me to simplify track path finding and layout quite a lot.

If you look closely at the bottom left of these screen captures, you can see the track layout working with branching.  In these pictures, new track to be placed is rendered in a purple color and track that has been placed is rendered in a yellow-brown.  Resources are spheres rendered in a color depicting their type (green for timber, off-white for color, etc.)

Next on the list to tackle is station placement, then train path finding.

screenshot2 screenshot3 screenshot4 screenshot5 screenshot6

I have been working more on project Cat Phone recently.  I have added a lot of new mechanisms to the project.  The most recent being the supply and demand engine.  None of the numbers are correct (the rates that things produce goods, and the rate they demand them, etc.), but the engine is now fully in place.

Cities may have industries added to them (The extra-large white models in the cities you may see).  When an industry is added it creates a supply and demand sub-node on the city.  A city can have any number of supply and demand nodes.  They are all added up and the total of each type of good is displayed for the player to recognize in the HUD along with a numerical indicator for how much that type of good is being supplied or demanded.  I am using random license-free textures I found on the internet to do those indications  so they don’t look so good.  But when the projects moves towards production and becomes an official game, I will have an artist replace everything with good looking textures and models.

Supply Demand

Supply and Demand HUD

The Tanks Online HD beta process has started and I am using some new tools to get the job done better.  Without having to release Tanks Online HD to the app store, I can get up to 100 devices to install my beta app via the Ad hoc distribution method.  The problem is, how does one manage all the communication, sign ups, user recruitment, user management, and beta app distribution of the beta process?   Test Flight is the answer to that.  Test Flight allows you to manage all of that and even offers an SDK to collect testing information as the users test your app.

Sign up:

If you are interested in beta testing Tanks Online HD, please sign up to my Test Flight team: http://tflig.ht/Qn0nfr

So Unity 3D is super easy to use and you can make really cool stuff rapidly.  The first “professional” release I am trying to do involves Unity’s networking layer because Tanks Online is a multi-player game.  For me, this is where Unity starts to stumble – or at least is not very developer friendly.  I got Tanks Online running a few weeks ago in a very alpha form with networking enabled – meaning multiple players could connect and shoot at each other.  That was the easy part.  I have spent about 25 hours since then ironing out the plethora of networking bugs.  Here is two of my “favorites” – meaning it took about 10 of those 25 hours to figure out and fix.

Who’s your daddy?

Hosts (players) can use Network.Instantiate(…) to create objects in the scene (world).  When Network.Instantiate(…) is used, all the hosts regardless of type (server or client, remote or local) create that object.  This works like a charm and in very little time I had tanks running around and shooting at each other.  Now, I needed to do a little bit of collision detection for when a projectile hits a tank.  It’s important to know who “owns” the tank and who “owns” the bullet so you can tally the correct stats on death and not register a “hit” when a tank is colliding with a projectile it created.  Unity offers this through the network information (NetworkView) of a object that was instantiated with Network.Instantiate(…).  I was doing this check on the collision of a projectile with a tank and getting good results on the server but not the client hosts.  It turns out that the server is the only host who really does know who the “owner” of each object is, but the other hosts all think that the server is the owner of the Network Instantiated object (tank).  I think this is because the server is the one to brodcast RPC calls (of which Network.Instantiate(…) is a special case) to all the other hosts, even when the RPC is called on a client host.

The solution was to add an OnNetworkInstantiate “callback” on the tank object that sends a RPC only to the server that asks for the NetworkPlayer who owns the newly created tank.  The server sends a RPC back that has the “owning” NetworkPlayer.  The tank object stores that away in a member variable.  Now when a projectile and a tank collide, each host can correctly check the owner.

This seems like quite a bit of overhead that could have been avoided if Unity would have correctly assigned the owner of the NetworkView on each host.  Hopefully they will correct that some day and this convoluted way to get the correct owner of a network object can go away.

Give up the ghosts

Network.Instantiate(…) is a buffered call, meaning new hosts will get these objects even if they are created before that new host joins the network game.  Cool!  When a tank dies in Tanks Online, the tank’s Game Object that represents that player is removed from the game using Network.Destroy.  Everything looks great when you are fooling around with a few players – everyone spawns correctly and when they die all the hosts see the player’s tank disappear.  However, Network.Destroy is apparently not a buffered call because if a player died and a new host shows up, that new host will create an instance of a tank (where it originally spawned) that was destroyed on the network before the new host showed up to the party.  And because no one is using that tank any more, it just sits there, un-moving and absorbing any project’s sent it’s way.  An indestructible ghost of a player’s past.

I looked online and the proscribed solution was to call Network.RemoveRPCs on the NetworkView associated with the tank that was about to be destroyed.  But that didn’t work – apparently more than a few people have run into this problem and there is no solution yet.  Luckily for me, the only buffered RPC’s I am using are creating a new tank when a player spawns – so they don’t need to there forever, I can clear all the RPC’s from that player when the tank dies.  Network.RemoveRPCs allows you to pass in a NetworkPlayer and it blasts away all the buffered calls on the network from that player.  So that’s what I did.    If I had a more complicated game this bug would have gotten in my way, but because spawning a tank is the only buffered call that is made, I lucked out and can brute force hack my my out of this one.