Tango Trails - Project Blog

So I managed to get hold of a Project Tango developer device and wanted to see how easy it was to develop for it. I use Unity for my main development and was really pleased to see it was fully supported.

I came up with a simple game idea to start myself off. Create random positions in a room, move from one point to the next and after you get there a trail is made. You now must go to the next target without touching the virtual track you just made. Simple but should make for a fun two player game.

First thing I noticed is that for Area Learning to be used it requests a permission. Nice and secure but it may put some people off so I decided to just do a simple room plotting system myself and just use the depth information.

In its simplest form Tango will spit out a long list of positions in space where it found a surface and so I decided to just use this data for my first game to keep things simple.

The first task is to define a play area for the player to walk around and for me to set the targets. This is by far the most complicated part of the whole game. Luckily the Tango API provides a concept of a floor that it will find itself and so this made things easier.

So, to keep things speedy, I run through a subset of the list of points it returns as it can be 9000. I sample 1000 from the set with a changing offset so I eventually hit all points over time. The image below shows in the background my first visualisation of the data. I quantize the floor into squares of 17.5cm and count up the heights in each square. If they don't vary too much and are close to the floor value from the Tango system I mark it in green and denote it as floor.

I also keep track of where you walk and if you are over a floor square it marks its a lighter green to show it is a floor area that is walkable (more on that later).

Getting a reasonable result from this scanning was quite tricky as you can get random bad data that can throw out results. Or this can be from a square that is half floor and half wall and so the average is above the floor. I measured a max-min variance on each pool of points and if it gets too large then it resets it and stops it becoming a floor tile. For a floor to be established it needs around 20 points that are within a tolerance of the found floor.

The above shot is the first successful plotting of the route taken. Its a bit rough looking but proved the mesh generation system. If you haven't done dynamic mesh generation before I use this as a base for the routine: http://wiki.unity3d.com/index.php/ProceduralPrimitives It gives full examples of creating meshes in code. As a warning, if you want collision data to be generated then it will take some time so don't expect this to happen in a frame for a large mesh. Luckily my design means the paths are quite small the generation only happens when you've got to the target. I don't make it as you travel ro else you may go into it as you walk. I did think of making a visualisation of the path as you walked but you never look behind yourself and so was not needed.

As I walk I note the position and orientation of the path, logging points after you move a minimum distance from the last one. If you move backwards too it will delete points behind too so you can't draw too much on top of itself. For the angle of each segment of the path I first tried the orientation of the device when it logged the point but this can be less useful if they move laterally, but in this game it is fairly unlikely as you normally want to see where you are going. In the end I used the angle made from the previous and next points with 25% of the orientation taken from the points (with a Slerp to generate this value). I did think about adding more smoothing after the event so it looks visually nicer but as its just a play around game I left this. Something for an improvement if I return to it.

One of the best things I found when I started writing this is that running it inside Unity shows a test lounge scene that you can use to scan without having to go onto the device. Brilliant, and I later found that you can even supply your own model to customise it. Very cool. Of course you will have to test a lot on device too as the testbed returns perfect values and so can't test for the randomness of the real results.

So once I've got a plot of the floor I now need to tidy up the space and find the final play area. It can be easy to scan an area that you cannot get to and have odd floor points lying around. To reduce this problem I spread out the squares marked as "walked-floor" outwards to their neighbours so any play area must come from a floor tile that was walked on. This removed a lot of the poor scanned edges and when I combined it with a coroutine I could make it visually spread out before the player. I did try making the floor out of chocolate squares but it just didn't look as nice as the simple spots that I settled on in the end. A benefit of this approach is also that the play areas can be separated so long as you did walk in each area.

I now need to find a set of points to use as the go-between positions. I try to find 4 points but it will still succeed if it can find 2 sufficiently separated. The scan may fail if the space is not large enough but I try to get them to scan for a minimum time and walk around a bit before I let them proceed. 

I realised that I need to keep these targets away from walls and unwalkable areas and so I do a further pass on the squares looking for all the ones with a border of 2 squares. This reduces the amount of possible target points down further which can also cause scan fails. The sizes I picked here are so that it would still work through a standard door - basically the space in my house where I was testing!

To set up the points I did a quite dirty random pick and test algorithm which just adds a successive point randomly and keeps it if its not too close to others created. If it fails 20 times it starts it all again and will abort out if this process fails 200 times. Yes, I could have done some intelligent system to search for edges and work in from there but that would have taken ages and would also probably generate very samey patterns from the same room. I like my solution and so am sticking with it!!! ;)

In case you're wondering about the bubblgum blobs, they are the markers for the target points. I needed a way to ensure you could never draw into these areas or else a target may become impossible to get to so these areas become no fly zones when not a target.

I tackled the issues of knowing where your target is in a couple of ways. The first and simplest was to have a radial particle effect emanating from it. Simple and naturally gives you an idea of where it is. I augmented this with a more traditional arrow that will point the way to go. The game goes through a phase of going to the start point and then going to the target. The "go to target" time is also useful as you can just wander around and look at the state of play.

Collision detection on the world wasn't as simple as you may think as I need to have a gauge on how far you are from the impact point. In the end I used a Physics.CheckSphere call on the fixed update to test a radius around the player. This radius starts at a maximum value until it hits something and then will shrink a step. This way it will drop down to either a size small enough to not hit or go too small and trigger an impact after a few frames. It's a game so the implicit delay here is also a bit of niceness to be generous to the player if they clip something just slightly. Now you might think that this will result in the collision radius bouncing up and down a lot and you'd be right, but not if you do it twice every frame! This solution meant that at the threshold point it will either expand and then shrink back immediately or the reverse. Not perfect but solved it sufficiently. I then combined it with a lerp on the displayed indicator and you have a soft collision closeness detector. I applied the lerped 0..1 value to the position of an animation of a ring scaling in and fading in and I had my simple collision gauge.

So the rest of the work was adding in the two player mode and the assets which I did myself - yes it's programmer art but ok for this quick game! Found some free assets on the Unity Asset Store for some sprite particles and I even created my first bump map to make the candy canes a bit nicer.

All told from start to finish was around 3 weeks and that involved doing everything there. Not bad for a from scratch game as I had to learn the Tango system as I went too.

Thanks go to Mark at Austella VR for the loan of the Tango device.

No comments:

Post a Comment