• Subcribe to Our RSS Feed
Tagged with " Unity3D"

Simple Scrolling Combat Text with Unity3D

Dec 10, 2011   //   by Josh   //   Games, Tutorials, Unity3D  //  1 Comment

I found an interesting discussion on Eric Heimburg’s G+ page about “floaty numbers” in Unity, and offered to share my solution to this problem as seen in HexDev, so here it is! Maybe someone will come looking for Scrolling Combat Text in Unity and this code will help!

So to get things started, here’s a quick screenshot of the implementation in HexDev:

Concept

The basic concept is to display numbers above a unit whenever they take damage.  The number should rise for a certain height at a given speed and then poof away!  Nice and simple right?

So, to do this using my approach, we need a couple things:

  1. A Prefab with a TextMesh component attached.
  2. A Unit object with a MonoBehaviour attached that calls: SendMessage(“DamageTaken”, x);   where x is the number to be displayed.
  3. The ScrollingCombatText behaviour below attached to the GameObject that you want to display SCT numbers.

So, Step 1) In my projects, I have created a prefab called SCTText which looks like this:

Nothing fancy, again just a GameObject that has a TextMesh object on it.  The beauty of it is that you can change this prefab to have a mesh or particles or whatever you want on it.  The number will be updated by the ScrollingCombatText script below.

For step 2, all of my units have a special behaviour attached to them that manages their health.  Whenever they take damage, they simply use the Unity SendMessage API to notify other MonoBehaviour’s attached to the game object that the unit has taken damage.  This will probably need to be tailored to your project.

And for step 3, I just attach the script below to my GameObject, give it the Prefab we defined in step 1, configure some parameters and whenever the unit takes damge, voila!  Scrolling combat text!  Here’s what the configuration of the script looks like on my units (each unit can have their own values or we can use the default values):

Code – ScrollingCombatText

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
 
public class ScrollingCombatText : MonoBehaviour
{
	// How fast will the spawned text object rise
    public float RiseRate = 4.0f;
	// How high should the spawned text object rise
    public float RiseHeight = 10.0f;
 
	// Prefab with an attached TextMesh component that will be spawned when damage is taken
    public GameObject TextPrefab = null;
 
    private List floatingTextObjects = new List();
 
	// This will be the starting height of the floating numbers
	private float initialHeight = 0.0f;
 
	// Use this for initialization
	void Start ()
    {
		// If this component is attached to a CharacterController, use the CharacterController's height attribute to set the initial height
		CharacterController charController = gameObject.GetComponent();
		if (charController != null)
			initialHeight = charController.height;
	}
 
	// Requires the GameObject to have a method call to: SendMessage("DamageTaken", int)
    void DamageTaken(int damageAmount)
    {
		// Create a new text object and set the starting height and text
        GameObject textInstance = (GameObject)Instantiate(TextPrefab);
        textInstance.transform.parent = gameObject.transform;
        textInstance.transform.localPosition = new Vector3(0, initialHeight, 0);
 
        TextMesh mesh = textInstance.GetComponent<TextMesh>();
        mesh.text = damageAmount.ToString();
 
		// Add to the list of floating text objects to update every frame
        floatingTextObjects.Add(textInstance);
    }
 
	// Update is called once per frame
    void Update()
    {
		// Cache all text meshes to be deleted and later delete them
        List objectsToDelete = new List();
 
        foreach (GameObject floatingTextObject in floatingTextObjects)
        {
			float riseDelta = Time.deltaTime * RiseRate;
            Vector3 newPosition = new Vector3(floatingTextObject.transform.localPosition.x, floatingTextObject.transform.localPosition.y + riseDelta, floatingTextObject.transform.localPosition.z);
            floatingTextObject.transform.localPosition = newPosition;
            floatingTextObject.transform.LookAt(floatingTextObject.transform.position + Camera.mainCamera.transform.forward);
 
			// Delete this floating text object if it exceeds our RiseHeight property
            if (floatingTextObject.transform.localPosition.y &gt;= initialHeight + RiseHeight)
            {
                objectsToDelete.Add(floatingTextObject);
            }
        }
 
        foreach (GameObject objectToDelete in objectsToDelete)
        {
            floatingTextObjects.Remove(objectToDelete);
            Destroy(objectToDelete);
        }
    }
}

Hex HowTo 1

Mar 22, 2011   //   by Josh   //   Games  //  No Comments

I had a few technical questions regarding the tiles used by this approach, so I figured I would at least share my approach. It’s probably not optimal, but it works so far.

Q: So how do we create a Hexagonal Tile?

