Unity 2D Curves using Triangles

Hi Xander here….

I know I shouldn’t be spending time doing this sort of stuff when I got games to make but I got really sidetracked with this little brain boiler. I got the idea while doing some maths research and came across an image of a cat’s cradle spun in a triangle. The way the lines joined made a perfect curve and I really liked the idea of doing something like that for making custom curves in games. I know the idea is probably not original and there has got to be some better implementations out there but once my noodle started working on this I got a little obsessed with seeing it through to the end.

I have written before about making curved movement by using sin functions and still think that’s a pretty cool way to do it. You can read about it here: (Fly Birdy Fly! 2D Curved Movement in Unity). But this is a much more intuitive way to get the perfect curve you want and very easy to plot and track the path of movement without having to guess.

This is how it works…

You take the three points of a triangle. I was thinking of something like a cannon shot, or lobbed object, or a flying arrow to start with so I called them Source, Height and Target. You measure the distance between those points and make lines to form a triangle. Then you cut those lines into equal points and start joining one point on one line to another point on the other line all the way down the length. It’s easier to explain in an image:

Building a Triangle and “Cat’s Cradle” lines to make a curve!

Now for the Mathy part… Once you get those lines drawn you use algebra to find the intersection point of one line and the next to get your curved path! Every additional line crosses the one before and by finding that point where they cross you get a list of points that make a curve.

Simple curves only need a few lines.

Five Lines

The more lines you use the smoother your line is…

Ten Lines
Twenty Lines

Start moving around those points of the triangle and it becomes really easy in the Unity Editor to Map and draw custom curves. This kind of blew my mind.

Different Types of Curves

Here we have a number of different curves all just by making a few tweaks to the position of those three points of the triangle. I’ve used the intersecting points to draw a parabolic line on the game scene below.

Here are few of the same images zoomed in (in case you are reading on your phone).

The Code

I’ll put the full script at the bottom of the post but for now I’ll work through the code a little bit.

If you want to copy the script you need to attach it to a GameObject that you want to move (or if you want to draw lines you need to attach it to a GameObject with a Line Renderer).

The script has a number of check boxes exposed in the editor which lets you control the movement and drawing functions as well as resetting and applying changes after moving the triangle’s points.

The only other variable that you can play with is the timeToHit float. This number controls how many lines you want to use to create the curve. Remember: The more lines the smoother the movement but the higher processing. (That said I’ve yet to do any serious profiling of the script but haven’t found any real performance hits yet).

Much of everything else is public so you can see what’s going on inside all the Lists and Arrays.

… … … (Editor View)

Defining the Triangle

First of all we get the positions of the three triangle points and find the length (Magnitude) of the lines between them using normal Vector maths.

Then we divide those lines by the number of strings we want to have (timeToHit) and work out the relative size of each one:

        Vector3 X_line = source - target;  
        X_line_length = Vector3.Magnitude(X_line);
        Vector3 Y_line = height - source;
        Y_line_length = Vector3.Magnitude(Y_line);
        Vector3 Y_Negline = target - height;
        Y_Negline_length = Vector3.Magnitude(Y_Negline);

        X_line_bit_x = (height.x - source.x ) / timeToHit;
        X_line_bit_y = (height.y - source.y) / timeToHit;
        Negline_bit_x = (target.x - height.x) / timeToHit;
        Negline_bit_y = (height.y - target.y) / timeToHit;

Get the Points Along Each Line

Next we iterate through all the points on the lines and make a pair of Lists (one for the forward or positively sloping line and one for the negatively sloped line):

        for (int i = 0; i < timeToHit + 1; i++)
        {
            P_lines.Add(new Vector3(Px, Py, 0f));
            Px += X_line_bit_x;
            Py += X_line_bit_y;

            Q_lines.Add(new Vector3(Qx, Qy, 0f));
            Qx += Negline_bit_x;
            Qy -= Negline_bit_y;
        }

Get Intersection Points

Getting the intersection points was much easier to do in 2D but is totally achievable if you wanted to extend it to 3D. We pass in our start and end points on each line (x and y coordinates) and return the intersection point (and convert it back to a Vector3):

            myPoint = findIntersectionPoints(
                (new Vector2(P_lines[i].x, P_lines[i].y)), 
                (new Vector2(Q_lines[i].x, Q_lines[i].y)),
                (new Vector2(P_lines[bc].x, P_lines[bc].y)), 
                (new Vector2 (Q_lines[bc].x, Q_lines[bc].y)));
            Vector3 myPoint_3 = new Vector3(myPoint.x, myPoint.y, 0f);
            IntersectionPoints.Add(myPoint_3);

(If you want to do more than idly read about this stuff have a look at Math Open Ref for more information on the functions for finding the intersection of two lines. I promise it’s actually really interesting.)

The maths bit:

float P1 =(Line2Point2.x - Line2Point1.x) * (Line1Point2.y - Line1Point1.y)
        - (Line2Point2.y - Line2Point1.y) * (Line1Point2.x - Line1Point1.x);

float P2 = ((Line1Point1.x - Line2Point1.x) * (Line1Point2.y -Line1Point1.y)
 - (Line1Point1.y - Line2Point1.y) * (Line1Point2.x - Line1Point1.x)) / P1;

return new Vector2(
            Line2Point1.x + (Line2Point2.x - Line2Point1.x) * P2,
            Line2Point1.y + (Line2Point2.y - Line2Point1.y) * P2);

That’s about it for the tricky stuff. There is a function to draw a line along the curved path and a function to move the attached object along the path as well. Add in a few Gui functions for displaying the pretty stuff in the scene view and you are done.

