Wednesday, December 3, 2014

Unity: MiniMap

This post shows an example of a simple implementation for minimap in Unity game. The complete source of the project can be downloaded from:

https://dl.dropboxusercontent.com/u/113201788/Unity3D/Camera.Minimap.zip

Firstly, we want to make sure that the player character's 3D model will not be rendered in the minimap, therefore we need to exclude the layer to which the player character belong to. The easiest way is to create a new layer and set the player character to be on that layer. Let's name that layer "No Map" layer)

Next, create a camera in the "Hierarchy" view by selecting "Create->Camera". Name the camera "MiniMap Camera", and set the following properties in its "Inspector" view:

1. Clear Flags: Depth Only
2. Culling Mask: Mixed (by excluding "No Map" layer in selected layers so that the player character 3D model will not be rendered in the minimap)
3. Projection: Orthographic
4. Depth: 1

Next, create a C# script named "MiniMapGenerator.cs" and attached it to the "MiniMap Camera" game object in the "Hierarchy" view. Update its content as follows:

using UnityEngine;
using System.Collections;

public class MiniMapGenerator : MonoBehaviour {

 public float camHeight=10.0f;
 public float camDistance=10.0f;

 public GameObject target; 

 public Texture2D marker;

 public bool freezeRotation=true;

 // Use this for initialization
 void Start () {
  Vector3 angles = transform.eulerAngles;
  angles.x = 90;
  angles.y = target.transform.transform.eulerAngles.y;
  transform.eulerAngles = angles;
  Draw ();
 }
 
 // Update is called once per frame
 void Update () {
  transform.position = new Vector3 (target.transform.position.x, 
                                 target.transform.position.y + camHeight,
                                 target.transform.position.z);

  camera.orthographicSize = camDistance;

  if(freezeRotation)
  {
   Vector3 angles=transform.eulerAngles;
   angles.y=target.transform.transform.eulerAngles.y;
   transform.eulerAngles=angles;
  }


  Draw ();
 }

 void Draw()
 {
  float minimap_width=Screen.width * 0.3f;
  float minimap_height=Screen.height * 0.3f;
  float xOffset = 10.0f;
  float yOffset = 10.0f;
  
  float minimap_left = Screen.width - minimap_width - xOffset;
  float minimap_bottom = Screen.height -  minimap_height - yOffset;
  
  camera.pixelRect = new Rect (minimap_left, minimap_bottom, minimap_width, minimap_height);
 }

 void OnGUI()
 {
  if(marker != null)
  {
   Vector3 markerPos = camera.WorldToViewportPoint(target.transform.position);
   float x = (camera.pixelRect.xMin+camera.pixelRect.xMax) * markerPos.x;
   float y = Screen.height - (camera.pixelRect.yMin + camera.pixelRect.yMax) * markerPos.y;
   GUI.DrawTexture(new Rect(x-marker.width * 0.5f, y-marker.height * 0.5f, marker.width, marker.height), marker, ScaleMode.StretchToFill);
  }
 }
}

The code sets the position and orientation of the "MiniMap Camera" to follow the "target" game object (we will set the "target" game object to the player character later) in the Update() method. The Draw() method determines the location and size of the minimap frame on the game screen.

Since we already exclude the player character 3D model from showing up in the minimap camera (i.e., the culling mask settings earlier), we need to add a marker to the minimap frame to indicate the location of the player character in the minimap. The OnGUI() use the DrawTexture on the marker texture to display a marker representing the player character.

Once the code for the "MiniMapGenerator.cs" is completed and attached to the "MiniMap Camera", we need to assign "target" and "marker" to it. With the "MiniMap Camera" selected in the "Hierarchy" view, drag the player character from "Hierarchy" view to the "target" attribute of the "MiniMapGenerator.cs" in the "Inspector" view. Do the same by dragging a texture for the marker to the "marker" attribute of the component. That is it.

No comments:

Post a Comment