I use Blender to do all of my 3D modelling, so naturally I used Blender to generate a simple hexagon.  So here are some quick steps to create a unit hexagon like the one seen here using Blender.

  1. Create a new empty scene in Blender.
  2. Set your camera to look down the z Axis (from the top) using NumPad+7.
  3. Add a Cylinder mesh with 6 vertices, with a depth of 0.2 (or however “thick” you want your tiles to be)
  4. By default, Blender generates it 15 degrees off center, so rotate the hexagon by -15 degrees around the z Axis to align the edges.
  5. Using this approach, Blender generates the hexagon with a Circumradius of 1.0, which is perfect.  If you want a different value here, scale the entire model by whatever modifier you want, and that value becomes your new HexSideLength in the previous code sample.
  6. Now, to get this hexagon into unity, select only the hexagon object and choose: File -> Export -> Autodesk FBX (.fbx) and use the following settings:
  7. Save the fbx file somewhere in your Assets folder in your Unity project.
  8. Now, when you go back to Unity, you should see your model in the Project window.  Simply drag and drop it into your scene to see it rendered in Unity!  Or, you can set this object as your HexTilePrefab on the HexGrid script from my Hexagon of Hexagons post, and you can tile them in a rectangular grid.

Q: Is each Tile a prefab?

In my case, yes.  Once I have successfully imported the model to unity, I create 1 prefab for each unique tile type that I want to use.

  1. In Unity, create a blank game object (Ctrl + Shift+ N) in the Hierarchy window.
  2. Drag the Hexagon FBX object onto the empty GameObject.
  3. In the Project view, create a new Prefab and call it whatever you want.  (Tile_Blank for example)
  4. Drag the blank GameObject you created in step 1 with the child hexagon onto the Prefab in the Project window.
  5. Now you can drag that prefab into your scene, or set it as another script’s GameObject for tiling.

The other major benefit to doing this, is that you can add unique behavior to each prefab.  If every forest tile acts the same, create a ForestTileBehaviour and attach it to your prefab.  In this way, you can create  a whole collection of unique tile prefabs, each with their own unique behavior.

Q: How can I select a hexagonal tile using this approach?

Generally speaking, when selecting something, I use a Raycast from the current camera to see if the ray has collided with any Colliders.  So I simply attach a Mesh Collider to the Cylinder object, and now the Cylinder GameObject will register a raycast collision when the user clicks on this object using the mentioned script.  What you do with it when you click on it is up to you!

Note: Be sure you attach the Mesh Collider to the object that has the Mesh Filter component, or you’ll have to manually assign the Mesh in the Mesh Collider, which causes other problems with rotations.

That’s all for this post.  If there are any more specific questions, I can try to answer them with another post.  Maybe I’ll actually work on the project again soon too. ;)

Hexagon of Hexagons

Feb 13, 2011   //   by Josh   //   Games, Uncategorized  //  5 Comments

I’ve been thinking of a slightly new direction for HexDev, which led me to thinking it would be appropriate to generate a hexagonal canvas instead of a rectangular one for creating HexWorlds.  I also decided to document the process of where it is today and how to get there for fun and for others to learn from.

So first a little background.  Let’s start with generating a rectangular grid of hexagons as HexDev already does.  To do this, we need a little bit of math (or you can ignore the math and use magic numbers).  I chose to orient the hexagons with their left and right side being vertically aligned, points facing up and down.  If you choose to orient them a different way, the math may look a little different.

From http://mathworld.wolfram.com/Hexagon.html, we learn the following properties which are very useful for this kind of grid generation:

Given a regular hexagon with side length a:

The inradius: r = 0.5 * sqrt(3) * a
The circumradius: R = a.

The inradius r is important because it tells us how much horizontal distance we need to shift between each tile and how much horizontal space we need to shift every other row.
The circumradius R is useful because we can calculate how much vertical distance we need to shift for every row.  Fortunately for us, R = a, so that keeps the math easy. :)

The horizontal and vertical space between the center of each tile is then calculated by the following formulas:
horizontalSpace = 2.0 * inradius
verticalSpace = 1.5 * R = 1.5 * a

So, given these fomula, here’s the code to tile a Prefab in a rectangular grid in Unity3D:

public class HexGrid : MonoBehaviour
{
    public int Width = 10;
    public int Height = 10;
 
    public float HexSideLength = 1.0f;
    public GameObject HexTilePrefab = null;
 