Moving the Green Sphere

This is an example of the script running in the editor that shows the scene view with the OnGui helper lines and then switches to the game view where I use the function to draw a curve and then move the green sphere along that path.

Full Script:

Here is the full script…enjoy!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class CurveFunction : MonoBehaviour {
public bool resetMe;    // Use these to manage the screen display
public bool updateMe;
public bool drawMe;
public bool moveMe;
public GameObject Source;  // The three points of the triangle
public GameObject Target;
public GameObject Height;
public Vector3 source;  // The three points of the triangle
public Vector3 target;
public Vector3 height;
public float timeToHit;     // A variable use to split the lines of the triangle into equal parts
public int targetreached = 0;
public float X_line_length;     // The length of the horizontal line between source and target
public float Y_line_length;     // length from source to height
public float Y_Negline_length;  // length from height to target (Negative slope of the triangle)
public float X_line_bit_x;      // the x and (below) y points of the X_Line.  
public float X_line_bit_y;
public float Negline_bit_x;     // the x and (below) y points of the Negline.
public float Negline_bit_y;
public float[] X_line_bit_xs;
public float[] X_line_bit_ys;
public float[] Negline_bit_ys;
public List<Vector3> P_lines = new List<Vector3>();     // A List of points on the Y_Line 
public List<Vector3> Q_lines = new List<Vector3>();     // Same for the Negline
public List<Vector3> IntersectionPoints = new List<Vector3>();  // Where two lines cross
public float Px;        // Used as shorthand for points on the lines when calculating
public float Py;
public float Qx;
public float Qy;
public bool isFound;
public float speed;         // Used for Draw function
public LineRenderer lineRend;
public int bc;
// Use this for initialization
void Start () {
source = Source.transform.position;
height = Height.transform.position;
target = Target.transform.position;
getPointsOnTriangle();
Px = source.x;
Py = source.y;
Qx = height.x;
Qy = height.y;
makeLineArrays();
}
// Update is called once per frame
void Update () {
if (updateMe)
{
getPointsOnTriangle();
makeLineArrays();
updateMe = false;
}
if (moveMe)
{
MoveMe();
}
if (drawMe)
{
drawLines();
}
if (resetMe)
{
ResetMe();    
}
}
void getPointsOnTriangle ()
{
source = Source.transform.position;
height = Height.transform.position;
target = Target.transform.position;
// Define the lines of the triangle and get their lengths
Vector3 X_line = source - target; 
X_line_length = Vector3.Magnitude(X_line);
Vector3 Y_line = height - source;
Y_line_length = Vector3.Magnitude(Y_line);
Vector3 Y_Negline = target - height;
Y_Negline_length = Vector3.Magnitude(Y_Negline);
// Time to hit is not really a time but an increment of how many times we want to cut the line into 
// chunks to make the lines from. The more lines the better the curve points but more processing.
X_line_bit_x = (height.x - source.x ) / timeToHit;
X_line_bit_y = (height.y - source.y) / timeToHit;
Negline_bit_x = (target.x - height.x) / timeToHit;
Negline_bit_y = (height.y - target.y) / timeToHit;
// Handy handlers of the x and y values of the source and height.
Px = source.x;
Py = source.y;
Qx = height.x;
Qy = height.y;
}
void makeLineArrays()
{
for (int i = 0; i < timeToHit + 1; i++)
{
P_lines.Add(new Vector3(Px, Py, 0f));
Px += X_line_bit_x;
Py += X_line_bit_y;
Q_lines.Add(new Vector3(Qx, Qy, 0f));
Qx += Negline_bit_x;
Qy -= Negline_bit_y;
}
makeIntersectionPoints();
}
public void makeIntersectionPoints()
{
bc = 0;
Vector2 myPoint = Vector2.zero;   // It's a bit easier to do 2D. So convert.
for (int i = 0; i < timeToHit; i++)
{
if (bc < timeToHit)
{
bc++;
}
myPoint = findIntersectionPoints(
(new Vector2(P_lines[i].x, P_lines[i].y)), 
(new Vector2(Q_lines[i].x, Q_lines[i].y)),
(new Vector2(P_lines[bc].x, P_lines[bc].y)), 
(new Vector2 (Q_lines[bc].x, Q_lines[bc].y)));
Vector3 myPoint_3 = new Vector3(myPoint.x, myPoint.y, 0f);
IntersectionPoints.Add(myPoint_3);
}
IntersectionPoints.Add(target);
}
public Vector2 findIntersectionPoints(Vector2 Line1Point1, Vector2 Line1Point2, Vector2 Line2Point1, Vector2 Line2Point2)
{
float P1 = (Line2Point2.x - Line2Point1.x) * (Line1Point2.y - Line1Point1.y)
- (Line2Point2.y - Line2Point1.y) * (Line1Point2.x - Line1Point1.x);
float P2 = ((Line1Point1.x - Line2Point1.x) * (Line1Point2.y - Line1Point1.y)
- (Line1Point1.y - Line2Point1.y) * (Line1Point2.x - Line1Point1.x)) / P1;
return new Vector2(
Line2Point1.x + (Line2Point2.x - Line2Point1.x) * P2,
Line2Point1.y + (Line2Point2.y - Line2Point1.y) * P2
);
/// Code modified from: https://blog.dakwamine.fr/?p=1943  
/// (Thanks for the leg up!)
}
public void drawLines()
{
lineRend.positionCount = 0;
Vector3[] positions = new Vector3[Mathf.RoundToInt(timeToHit) + 1];
for (int i = 0; i < timeToHit + 1; i++)
{
positions[i] = IntersectionPoints[i];  // Draws the path
}
lineRend.positionCount = positions.Length;
lineRend.SetPositions(positions);
drawMe = false;
}
public void MoveMe()
{
if (transform.position != IntersectionPoints[targetreached])
{
float step = speed * Time.deltaTime;
transform.position = Vector3.MoveTowards(transform.position, IntersectionPoints[targetreached], step);
}
else
{
if (targetreached != IntersectionPoints.Count)
{
targetreached++;
}
}
if (transform.position == Target.transform.position)
{
moveMe = false;
}
}
public void ResetMe()
{
transform.position = source;
targetreached = 0;
X_line_length = 0;
Y_line_length = 0;
Y_Negline_length = 0;
X_line_bit_x = 0;
X_line_bit_y = 0;
Negline_bit_x = 0;
Negline_bit_y = 0;
X_line_bit_xs.Initialize();
X_line_bit_ys.Initialize();
Negline_bit_ys.Initialize();
P_lines.Clear();
Q_lines.Clear();
IntersectionPoints.Clear();
Px = 0;
Py = 0;
Qx = 0;
Qy = 0;
moveMe = false;
resetMe = false;
}
void OnGUI()
{
GUI.Label(new Rect(10, 10, 140, 20), "Source: " + source);
GUI.Label(new Rect(10, 30, 140, 20), "Target: " + target);
GUI.Label(new Rect(10, 50, 140, 20), "Height: " + height);
}
void OnDrawGizmos()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(source, 0.2f);
Gizmos.DrawWireSphere(target, 0.2f);
Gizmos.DrawWireSphere(height, 0.2f);
Gizmos.color = Color.green;
Gizmos.DrawLine(source, target);
Gizmos.DrawLine(source, height);
Gizmos.DrawLine(height, target);
UnityEditor.Handles.Label(source, "SOURCE");
UnityEditor.Handles.Label(target, "TARGET");
UnityEditor.Handles.Label(height, "HEIGHT");
Gizmos.color = Color.yellow;
// Uncomment to see lines in editor
for (int i = 0; i < timeToHit + 1; i++)
{
Gizmos.DrawLine(P_lines[i], Q_lines[i]);
}
}
}

