Gábor's Site
  • Home
  • Contact
  • Nibbles
    • Nibble Work-in-Progress 22/05/14
    • Nibble Work-in-Progress 24/05/14
    • Nibbles Work-in-Progress 18/06/14 - Camera Moves
  • Blog

Nibbles Under the Hood - Edge Guide

8/10/2014

1 Comment

 
Word Cup is over, Scala course on Coursera course finished, time to get to work and extend Nibbles!
One of my good friend told me that it was difficult to navigate around on a map of Nibbles, because he didn't know the layout. Naturally I knew it already, so I didn't notice it. (That was when I realized I must use outside testers a lot! Thanks, David!)
I came up with two features to handle this problem:
  • Adding a zoom function, so you can see more ahead
  • Adding 'edge guides' to dynamic elements (collectibles) to the scene
I also fine-tuned the camera options a little bit, now it follows the snake more tightly, but I think both of the above mentioned features will be necessary. I've finished with the 'Edge Guide' feature, so let's see how it was done!
First, let me lay out my idea:
The whole concept was coming from FreeSpace – The Great War, and Skyrim. Let's take a look at FreeSpace first:

FreeSpace
Can you see the green and white thingies on the top of the screen? They follow around the edge any important out-of-sight object (targeted ship, incoming missiles), marking their direction (you have to face your ship that way to center the object), distance (the number), and also your angle to the target (the wider the guide, the more you have to turn to face the target). Pretty handy.
Next, let's see a screenshot from Skyrim:
Picture
Can you see the markers on the top? No, you can't. Let me zoom in for you:
Picture
This is a navigation bar. It marks the direction of important locations for you, and works as a compass. (You can see the 'N' for North). The locations are marked with their own symbol, but my favorite thing was that the closer you were to a location, the bigger and less transparent the symbols were! (You can compare the the turkoise and the leftmost grey arrow-thingy.)
Getting ideas from both concepts, I came up with the following design:
  • I need a component so an edge guide appears for the given game object
  • The edge guide appears on the edge of the screen, but on the inside, so it is visible by the player
  • The edge guide is positioned on the line connecting the object and the center of the main camera (to give the exact direction)
  • The edge guide is invisible if the object itself is visible
  • The edge has two components: and arrow like part, that is always poiniting to the target, and it is closer to the edge; and a symbol part, which is a visual guide of the nature of the object (typically the picture of the object itself)
  • The symbol part does not rotate, it is always right-side-up
  • The arrow part rotates, and always pointing to the object
  • the symbol part is always behind the arrow part, closer to the center of the screen
  • the further away the object is, the smaller and more transparent the edge guide is (both arrow and symbol), but only if it's possible to implement (SPOILER ALERT: it is)
Something like this:
Picture
Let's see how can we implement this.
First, let's notice, that the whole edge guide is rotating around the tip of the arrow. The symbol part however isn't rotated relative to the screen.
This gives us a structure, where the edge guide consists of two objects (an arrow and a symbol), where the symbol is the child of the arrow in the hierarchy.
So let's say the center of rotation is the red dot, and we rotate the edge guide:
Picture
Almost good, but the symbol is not okay, it needs to be rotated to the opposite way:
Picture
Perfect. Now let's fire up the Unity editor, (and Visual Studio / VS Express if you prefer), and implement it.
Let's create a new C# script, called 'EdgeGuide'. We will attach the script to our objects of interests.
The first thing we need to do is test the object if it's visible form the main camera, or not. It would seem straightforward to use MonoBehaviour.OnBecameVisible() and MonoBehaviour.OnBecameInvisible(), but it wouldn't work. The reason for that - according to this tutorial - is that these methods will take every camera into account, including the scene editor camera. So your results will be different in the editor, and in the built game.
We have to develop our own solution, which will be a shamless steal from the previously mentioned tutorial.
So every frame we test if the object is visible, hide the the edge guide if it does, or show if it doesn't. Here is our Update(...) method (called every frame):
  void Update () {
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(mainCamera);
if (!GeometryUtility.TestPlanesAABB(planes, thisRenderer.bounds)) {
//... show edge guide
} else {
//... hide edge guide
}
}
We will use 'planes' variable later, so we save it for later. These planes are the boundaries of the visible area of the camera. Everything inside is visible, outside is not.
Let's see what happens when we want to show the edge guide.
We need to find the edge point The edge point is where the edge huide should be centered. For this, we create a 'Ray' that origins from the camera position, and points to the object itself. Then we test all the planes for this ray, and save the smallest distance:
  void Update () {
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(mainCamera);
if (!GeometryUtility.TestPlanesAABB(planes, thisRenderer.bounds)) {
Vector3 rayOrigin = mainCamera.transform.position;
rayOrigin.z = transform.position.z;
Ray ray = new Ray(rayOrigin, transform.position - rayOrigin);
float smallestDistance = findEdgePoint(planes, ref ray);
} else {
// ... hide edge guide
}
}

private static float findEdgePoint(Plane[] borderingPlanes, ref Ray rayToTarget) {
float smallestDistance = -1.0f;
foreach (Plane plane in borderingPlanes) {
float rayDistance;
if (plane.Raycast(rayToTarget, out rayDistance)) {
if (smallestDistance < 0.0f || rayDistance < smallestDistance)
smallestDistance = rayDistance;
}
}
return smallestDistance;
}
Negative value is returned if none of the planess intersects the ray, but in our case this is impossible. We take the safe route in our code anyway.
Setting the scale of the edge guide is trivial, but setting the opacity is not. I needed some research in this matter, but in the end it turned out to be really easy. Here is the code:
  private void setOpacity(Renderer renderer, float value) {
Color color = renderer.material.color;
color.a = value;
renderer.material.color = color;
}
These are the interesting parts of the edge guide. Oh, one more thing, I've set the center of my arrow sprite to the tip of the arrow in Unity's sprite editor, so it automatically rotates around the right way:
Picture
I've uploaded the whole EdgeGuide.cs here, for anyone interested. Study or use it for whatever you like!
Happy coding!
1 Comment
Alarm System Texas link
12/1/2022 05:05:45 pm

Thanks great posst

Reply



Leave a Reply.

    Gábor's blog

    Some technical and personal stuff

    Archives

    January 2018
    August 2014
    June 2014
    May 2014

    Categories

    All
    Cocos2d
    Nibbles
    Personal
    Programming
    Unity

    RSS Feed

Powered by Create your own unique website with customizable templates.