    public void GenerateGrid()
    {
        float inradius = (float)(0.5 * Mathf.Sqrt(3) * HexSideLength);
	float spaceBetweenTilesHorizontal = 2.0f * inradius;
	float spaceBetweenTilesVertical = 1.5f * HexSideLength;
 
	if (HexTilePrefab != null)
        {
            for (int x = 0; x < Width; x++)
            {
                for (int y = 0; y < Height; y++)
                {
                    GameObject tile = (GameObject)Instantiate(HexTilePrefab, Vector3.zero, Quaternion.identity);
                    tile.transform.parent = gameObject.transform;
                    tile.transform.localPosition = new Vector3(x * spaceBetweenTilesHorizontal + (y & 1) * inradius, 0, y * spaceBetweenTilesVertical);
	        }
	    }
        }
 
        // Center the Grid
        gameObject.transform.Translate(new Vector3(-spaceBetweenTilesHorizontal * Width / 2.0f + inradius, 0, -spaceBetweenTilesVertical * Height / 2.0f - HexSideLength));
    }
}

Using this code will produce a visually “tight” grid of hexagons, if HexSideLength equals the visual length of the hexagon.  If you want some space in between your hexagons, you can set HexSideLength to a value > the actual side length of the hexagon, producing an even space around each hexagon.

Here we show HexSideLength = 1 and HexSideLength = 1.05 for a hexagon whose actual side length = 1.

So with a little background out of the way, we can now attempt to generate hexagonal grids.  Using HexDev’s Free Tile Builder, I generated the hexagonal grids that I want to automatically generate.  I started with 1×1 and worked up to 5×5 to determine the pattern and here’s what we end up with:

So what we have here are forests that represent the tiles that I actually want to generate and water to represent the empty spaces in the rectangular grid space.  My planned input is a single value a that represents the number of tiles per side.

To figure out how we are going to generate this grid, some observable stats are useful.  If we can find general equations for these values in terms of a, we’ve got enough information to render the grid, so let’s do that.

Here are some stats for every grid:

a rows midRowColumns midRowNumber
1 1 1 1
2 3 3 2
3 5 5 3
4 7 7 4
5 9 9 5

Let’s break down a = 5 to some even further stats:

row leadingSpaces tileCount abs(distanceFromMid)
1 2 5 4
2 2 6 3
3 1 7 2
4 1 8 1
5 0 9 0
6 1 8 1
7 1 7 2
8 2 6 3
9 2 5 4

So here are some equations that we can derive from these tables:

rowCount = 2a – 1
distanceFromMid[row] = abs(a – row)
tileCount[row] = rowCount – distanceFromMid[row]

The hardest one to derive I think is the leadingSpaces variable, because it changes depending on even/odd a values, but I’ve found this to be true:
For even values of a:  leadingSpaces[row] = Floor(distanceFromMid[row] / 2 )
For odd values of a: leadingSpaces[row] = Floor((distanceFromMid[row] + 1) / 2)

At the moment, I’m not going to share my code for this, because it’s getting late and it needs to be cleaned up… but if there is enough interest, I don’t have any qualms against posting it.  For now, I leave you with a screenshot of HexDev using a hexagonal canvas.  HexDev’s Free Tile Builder mode has been updated to also generate Hexagonal boards in 4, 5, and 8 length sizes.  Enjoy!

Tile Walker

Dec 5, 2010   //   by Josh   //   Games  //  No Comments

Small update, because I feel like updating [not because what I'm updating is worth an update].

I posted an updated to Hex Dev with a prototype of the “runtime” or “game” mode after you design a tile set.  Basically, every hexagon enlarges and the system procedurally fills it with “stuff”.  So far, only the forest gets procedurally generated trees.  In addition to stuff, you get a capsule to move around with the Right Click mouse button.  The capsule slides forever in the direction you tell it to go, so have fun and play around with all the quirky bugs.  :)

Painting Forests

Dec 2, 2010   //   by Josh   //   Games  //  No Comments

Small update… added forest tiles.  You can always check back to see the latest version on the “Hex Dev” page above.

TODO next:  Prototype the gameplay mode.

A Forest of Tiles!

Painting with Hex Tiles

Dec 1, 2010   //   by Josh   //   Games  //  No Comments

Now that my DNS host is back up, I can post this before bed.

In this demo, you can paint the hex tiles with the mouse.  After clicking generate to build a grid, use the keyboard shortcuts to change the “tile brush”.

Keyboard Shortcuts
1 – Empty Tile
2 – Grass
3 – Water

http://blog.redclovergames.com/projects/tiles/tilestest2.html

http://blog.redclovergames.com/projects/tiles/tilestest2.html

Inspired?

Nov 23, 2010   //   by Josh   //   Uncategorized  //  No Comments

Maybe.  Here’s a hex grid rendered in Unity3D.  WADS/Arrow Keys + Mouse Wheel to scroll.

Edit: I made a hex grid in Unity, yippee.  Now I just have to figure out how to embed it properly.  More to follow…