Xander out.

The Coin Flip

Ah the coin flip! Simple easy and fun. The mechanism is a platformer mainstay. You run over a spinning coin (it glitters, it calls you) it pops into the air, and it’s yours!

The Endless Elevator Coin Flip !

This is how we do it…

There is a Rigidbody and Collider on both the coin and the player character. You can clearly see the spinning frame of the coin collider in the .gif above.

The collider acts as a trigger which is being listened for by our script which executes the “pop”.

The coin has a spinning script (and also a magnetic feature as a bonus for later).

The player has a couple of behaviours that handles the trigger and action.

The coin scripts – note the use of the slider to get the spinning speed just right.

Here we have the coin’s Rigidbody and Collider settings:

The Rigidbody isKinematic and the Collider is a Trigger

This is the script we use for spinning:

public class spinCoin : MonoBehaviour {
[Range(0.0F, 500.0F)]
public float speed;
// Update is called once per frame
void Update () {
transform.Rotate(Vector3.up * speed * Time.deltaTime);
}
}

Simple and sweet.

This is the function that that handles the collision and the pop into the air! (It’s part of our character behaviours).

    void OnTriggerEnter(Collider otherObj)
{
if (otherObj.name == "Coin(Clone)")
{
coins++;
var coin_txt = coins.ToString();
coinsText.text = "Coins: " + coin_txt;
Rigidbody riji = otherObj.GetComponentInParent<Rigidbody>();
riji.useGravity = true;
riji.isKinematic = false;
riji.AddForce(Vector3.up * 40f,  ForceMode.Impulse);
Destroy(otherObj.gameObject, 0.4f);
}
}

First of all we are incrementing our coin total variables and screen display.

The mesh for the coin is part of a child component so we need to call the Rigidbody attached to the parent object.

We set gravity to true so that it falls back down after adding the force and set isKinematic to false so we can use it’s mass to fall.

After a very short flight we destroy it (0.4 seconds).

As an added bonus here is the other coin behaviour for when a magnet power up is used in the game.

    private void OnTriggerEnter(Collider col)
{
colName = col.gameObject.name;
float step = speed * Time.deltaTime; // calculate distance to move
if (colName == "chr_spy2Paintedv2")
{
transform.position = Vector3.MoveTowards(transform.position, col.gameObject.transform.position, step);
}
}

This is when we make the collider really big on the coin. If the player gets in range of the collider then the coin moves like a magnet towards him. Which is kinda fun when there is lots of coins around and you feel like a millionaire just by standing around.

MagicaVoxel-Blender-Unity Workflow

Hi Trixie here….

We had a good break from the build cycle with the Text Adventure framework and since then have been making lots of fun headway on the main game in development Endless Elevator.

Endless Elevator is, as the name suggests, an endless runner style of game. It’s played in the vertical axis and follows the Good Cop as he scales the heights of an endless building shooting down the bad guys, climbing stairs, and catching elevators.

We have the main game functionality finished to a point so we started working on background objects and some cute little buddies for the Good Cop. It’s puppies…ain’t they cute!

This is not about the puppies though. This is about the workflow we have been using for creating assets using MagicaVoxel and making them game engine ready using Blender before importing them into Unity.

Lets start with MagicaVoxel. A 3D voxel editor that is free (no commercial license required) 8 bit and super awesome. Credits to the software are appreciated (e.g. “created by MagicaVoxel”) – like what I did there just like that! All the assets for the Endless Elevator have been made with MagicaVoxel. The walls, the floors, the furniture, and the characters.

First we model and then we paint in MagicaVoxel. For example this table lamp:

When we are done modelling and painting we export it as an .obj file that also produces a .png of the palette mesh mapping. It’s a bit like using the UV Unwrap in Blender but much harder to manually map or see.

Once we are done with MagicaVoxel if we want to optimise we import the .obj file into Blender. Blender is a terrific open source 3D modelling (and more) software. There is a trade-off here… we use Blender to lower the poly count on complex objects by using the decimate modifier. This modifier basically takes a parameter in your vertexes (like the angle between edges) and reduces the vertex count by simplifying the model. You see the problem with MagicaVoxel is that it created edges from a fixed point which can make lots of thin triangles.

Have a look at this model of the lamp imported into Blender:

You can see all the sharp angles of the triangles there. This is how MagicaVoxel works under the hood and it’s great for the internal workings of that program and is very efficient when working in that app but it sucks a bit for making complex models that you want to import into a game engine.

This is the Decimate modifier in Blender that we use to simplify this topology. We tell the modifier to take the Planar (faces) and simplify anything that has an angle under 25 degree.

We are left with something like this: (below)

This is much simpler and super easy for the game engine to understand and render.

The trade off here is that when you decimate all the vertices you lose your UV mapping for the paint work you might have done with MagicaVoxel. These are the limitations of working with awesome freeware. Sure they are awesome but if you shell out a few hundred (or less in some cases) for different Voxel modelling software you can get away with not having to work around these problems. But welcome to the world of no-budget game making. Hacking through the workarounds is part of the fun. Plus you actually learn a bit while you are working it out.

So in our game Endless Elevator we use a lot of small models (ie. not complex) and import them straight from MagicaVoxel and use their paint system and resulting exported image files for making the materials (albedo component). If we have more complex models that we want to simplify, like the walls and lifts in the surrounding building, then we import into Blender and do some optimising. Once the complex models have been optimised then we unmask them and paint the UV’s using GIMP. Next when they are imported into Unity we either add a material with the coloured UV mask we painted up or use Unity’s in built colour system for large areas.

There is another problem with using MagicaVoxel to make your game assets and that is on more complex models the “normal” of a face are often flipped the wrong way round. This one is kind of easy to spot and not that much fun to re-mediate. If you have a look at our character below you can see his shadow being projected on to the wall behind him.

Oops – he’s got big holes in him. You cannot see it on the model and it’s really only a problem if you are looking for it and using lots of hard lighting. In a 3D model each mesh forms a face and that face has two sides. In Unity’s default Shader only one face (the forward one) is rendered. So when MagicVoxel flips a few faces here and there (they are very small usually) you get these gaps that do not block the light in a shadow. It’s pretty hard to show in an image but what we have below is the model imported into Blender where we can expose the normals (the direction the face is facing!) and see the issue. In this image we have clipped the camera hard so that we can see into the cavity inside the model. Normals show up as light blue lines. You can see a few of them poking the wrong way into the center of the model instead of the outside. You can play around with the “flip normals” feature in Blender to fix these issues but it’s a lot of fiddling that frankly I have not had the patience or need to do yet!

So these are just a few of the issues and workarounds we use with this workflow – I hope you enjoy reading about it and if you have any questions feel free to comment 🙂

Trixie out.

Unity Hinge Joint

Hi Xander here…

For our game Endless Elevator, which is in development, we have a bad guy who is a knife thrower. I know nasty. In keeping with the blocky style of the characters in the game only his throwing arm moves and the rest of him is rigid. We decided to use the Unity inbuilt Hinge Joint and “spring” feature to simulate the throwing action. It turned out to be really easy to implement but hard to control perfectly. This is the story of how it all hangs together.

This guy below with the creepy eyes and beard is our knife throwing guy. You can see the top level empty Game Object called KnifeSpy_Package and two child objects (one for his body mesh the other for his arm which is separate). You can just make out the orange arrow of the Hinge Joint near his shoulder but more of that below.

This is his arm object. He’s holding a knife now… but soon we are going to teach him how to throw it (kinda).

You can see the Hinge Joint attached to the arm object here as a red arc around the Z axis. The arc of the Hinge Joint has been limited to just the angle that he needs to raise the arm and bring it back down in a throwing action.

Here is what the Hinge Joint looks like in the Editor. That Connected Body is the main figure of the character. The arm mesh that this script is attached to also has a Rigidbody component and must be set to “Use Gravity” for the Spring to work.

You can see where we set the limits for the arm axis in the bottom of the object there. We access the Use Motor boolean from our script to turn that feature on and off. When it’s on a spring winds up the arm to it’s firing position and when he throws that spring is released shooting his arm back down in a throwing arc.

This is what our script looks like in the editor:

The Target Angle is the height of the arm as it raises to throw. When the Player is in range and we are facing him if the arm has been raised above the target angle we can throw the knife. We can use this to tweak the throw. You can see in the example below our arm doesn’t really come up high enough so we can use this setting to fix what it looks like on the fly.

The ‘X’ is exposed in the editor to help with that process so that we can understand what’s going on with that setting without having to click around in the editor to see it against the arm transform.

The Knife Prefab is the knife mesh and the Knife Transform is an empty game object used to define the spot where we instantiate the Knife Prefab.

The Knife is instantiated with some Force and there are booleans to control if we can shoot and if the wait between shoots has completed.

This is what the script looks like as code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class KnifeHinge : MonoBehaviour {
private HingeJoint hingeKnife;
public Vector3 targetAngle;
public float x;    // Debug in Editor
public GameObject knifePrefab;
public GameObject knifeTransform;
public float force;
public bool canShoot;
public bool waitDone;
private Transform playerTransform;
public Transform parentTransform;
// Use this for initialization
void Start () {
hingeKnife = GetComponent<HingeJoint>();
playerTransform = GameObject.FindWithTag("Player").transform;
}
// Update is called once per frame
void Update () {
if (Mathf.Abs(playerTransform.transform.position.y - (parentTransform.transform.position.y)) < 1)  // If the player is on the same level as you
{
if (Mathf.Abs(playerTransform.transform.position.x - parentTransform.transform.position.x) < 8)  // If he is within 16 units from you
{
var lookPos = playerTransform.position;
var rotation = Quaternion.LookRotation(lookPos);
parentTransform.transform.LookAt(lookPos);
if (waitDone)
{
canShoot = true; // Can shoot is only true if you are looking at the Player (on the same level and 16 units away)
}
}
}
}
void FixedUpdate()
{
x = hingeKnife.transform.rotation.eulerAngles.x;   // this is for debugging the angle of the arm and hinge in the editor easily
if (canShoot)
{
if (hingeKnife.transform.rotation.eulerAngles.x > targetAngle.x && hingeKnife.transform.rotation.eulerAngles.x < (targetAngle.x + 10f))  // this is set to 295 it goes up to 297 (If your arm is all the way up)
{
hingeKnife.useMotor = false;
var theKnife = (GameObject)Instantiate(knifePrefab, knifeTransform.transform.position, knifeTransform.transform.rotation);
theKnife.GetComponent<Rigidbody>().AddForce(-force, 0, 0, ForceMode.Impulse);
Destroy(theKnife, 2.0f);
canShoot = false;
waitDone = false;
StartCoroutine(WaitAround(2f));  // shoot every 2 seconds
}
}
}
private IEnumerator WaitAround(float waitTime)
{
yield return new WaitForSeconds(waitTime);
waitDone = true;
hingeKnife.useMotor = true;
}
}

This is what the whole thing looks like put together:

As I mentioned above there is a bit of tweaking to get it to look right – but this post is about the process of putting everything together and how the components work to achieve the effect.

This is what it looks like after the tweaking:

I hope you found this interesting enough – if you did and want to read more about this stuff I did a post a few weeks back about how we do the guns in this game Endless Elevator:
http://www.zuluonezero.net/2019/03/15/unity-how-to-do-guns/

Enjoy.

Unity How To Rotate

Hi Xander here. I kept making mistakes and wasting programming time when it comes to Transform.Rotations. It can be hard to remember what all the inbuilt Unity Vector commands do and when it’s easier to use Quaternion.LookAt() or a different inbuilt command. so I created an example project that included common ways to handle a rotation and a graphical representation of them. I’m putting it up here in the hope that other people find it useful. The code and project files are in GIT here: https://github.com/zuluonezero/UnityRotation and I will give a description of what to do with it below.

All you need to do to get it working is to open a fresh project and remove any existing Camera’s and other items from the default Scene.

Then import the RotationsPrefab from GitHub and place it in the scene.

You will see that there is a cube set up in the middle with the Axis bars shown in green, red, and blue.

Have a look at the Cube object in the Editor and check out the script attached to it called RotationScript.

This is what it looks like:

This is the bit that deals with Vectors.
This is the bit that deals with Quaternions

Have a read through the code (most of which is not my own and comes from the Unity3d Manual examples for the functions called).

The script runs in the Editor but it’s better in Run mode (don’t maximize it or you cannot play with the script while it’s running).

You can use the Move Camera button to shift from 2D to a 3D view (3D is better).

Click Play and start messing round with the tick boxes and sliders of the Rotation script in the Editor. (Most of the tick boxes need to be unchecked after you have used them to move down the execute order of the script).

The first section plays with Vectors to rotate the cube and the seconds uses Quaternions.

There is a summary of what’s happening in the script on the screen but having the code open while you play helps understand what’s going on a little easier.

Here is a little demo of what it looks like when you play around with it.

I hope you get something out of this because even after a couple of years I still get this stuff wrong time and again and have to relearn it again. Hopefully now it will stick!

Xander out.

Unity How To Do Guns

Here at ZuluOneZero we love guns in games and other fantasy settings for their ability to embody drama, tension and action. They are a super power that takes us beyond the normal abilities to exert force. Sadly in real life guns suck and if you like shooting guns for real stay the heck away from me and my friends.

Anywhoo… this is how we use Guns in Endless Elevator to dispatch the Bad Guys and generally wreak havoc in an otherwise quietly innocent building.

This is our hero The LawMan! See he comes with that super powered lawmaster pistol, standard issue bullet proof vest, sherrif’s hat, and a make no mistakes we mean business moustache (can you tell he’s smiling under that?).

The LawMan

This is how he looks in the Unity Scene Editor. See those two Objects he has as Children “Gun” and “smoke”? They sit invisibly just where the 3D curser is in the image below…just at the end of the gun barrel. The Gun object is used as the spawn point for bullets and smoke is one of two particle systems that go off when the gun fires (the other particle system does sparks and is attached as a component directly to the Game Object).

There are four scripts that handle the basic Gun actions in our game. There are of course plenty of ways to do this – but this is the way we do it for this game. One script handles the aiming of the gun as part of the Character Controller. Another script attached to the Character handles the firing of the Gun and the spawning of the bullets. The Bullets have their own script that handles Gravity, Acceleration and Animations while alive and during Collisions. The last script attached to the Bad Guy handles the impact effects of the Bullets and the “blood”.

We wanted to keep the cartoon elements of gun violence in this game and get away from realism as much as possible. That said a bullet strike has a pretty huge impact and when we had a red coloured particle system for the blood it looked really gruesome. We changed the impact force to be over the top and super exaggerated so that it’s funnier reaction and moved the particle system color to yellow (might change it to stars later on). The Bullets are supposed to look like expanding rubber dum dum bullets so they grow out of the gun and enlarge a little bit in-flight. After a collision they start to shrink again and get very bouncy.

Here is a sample of game play where our hero blasts away at some chump.

So the Hero Character has a couple of scripts that handle aiming and firing.

The snippet below is the aiming component of the Character Controller. The Player has a wide Trigger Collider out the front that picks up when it hit’s a Bad Guy. If there are no _inputs from the Controller (ie. the Player stops moving) then he will automagically rotate towards the Bad Guy and thus aim the gun at him.

void OnTriggerStay(Collider otherObj)
{
if (otherObj.name == "bad_spy_pnt"  || otherObj.name == "Knife_spy")
{
if (_inputs == Vector3.zero)
{
Vector3 lookatposi = new Vector3(otherObj.transform.position.x, transform.position.y, otherObj.transform.position.z);
transform.LookAt(lookatposi);
}
}
}

Now once we are aiming we can fire (you can shoot at anytime – and straffing is pretty fun – but it’s far easier to hit if you stop and let the auto-aim work for you). For firing this is what the FireBullet script exposes in the Editor:

There is a “bullet” prefab which we will talk about below, the Gun transform (ie. bullet spawn point), the force at which the bullet is spawned with, the audio for the shot, and the particle system for the smoke (called PartyOn …. I know).

The script itself is pretty straightforward: The bullet is spawned at the Gun Transform with a direction and force, the gun noise goes off, and the particle system does smoke and sparks. After two seconds the bullet is destroyed. This is what it looks like:

using UnityEngine;
public class FireBullet : MonoBehaviour
{
public GameObject bulletPrefab;
public Transform bulletSpawn;
public float force;
public AudioClip fireNoise;
private AudioSource MyAudio;
public ParticleSystem partyOn;
public bool includeChildren = true;
void Start ()
{
MyAudio = GetComponent();
partyOn = GetComponent();
}
void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Fire();
}  
}
public void Fire()
{
partyOn.Play(includeChildren);
var bullet = (GameObject)Instantiate(bulletPrefab, bulletSpawn.transform.position, bulletSpawn.transform.rotation);
MyAudio.Play();
bullet.GetComponent().AddForce(transform.forward * force);
Destroy(bullet, 2.0f);
}
}

One of the really important lessons we learned from this script is to get the Transforms and X/Y/Z directions of your models imported into Unity in the right direction first up. We had a few different models for bullets over the last few weeks ranging from simple cylinders, to pillows and bean bags, and real bullet shapes. It makes it so much easier to direct objects if their rotations are correct to start with. For example we did one quick model of a cylinder but had it sitting on the Z axis instead of X so when we did the “forward” force the bullet would travel sideways.

This is how our bullet looks now:

This is how the script to handle it’s behaviours and the settings of it’s Rigidbody and Collider:

It’s got a Rubber material on the Collider so that it bounces around when Gravity is enabled in the Rigidbody on Collision. We disabled Gravity so that we could slow down the Bullet firing path and not have to use so much Force. Having a slow bullet adds to the cartoon drama, reinforces the rubber bullet idea, and looks less like killing force. Here is the script:

using UnityEngine;
public class BulletGravity : MonoBehaviour {
private Rigidbody rb;
public float force;
public float accelleration;
public bool collided;
public float scaleFactorUp;
public float scaleFactorDown;
public float maxScale;
public float bounceForce;
void Start () {
rb = GetComponent();
}
void Update()
{
if (transform.localScale.x  scaleFactorDown)
{
transform.localScale -= new Vector3(scaleFactorDown, scaleFactorDown, scaleFactorDown);
}
}
}
void FixedUpdate ()
{
if (!collided)
{
rb.AddForce(transform.forward * force * accelleration);
}
}
void OnCollisionEnter(Collision col) {
collided = true;
rb.useGravity = true;
rb.velocity = transform.up * bounceForce;
}
}

Below is the Collision part of the script that handles the BadGuy flying up into the air and bleeding all over the place.

void OnCollisionEnter(Collision col)
{
colName = col.gameObject.name;
if (colName == "bullet(Clone)")
{
hitpoint = col.transform.position;
GameObject BloodObject = Instantiate(BloodPrefab, hitpoint, new Quaternion(0, 0, 0, 0), TargetObject.transform) as GameObject;
Destroy(BloodObject, 5.0f);
//   We disable his AI script so he doesn't try and walk around after being shot :) It's not a zombie game.
var AI_script = GetComponent();
if (AI_script)
{
AI_script.enabled = false;
}
Vector3 explosionPos = transform.position;
explosionPos += new Vector3(1, 0, 0);
rb.AddExplosionForce(power, explosionPos, radius, offset, ForceMode.Impulse);
yesDead = true;
Destroy(transform.parent.gameObject, 2f);
}
}

Let’s break down the whole process visually. Here is our Hero in a standoff with a Baddy. He hasn’t aimed yet but you can see his big aiming collider in yellow underneath him extending out front and of course the character box colliders are visible too in green. (The Bad Guy has a yellow sphere collider on his head cause we make him get squashed by lifts!).

Here we are just after firing. His aiming script has put him on target and his bullet is there travelling with force and bloating in size.

And this is the impact with the force applied to the Bad Guy and his yellow blood impact stuff spewing out dramatically for effect.

All we got to do now is to clean up the Bad Guy’s object and destroy the used bullets. We don’t do any object pooling for the bullets yet…the overhead for the current system has warranted it but maybe later on.

That’s about it. Hope you’ve enjoyed this gun for fun expo-say.

Trixie out.

Endless Elevator – Show Reel

DevLog March 2019: This month we did a cheesy show reel of the latest changes in development for Endless Elevator.

This is a very early “In Editor” development sketch up of some of the features currently being included… Enjoy the show.

The game will be available on the mobile app stores in 2019.
For more information subscribe to our Dev Blog at: http://www.zuluonezero.net/zuluonezero-devblog/

Violation of Usage of Android Advertising ID policy and section 4.8 of the Developer Distribution Agreement

This week we got an email from Google about our demo game Adventure Text that we had released to the public ten or so days before on the Google Play Store.

The game was removed from the Play Store with this email being the only notification after the fact. The public couldn’t see it, couldn’t search for it, and any live links from promotional material wouldn’t connect through to it. If this was a commercial product or even one that I had a vested interest in it would have been a small disaster. Those first few days of a game release are critical for generating user interest.

The reason that the app was removed was because we had included the Unity plugins for Analytics and Advertising in the packages that it was compiled with. Our app is a demo of a Text Adventure framework we built as a side project and we did not use either of these packages. They were included in our base build of the project by default even though we had the Enable Analytics switch turned off when we created the project.

One or both of these packages was capturing either user data or Android Advertiser ID’s in the background. Because we were not actively using the packages and did not capture any user data as part of our application we were kind of stumped. We did a bit of Google Foo and found that a common source was the Unity packages for Analytics and Monetization. Here they are in the project folder (below) – was kind of obvious once you look but since we weren’t using them in any of our code I figured they would not be included in the final package (just like unused assets). Wrong!

Google Play requires developers to provide a valid Privacy Policy when the app requests or handles sensitive user or device information. If they identify that your app collects and transmits the User Data or the Android Advertising Identifier then you must provide a valid Privacy Policy in both the designated field in the Play Console, and from within the app.

You can read more about the Google Play policies for Privacy in the Developer Policy Center (see Advertising and User Data Privacy). There is also more information available in the Google Play Developer Distribution Agreement.

In our case it wasn’t a big thing. We had just released a demo game for fun not for profit. But if you were going for a monetized app (and hey why not) you do need to use a valid Privacy Policy both somewhere available on the internet and also from within the application.

This was a game made in a week. There was no way we were adding another button for a privacy policy we didn’t really need. We took the offending packages out of the project in Unity (Window -> Package Manager) by using that little “Remove” button there in the top right hand corner:

We rebuilt the game and uploaded another release to the Developer Console and in a few hours the app was again available on the Google Play Store. Phew. Cool. Problem solved.

But what if we really wanted these packages? What would we have to do? Well first we needed a Privacy Policy. There were some pro-forma one’s available on the interwebs that might have been appropriate. I found several forum threads where other people had had this problem and used this site to generate one: here

I cannot endorse or even suggest that it’s a good idea to grab something off the internet that is a legally binding policy so please do your research on this subject before you leap into it.

Once you get your policy in place it needs to go somewhere on your web site so that it’s publicly available.

It also needs to be available in your Google Play Store Listing. If we wanted to use one it would go down the bottom in the Google Play Developer Console:

Finally you would need a mechanism in your game or app that allows users to easily find and see your Privacy Policy from within your game.

People’s privacy and the data you collect from your applications and games is an important topic. Both ethically and practically.

It’s kind of a dummy mistake to get caught out by this one. Don’t let it be you! Be aware that the default project settings in Unity (at least in the 2018 build) include packages that collect user data and that if you include these packages you need to have a Privacy Policy.

Maybe even if you didn’t include these packages it would be a good idea to have one anyway. It’s totally ok for app developers to gather information that’s going to enable them to make a better product and I think most game developers include either analytics and advertising in their games. It’s unfortunate that Unity includes these packages in the default project build without really making the end user aware of it but if you look it’s plain to see. Also if you are informed and have read all the Google Play Store policies that are there to protect everyone then it shouldn’t be too hard to put it all together.

Zulu out.

Demo Text Adventure Game Released on Google Play

Hi Harmony here….

We released the demo game for our Text Adventure framework on the Google Play Store this week.

https://play.google.com/store/apps/details?id=com.ZuluOneZero.AdventureText


The Code for the Project is available on GITHUB:

https://github.com/zuluonezero/AdventureText

Quick Start Instructions for building a 2D Unity project are available on the README.

More detailed information is available in the ZuluOneZero – DevBlog.

See our posts about the development of this game and more information on how to configure the project: 

I hope you enjoy playing with it.

If you have any questions or need support you can email us at zuluonezero.z10@gmail.com.

Harmony out…

Text Adventure Design and Programming

Hi Xander here….

This post is about the design and build of our Text Adventure game over the course of a week. This was a “proof of concept” project to make a framework for a text based game that could be re-used and expanded on for future use. It’s not a polished game but an exercise in execution – and a jolly fun one at that.

The main features of the game are:

A simple 2D UI with Directional buttons an Action/Attack button, and a “Show Map” button. A HUD bar at the top with Player HP (hit points) the outcome of combat interaction (Player vs Monster) and during combat the Monster HP.

A large text area for describing your location and the environment around you. This area also shows the random actions taken by both Players and Monsters during combat.

A map that is gradually exposed as you explore the game.

This is the starting layout (digging the “panelled wood” feel here):

In the Scene the main Game Objects are:

The Canvas for the UI.

An InputControl object to handle what happens when a button is pressed and provide the appropriate response.

A FightClub object to handle combat events.

Another Map Canvas to show the map and hold all the map components.

And what I call the WayPoints which are the different locations and events that can happen during the game. Each one gets a new object and in this sample game there are Thirty Four of these nodes. These objects hold all the information about a particular location including which WayPoint is next in any give direction and what Monster if any appears here.

This is what it looks like in the explorer:

I’ll go through the main scripts one by one.

I will also put all the scripts in our GIT Repository (link below).

WayPoint Script

This is a custom class that mostly just holds data about a given location and only if required Generates a Monster. See the example below (which shows a section of the full details):

The first boolean tick box Way Point Visited let’s the InputControl script know if an area has been explored before. This allows alternate short descriptions of the location (which makes navigating known areas faster) and is used by the mapping component to tell if an area of the map can be revealed or not.

The Name, UID and Description fields are not actually used but I added them in for future use. Since the Object name includes a UID and is a descriptive name (Eg. 06_StatueFight) I didn’t really need them for coding.

The Write_rate and Text_size are passed to the Main Printing System (also attached the InputControl object) so that there is some control over the speed and size of the text that prints on the screen like a typewriter for managing the pace of the game. Faster and larger for combat and exciting events and slower for more descriptive passages.

The Text Sections are self explanatory. When a Player enters a location the first time or a repeated time this is the text that is printed.

WayPoint _forward, _backwards, _left, and _right point to the name of the next WayPoint object in that direction. If it’s NULL then there is nothing in that direction.

The rest of the script is for defining if a Monster spawns in the given location, it’s attributes, and the text options passed to the FightClub combat module (each Monster has different attack and defence descriptions to make it more variable and exiting).

The WayPoint script has one Function called GenerateMonster() which when called by the InputControl system does just that with the info in the WayPoint class for the monster we defined above).

Input Control Script

The Input Control Script handles input from the four directional buttons (Forwards/Backwards/Left/Right or North/South/East/West), the Action/Attack button and the Map button. The Map button shows the map canvas and the progress the player has made within the dungeon. The Action/Attack button is only used once the Combat feature is triggered. The main body of the script is for handling navigating around with the directional buttons and triggering special events attached to some locations.

The Current Waypoint variable is the most important piece of the whole game system. It holds all the data for the current location such as the available text to print and if there is a Monster to fight or other special action.

The next public variables hold references to all the components we will need in the Input Control Script: The Combat System (FightClub), the UI buttons, and the Map Canvas.

We also have two bools. One to let us know if the game has just started so we can show the appropriate text and one to let us know if there is a Monster present (so we can initiate the Combat System).

The Generate Map function in this script does a find on all the WayPoint objects in the game and collects their names. Each map piece is tagged with it’s related WayPoint name and if the “visited” bool has been check it displays that part of the map.

Print Main Text

This is the printing workhorse of the game. It takes the input from the WayPoint (and a text size and speed of typing) and prints it out on the main screen like a typewriter.

It handles all the printing to the other smaller text components as well like the Title, HP and Combat stats.

This script is made into a Singleton so it’s easy to call from all the other scripts that have printing needs.

Fight Club

The Fight Club script is the combat system. Very simply the Player and any Monster gets a maximum and minimum limit to their random integer attack. The player gets an optional “Weapon bonus” if he/she picks up a magical sword during the course of their adventures which adds the random int. Whoever has the higher number wins. The value of their integer is also the amount of damage done. Damage is done against another integer (Hit Points or HP) which if it reaches 0 indicates that the combatant has died (usually horribly).

This is the public behaviour of the script:

The Monster’s HP and Min/Max Damage is recorded in the WayPoint for that location and passed from the MonsterStuff class that is attached to the Monster.

Monster Stuff

The Monster Stuff script is attached to a Monster prefab and is instantiated when a monster spawns. This is the behavior:

As you can see it’s the same sort of stuff that the Player has in the Fight Club script (HP, Max and Min Damage) but there are also arrays of text fields. The Monster prefab gets passed all this data from the WayPoint script on instantiation so they are really just placeholders waiting for data.

The Dead bool is pretty self explanatory – you couldn’t get more boolean!

The Monster Stuff class presents four functions:

MonsterAttack(), MonsterTakesDamage(), MonsterAttackText(), and MonsterDefenseText(). The attack and damage functions return integers for calling from the FightClub and the text functions return the appropriate text to the FightClub. Each Monster has its own special attacks and defences so the text generated for the fights is unique. The attacks and defences are arrays so you can expand the available text options at will thus making the game more interesting and variable.

Other Miscellany

That is basically all the scripting that there is to the game! It’s a Text Adventure so most of the work goes into the writing and the story that you build into the WayPoints. It’s pretty light and flexible and able to be extended a number of ways.

There is also script to open the map and close it and to reset the game back to it’s starting position but I won’t talk about them here. They are pretty generic.

GIT Hub

All of the code is available publicly on our GIT Repository: https://github.com/zuluonezero/AdventureText

Xander out.