Category Archives: Uncategorized

The Making of Game of Clowns

I’ve just released my Unity game, Game of Clowns on iOS (it’s been on other platforms for some time already), and I thought it would be helpful to explain how I made it.

Background

Game of Clowns is a physics puzzle game in the tradition of Amazing Alex and The Incredible Machine. It’s my second game, but my first made in Unity (my first game, Puzzle Detective is available for Windows Phone, WinRT, and Windows 10, and was built in Visual Studio). I was totally new to Unity and C# when I embarked on making this game.

A Naïve Effort Assessment

After playing around in Unity I discovered the Asset Store, and found that I could buy a pre-built game template. I figured I could replace the graphics and audio, build my own levels, and – ABRACADABRA! - have a complete game. To cut a long story short the game took more than 6 months of every spare minute I had (making games is not my day job), and far more work than I anticipated. I learned a lot while making the game, and I’m now sharing what I learned in this article.

Designing the Game

Game of Clowns isn’t a particularly original game (it was built using an Asset Store template, after all). My main motivation was to build something like Amazing Alex because it wasn’t available my Windows tablet. I also figured that a physics puzzle game was manageable, but also more challenging to make than Puzzle Detective. With a genre chosen, my next decision was to pick a theme that suited it. I ended up with two ideas:
  • A Flintstones-like caveman theme
  • A circus with flying, bouncing clowns.
I decided on the circus theme because it could be colourful and funny, but most importantly it could feature clowns being shot out of cannons.

Scope Creep

Two factors led to the game’s scope increasing hugely. Firstly, I found that the template I was using had a few issues (the makers of the asset, as well as users on the asset’s forum thread, were very helpful in resolving them), which required me to increase my Unity and C# knowledge sharply. Secondly, the more I worked on the game the more my ideas flowed. I wanted to add new physics objects (which I would have to build myself with my still limited Unity skills), and improve existing features. The amount of work needed was creeping up. I realised that the game would take a lot longer to finish than I had first thought.

Lessons Learned

  • Any estimate of effort required is probably short by a LOT.
  • A template is a starting point for your own ideas, not a ready-made game.

Making Progress

I developed an organisation technique when creating my previous apps and game. Every task I’ve identified – whether it’s as small as fixing a typo or as big as adding a huge feature – goes into either my current working checklist or put aside for future work. Keeping a good balance of ‘quick wins’ and more substantial work in my current checklist helps keep momentum. If I only have a few minutes to work, I can check off one or two quick wins; if I’m in the mood for digging into the code I can work on a large feature; if I’m feeling like Sherlock Holmes I can investigate an elusive bug. Using this checklist method, I found I could stay motivated even as the scope got bigger and bigger, because there was always a task waiting for whatever mood I was in or how much time I had. When I complete a checklist I mark that ‘version’ complete and create a new checklist from outstanding tasks.

Lesson Learned

  • Productivity directly correlates with organisation.

Art

Once I had momentum I decided to buy some art. Due to the game’s design I didn’t need any animation or a lot of art, which suited my limited (non-existent) budget. I found a great artist (via Reddit) who was able to draw what was in my head perfectly. This clown with a hose is my favourite piece:

Here’s how I sourced all the art in my game:
  • Commissioned art.
  • Licenced art packs.
  • UI pack from the Unity Asset Store.
  • Art from the game template.
  • Public domain sprites.
I spent a few hundred dollars on art, and I’m very happy with the outcome on that budget. The art that was drawn specifically for me is perfect, and I’m pretty happy with what I achieved with the public domain and licenced art too.

Commissioning Art

When commissioning art I sent the artist some sample images showing the style I wanted, along with a few notes. When I needed a clown driving a tiny car I sent these images to the artist:

And here is what she created:

Fantastic art, and exactly what I had in mind. To stretch the usefulness of some of the other art, I created different coloured variations using a simple image editor. The game template asset came with a small red ball sprite, which I used as the basis for some different coloured balls. This simple trick makes the game livelier at no extra cost.

Lessons learned

  • Art is worth every penny you spend on it, and it’s great to find an artist who can draw in exactly the style you want.
  • When your budget is small you can find ways to stretch it. Try re-colouring art for variation, search for public domain images, and look into licencing packs of art that suit your game style.

Building up the Engine

I estimate that by the time the game was finished I had rewritten more than half of the code that came with the purchased asset in order to accommodate my game’s needs, enhance features, and fix bugs.  I must make it clear that I didn’t rewrite chunks of the asset code because it was deficient. I wanted to expand it to allow for new features and to better fit my evolving ideas for the game. There were a few minor bugs, but the asset creators always helped fix them. There is a pretty big thread on the Unity forum where myself and several other users shared ideas and code for improving the asset too. I also learned a lot about Unity from the code provided in the asset. Here are a few of the features I ended up adding to the game:
  • Cannons that shoot clowns.
  • Trap doors that can be opened by pressing a button.
  • A clown with a hose that pushes objects that enter its stream.
  • Moving platforms (horizontal and vertical).
  • Multiple goals to complete a level.
  • Custom touch input controls to make manipulating objects more intuitive and reliable.
Unity itself presented some challenges. Some of the 2D collision functions didn’t work reliably, which caused unpredictable bugs. I ended up adding workarounds and hacks that required me to learn lots more about Unity.

Lesson learned

  • Purchased assets can save you a huge amount of time, but they work best when you use them as a starting point to build on.

Music and Audio

When I started adding audio and music the game really started to come alive. I knew I wanted the classic clown theme ‘Entrance of the Gladiators’, and I found a reasonably priced version to licence. Then I found a few licenced and public domain tracks that had a circus feel, and set the music to rotate randomly between the tracks. I spent about US$30 on music. I wish I could have afforded a custom theme song for my game, but the game’s theme luckily lends itself to the well-known, well-used ‘Entrance of the Gladiators’ theme. This game trailer includes the famous clown music: All of the audio is public domain, but there isn’t much. Audio is one area I wish I’d spent more effort on, but by the time I was filling in the sounds I was trying to limit the effort needed to reach the finish line.

Lessons learned

  • Sound and music are as important as graphics, but unless you’re a sound or music person that’s not necessarily intuitive. George Lucas says that sound is 50% of a movie, and I think that holds true for games too.
  • You can get pretty good sound and music on a budget, but as with graphics you get the most value from something customised to your game.

Levels, Levels, Levels

Game of Clowns has 88 levels (some of those were added in updates after the initial release). That’s quite a lot of levels. The amount of work that went into designing, building, and testing the levels was probably 100 times more effort than I anticipated (I’m not exaggerating). Every level was carefully designed, sometimes on scraps of paper, sometimes in my head as I rushed to the computer before the idea evaporated.

So Much…Fun

Designing physics puzzle levels is fun. There is something tangible about objects behaving realistically. Watching a clown shoot out of a cannon, bounce on a trampoline, collect a star, then fall into a barrel of water with a splash…it’s so much fun. I thought I’d never tire of making levels, and this would be the easy, fun part of making the game…

So Much…Work

Designing game levels is a lot of work. The nature of a physics puzzle game threw up challenges I didn’t anticipate. Any change to the game’s underlying physics object behaviour necessitated re-testing every level. The difficulty curve was very hard to get right – it’s actually very difficult to determine how difficult a puzzle is when you’ve made it yourself! This meant that I was constantly shifting levels around between the different level sets in the game. Because I had planned some aspects of the game poorly (it was my first Unity project after all), moving levels around was a lot more work than it should have been, which added to the tedium of creating so many levels. One shortcut I found (and wished I’d found earlier) was to ‘cheat’ in my levels. Sometimes I could get a level to work better by tweaking the physical properties of objects slightly. For example, if the level requires the player bounce a clown off a trampoline to get to a shelf I might tweak that specific trampoline to be a little bouncier than normal. I used this technique sparingly, and only where I felt it helped make the player’s intuitive understanding of physics work as expected. I could have saved myself a lot of time if I had built a level editor and implemented a way for levels to be loaded and saved to XML. In the game each level is a Unity scene. I didn’t know at the time that that approach would not scale well. I did eventually build a prototype level editor, and in my tests I could get a big improvement in my game package size and performance by storing the levels as XML, but re-working and re-testing every level into the new format would not be worth the effort.

Puzzle Blind Spot

At one point I sent an alpha version of the game to a friend to playtest levels. One of the new levels was quite complex, requiring several carefully placed objects in just the right places in order to solve the puzzle and collect all three stars. It was designed to be one of the game’s hardest challenges. My friend solved it in a ridiculously simple way I didn’t anticipate. I was focused so much on the level I had designed that I was blind to the very obvious simple solution.

You can Never Test Too Much

I developed a habit of playing through every single level as often as possible. On the train home from work I would play as many levels as I could, noting down any problems or glitches, then I’d fix those problems as soon as I got home. I would do this almost every day. I played through each level more than a hundred times, some levels probably 200 or more. The playtesting got extremely tedious towards the end, but it was invaluable. But by the time the game was finished I was absolutely sick of playing the levels!

Lessons learned

  • You should have as many people as possible test your game. Different points of view shed light on different things, often things you as the developer can’t see.
    • Non-gamers will show you if your game is intuitive.
    • Kids will show you if your game is simple and fun.
    • Good gamers will find creative ways to solve problems.
  • Any time or effort saving you can find in creating levels is worth implementing. The effort required to build a simple level editor and/or serializer will repay you several times over in saved time and energy.
  • Designing levels is a huge creative drain. Spread the load as much as possible. Look for inspiration everywhere. It’s not the ‘fun’ part of developing a game, it’s just as much work as any other aspect.

The Final Countdown

Eventually I had to decide that I was going to finish and publish the game. I decided on a ‘feature freeze’ and set about polishing the game as much as possible. I played through the game over and over again, noting any issue – no matter how small – on an ever-growing list of must-do fixes. Here’s a small sample of my issues list as I headed down the home stretch. On the left are general issues, and on the right are tweaks to the levels:

Since I’m not beholden to a publisher or any set schedule I could take the attitude of releasing the game when it was good and ready. However, I did choose to limit myself to just polish and bug fixes at this stage or I knew I would never finish. Here’s one of my favourite bug notes: The funny thing about that bug is that it bothered me for a long time…and that was simply due to my lack of Unity experience. It was quite a simple fix in the end. I chose Windows Phone and Windows 8/RT as my launch platforms because they were the platforms I was most familiar with. I figured I could port to Android (and possibly iOS) later. I didn’t have any financial expectations for the game, so the platforms didn’t matter to me at all, really. I finally finished the game and pushed a very small number of issues into my plans for version 1.1, which I would get to work on as soon as version 1.0 was submitted. Lessons learned:
  • You need to draw the line somewhere in order to finish a project. Don’t be scared to release something that is not 100% finished, but make sure it’s 95% there and nicely polished.
  • Test constantly. Note down any issue no matter how small, then fix it. Some issues don’t present themselves immediately. There is an example in the list above of a sound effect that is annoying – but it’s only annoying when you hear it several times, which only happens when you playtest the game properly.
  • Don’t be afraid to push a feature or bug fix into a future update. You can’t fix everything immediately. A bug that only happens in very specific circumstances will not affect many people, and you can fix it with a clearer head if you just release the game and then get to work on a small update to fix the bug.

Marketing

Because I had no actual budget I did very little marketing. I did spend a small amount of money on some banner ads, and I promoted the game on a few websites and forums. I don’t think my marketing had any real effect on downloads or sales. I know that advertising is crucial if you want to make your game successful. It’s practically impossible for a game to get noticed among the glut of products being released into app stores every day, and you’re competing with the big game studios. If I had a real budget I would probably choose to spend 50% of it on marketing if I felt I had a game that could be popular, but ifor my hobby game I had to choose to put it out there and cross my fingers. The game was originally called Clowntraptions, and was renamed sometime between the initial release and the Android release a few months later. I felt the pun was a bit forced and obscure, and I thought maybe Game of Clowns could trade on the popularity of Game of Thrones.

Lesson learned

  • There is no success in the app world without marketing (unless lightning strikes). People need to know your game exists; they need to want it; you need to reach a critical mass of recognition. That comes from marketing.

Other Platforms

I released Game of Clowns almost 2 years ago on Windows platforms. The intention was always to release an Android version, and then an iOS version if I could figure out how (I don’t own or use any Apple devices, so there’s a big barrier there). I published both a free (limited to about 30 levels) and a paid version to Android a few months after the initial launch, again with no marketing. I have sold very few copies on Android, though I have almost reached 20,000 free downloads, which is cool, I suppose. Ratings are generally 4 or 5 stars, which is great. Porting to Android (and later iOS) was very easy. There is only one script in the final code that has any differences for the different platforms. I got some help accessing a Mac via remote desktop, and set about publishing the iOS version. The tools were new to me, and using remote desktop was tedious, but I got it sorted out and published.

iOS Publishing

A major reason it took so long to port to iOS was the cost of a developer licence (AU$150 per year compared to a nominal one-off fee on Android and Windows). I don’t know if I’ll sell enough copies on iOS to cover the developer licence, but at least I have iOS publishing experience and my iOS-using friends can now play the game.

Lessons learned

  • I get far more downloads and sales on Windows Phone than Android. This is probably due to the difficulty of being noticed in the much larger Android store.
  • iOS is a trickier platform to publish to, and costs a lot more. Time will tell if iOS users buys more copies than Android and/or Windows users.

Conclusion

The main lessons I learned while making Game of Clowns were:
  • Game development is hard work, and there are no shortcuts.
  • Only through experience can you really understand how much work goes into any aspect of game development.
  • The best art and music comes from talented people who have the required skills, but with some clever tricks you can stretch a small budget.

What I Spent

Here’s a quick list of costs I incurred making this game. I’m very happy with the end product considering the budgetary constraints I had.
  • Art: ~US$400, mostly on commissioned art
  • Music: ~US$30 for licenced music
  • Software: US$55 for original game template
  • Marketing: ~US$150 on some banner ad impressions.
I haven’t made back the ~US$600 I spent creating the game, but I’ve definitely got more than US$600 worth of lessons learned.

Get the Game

If you want to check out Game of Clowns, you can get it for the platform of choice from the following links: Android (free version with limited levels) Android (paid full version) Windows Store (phone/PC Windows 8+, works great with mouse or touch) iOS (iPhone and iPad) Game of Clowns website and desktop PC version  

Word Game Drag-and-Snap

Intermediate: I expect you to know a moderate amount of Unity and C# coding to follow this tutorial, and I don’t go into beginner-level detail. Please refer to my Beginner’s Pong Tutorial if you’re a beginner and find this tutorial too advanced. You can still download the full demo project below and poke around. Following on from my previous article explaining drag-and-drop functionality, I’d like to show you how to implement ‘snapping’ objects to a specific place, such as a Scrabble grid: drop-snap

How does it work?

We will create a simple Scrabble/Words with Friends demo, with a few tiles that can be dragged onto a board grid, so we’ll:
  • Create a board with a grid of possible letter tile positions.
  • Create tiles with different letters on.
  • Allow dragging of the tile objects.
  • Determine where a tile should be placed when it is dropped.
  • Smoothly move the tile to the correct position for a nice feel.

Get started

Create a new Unity project and choose the 2D settings. Download the sprites package below. Get the complete demo project. I’ve included some public domain letter tiles in the project. As usual I use art by Kenney, who provides tons of great free art for the game development community. You can find his art - and ways to support him - at Kenney’s website.

Build a game board

To build a game board, I created a simple square cell prefab with a sprite and a BoxCollider2D. I then created a row from 5 cells side by side. Finally, I stacked 5 rows vertically to create a grid. There’s nothing notable about the grid, so you should be able to create your own without detailed instructions, or you can just copy the one in the sample project. I gave the grid its own layer so that I could tell the InputManager to ignore it. This ensures that the input doesn’t incorrectly detect touches on the grid when the player is trying to grab a letter, and raycasts can be a little unusual if you’re not careful.

Drag and Drop Script

The script that controls the drag-and-drop functionality is basically the same script from my previous article, so I won’t explain it again here. The main difference here is that the script calls some public methods on the Tile objects when a tile is picked up or dropped. Here’s the drag and drop script in full. Note: This script calls methods on the Tile script, so you can’t test this script out until you’ve also created the Tile script, which we’ll do next. [code language=”csharp”] using UnityEngine; using System.Collections; public class InputManager : MonoBehaviour { private bool draggingItem = false; private GameObject draggedObject; private Vector2 touchOffset; void Update() { if (HasInput) { DragOrPickUp(); } else { if (draggingItem) DropItem(); } } Vector2 CurrentTouchPosition { get { return Camera.main.ScreenToWorldPoint(Input.mousePosition); } } private void DragOrPickUp() { var inputPosition = CurrentTouchPosition; if (draggingItem) { draggedObject.transform.position = inputPosition + touchOffset; } else { RaycastHit2D[] touches = Physics2D.RaycastAll(inputPosition, inputPosition, 0.5f); if (touches.Length > 0) { var hit = touches[0]; if (hit.transform != null && hit.transform.tag == "Tile") { draggingItem = true; draggedObject = hit.transform.gameObject; touchOffset = (Vector2)hit.transform.position - inputPosition; hit.transform.GetComponent<Tile>().PickUp(); } } } } private bool HasInput { get { // returns true if either the mouse button is down or at least one touch is felt on the screen return Input.GetMouseButton(0); } } void DropItem() { draggingItem = false; draggedObject.transform.localScale = new Vector3(1, 1, 1); draggedObject.GetComponent<Tile>().Drop(); } } [/code]

The Tile Script

The tiles themselves have a script that handles what happens when the tile is manipulated. Before we get to the full Tile script code I’ll explain what the script does. We have two public methods (that are called by the InputManager script) to handle picking up and dropping the tile.

PickUp()

This method simply makes the tile a big larger and raises its sprite’s sorting order so it is always above whatever you’re dragging it over. [code language=”csharp”] transform.localScale = new Vector3(1.1f,1.1f,1.1f); gameObject.GetComponent<SpriteRenderer>().sortingOrder = 1; [/code]

Drop()

The important code in the Tile script is the Drop method. I’ll explain each piece of the method separately, and you can see it all together in the full Tile.cs script later. The first thing we do is undo the scaling and sorting adjustment that was done when the tile was picked up: [code language=”csharp”] transform.localScale = new Vector3(1, 1, 1); gameObject.GetComponent<SpriteRenderer>().sortingOrder = 0; [/code] In the OnTriggerEnter2D() and OnTriggerExit2D() methods, we keep a running list of any grid cells that the tile is currently touching. The code for that is straightforward, and you can see it in the full script code, so I won’t detail it here. Knowing that we are keeping track of grid cells in contact with the tile we first check if the tile it touching any grid cells. If not, we set the tile back to its original starting position and make sure its parent is reset (as you’ll see in a moment, when a tile is dropped on the grid we make it a child of whichever cell it was placed into). [code language=”csharp”] if (touchingTiles.Count == 0) { transform.position = startingPosition; transform.parent = myParent; return; } [/code]

Deciding the Closest Cell

If the tile is touching only 1 cell, we drop the tile into that cell; if multiple cells are being touched, we cycle through them all and figure out which is the closest. [code language=”csharp”] var currentCell = touchingTiles[0]; if (touchingTiles.Count == 1) { newPosition = currentCell.position; } else { var distance = Vector2.Distance(transform.position, touchingTiles[0].position); foreach (Transform cell in touchingTiles) { if (Vector2.Distance(transform.position, cell.position) < distance) { currentCell = cell; distance = Vector2.Distance(transform.position, cell.position); } } newPosition = currentCell.position; } [/code] Finally, we have to make sure the cell is not occupied before dropping the tile into it: [code language=”csharp”] if (currentCell.childCount != 0) { transform.position = startingPosition; transform.parent = myParent; return; } else { transform.parent = currentCell; StartCoroutine(SlotIntoPlace(transform.position, newPosition)); } [/code]

Smoothing the Drop

One last thing we do is to make the tile slide neatly into its cell so it doesn’t appear to suddenly snap into place. We achieve a smooth effect by using a co-routine to gradually move the tile’s position over a period of time until it’s exactly centered on the cell. We use the tile’s current position as the starting point and the cell’s position as the destination. Then we use Vector2.Lerp to move the tile closer and closer to the destination over the amount of time we specify. One extra trick I added was to force the tile’s position to match the end position exactly once the co-routine has run its course. This prevents the possibility of the tile not perfectly lining up with the cell’s position due to rounding errors (you can think of it as a final check: if the tile’s position is not the same as the cell’s position then force it). [code language=”csharp”] IEnumerator SlotIntoPlace(Vector2 startingPos, Vector2 endingPos) { float duration = 0.1f; float elapsedTime = 0; while (elapsedTime < duration) { transform.position = Vector2.Lerp(startingPos, endingPos, elapsedTime / duration); elapsedTime += Time.deltaTime; yield return new WaitForEndOfFrame(); } transform.position = endingPos; } [/code]

The Full Tile Script

Here’s the tile script in full. I’ve also added an audio source to the tiles in the demo so the tiles make a nice sound when they slide into place. [code language=”csharp”] using UnityEngine; using System.Collections; using System.Collections.Generic; public class Tile : MonoBehaviour { private Vector2 startingPosition; private List<Transform> touchingTiles; private Transform myParent; private AudioSource audSource; private void Awake() { startingPosition = transform.position; touchingTiles = new List<Transform>(); myParent = transform.parent; audSource = gameObject.GetComponent<AudioSource>(); } public void PickUp() { transform.localScale = new Vector3(1.1f,1.1f,1.1f); gameObject.GetComponent<SpriteRenderer>().sortingOrder = 1; } public void Drop() { transform.localScale = new Vector3(1, 1, 1); gameObject.GetComponent<SpriteRenderer>().sortingOrder = 0; Vector2 newPosition; if (touchingTiles.Count == 0) { transform.position = startingPosition; transform.parent = myParent; return; } var currentCell = touchingTiles[0]; if (touchingTiles.Count == 1) { newPosition = currentCell.position; } else { var distance = Vector2.Distance(transform.position, touchingTiles[0].position); foreach (Transform cell in touchingTiles) { if (Vector2.Distance(transform.position, cell.position) < distance) { currentCell = cell; distance = Vector2.Distance(transform.position, cell.position); } } newPosition = currentCell.position; } if (currentCell.childCount != 0) { transform.position = startingPosition; transform.parent = myParent; return; } else { transform.parent = currentCell; StartCoroutine(SlotIntoPlace(transform.position, newPosition)); } } void OnTriggerEnter2D(Collider2D other) { if (other.tag != "Cell") return; if (!touchingTiles.Contains(other.transform)) { touchingTiles.Add(other.transform); } } void OnTriggerExit2D(Collider2D other) { if (other.tag != "Cell") return; if (touchingTiles.Contains(other.transform)) { touchingTiles.Remove(other.transform); } } IEnumerator SlotIntoPlace(Vector2 startingPos, Vector2 endingPos) { float duration = 0.1f; float elapsedTime = 0; audSource.Play(); while (elapsedTime < duration) { transform.position = Vector2.Lerp(startingPos, endingPos, elapsedTime / duration); elapsedTime += Time.deltaTime; yield return new WaitForEndOfFrame(); } transform.position = endingPos; } } [/code]

 That’s All, Folks

That’s everything. You can check the demo project if you can’t recreate the functionality fully.

Drawing Lines with LineRenderer

Unity’s LineRenderer component gives you the ability to draw lines with multiple segments. You can use this to draw anything line based, like a rope or a finger drawing. This tutorial is for intermediate users: I will expect you to know your way around Unity reasonably well and understand basic code without explanation. Please see my earlier tutorials if you’re a beginner.

What is a LineRenderer?

A LineRenderer component is a standard Unity component that draws a line (in one or more segments) based on the settings you provide. You can set several options, most importantly:
  • The line’s positions (each point along the line, which will be connected to each other to form the line)
  • The line’s starting and ending thickness (how wide the line is drawn at its beginning and at its end)
  • The material that determines how the line looks.

Adding a LineRenderer

To use a LineRenderer you can add one in the Inspector (confusingly, it’s under Effects, not Rendering), or you can add one in code: [code language=”csharp”] var line = gameObject.AddComponent<LineRenderer>(); [/code] Here’s a screenshot of a simple LineRenderer with some sample settings you can copy into your own project: I’ve manually filled in the positions and line thickness, but you can of course do this in code too. You can only have a single LineRenderer component attached to a transform. If you need several, you can create a child transform for each on the parent.

Coding a LineRenderer

To setup your line you’ll need to give it the appropriate settings. Here’s a basic method to setup a LineRenderer with the key properties: [code language=”csharp”] void SetupLine() { line.sortingLayerName = "OnTop"; line.sortingOrder = 5; line.SetVertexCount(2); line.SetPosition(0, startingPoint); line.SetPosition(1, middlePoint); line.SetPosition(2, endPoint); line.SetWidth(0.5f, 0.5f); line.useWorldSpace = true; line.material = LineMaterial; } [/code] Let’s go through that code line by line. [code language=”csharp”] line.sortingLayerName = "OnTop"; line.sortingOrder = 5; [/code] These lines sets the line’s sorting layer and order. In my testing I’ve found that you need to set this when the line is created, as changing it later doesn’t have any effect. Make sure you set the line how you need it in relation to other objects in your scene. [code language=”csharp”] line.SetVertexCount(3); line.SetPosition(0, startingPoint); line.SetPosition(1, middlePoint); line.SetPosition(2, endPoint); [/code] These lines set how many points make up the line, and then adds a position to each point forming the line’s shape. Here I’ve set a line to have three points, then set each to the value of a vector variable. Note that the vertex count is 1-based, but SetPosition is 0-based. [code language=”csharp”] line.SetWidth(0.5f, 0.5f);[/code] This line sets the line’s width at the start and end (i.e. at the first and last points on the line). If you set both to be the same, the line will have a uniform thickness, otherwise the line will taper towards the end that is thinnest. [code language=”csharp”] line.useWorldSpace = true;[/code] useWorldSpace determines if the positions you set are based on ‘world space’ or are relative to the line’s transform’s position. You’ll usually want to set this as true. [code] line.material = LineMaterial;[/code] This line sets the material used to draw the line. If you don’t set a material the line will be magenta by default.

LineRenderer Weirdness

No GetVertexCount or GetPosition

For some reason there is apparently no way to get the number of positions in a LineRenderer or to add a new position without keeping track of the line details yourself. So I always keep a List<Vector2> (for 2D lines) and update that list every time I need to change the line’s positions. Here’s a method to add a new point to extend an existing line: [code language=”csharp”] void AddLinePoint(Vector2 newPoint) {        storedLinePoints.Add(newPoint); // add the new point to our saved list of line points        line.SetVertexCount(storedLinePoints.Count); // set the line’s vertex count to how many points we now have, which will be 1 more than it is currently        line.SetPosition(storedPoints.Count-1, newPoint); // add newPoint as the last point on the line (count -1 because the SetPosition is 0-based and Count is 1-based)    } [/code] As you can see, we need to keep our own list of points in order to know how many points there are so we can add a new one. You can similarly remove a point from the line: [code language=”csharp”] void RemoveLastLinePoint() {        storedLinePoints.RemoveAll(storedLinePoints.Count - 1); // remove the last point from the line        line.SetVertexCount(storedLinePoints.Count); // set the line’s vertex count to how many points we now have, which will be 1 fewer than it is currently       } [/code] That method removes the most recently added point from the line.

Weird Tapering

Unfortunately, LineRenderers have weird behaviour when they are made to turn on sharp angles. Due to the way they are rendered you will get the appearance of tapered line segments even when you have set the thickness to be even. There is no way around this; it’s just how it works. You won’t see the problem if you have thin lines or avoid sharp angles. You can mitigate the problem by adding some extra points to your line, especially near the sharp turns.  

That’s It

That’s the basics of Unity’s LineRenderer! Experiment with different settings to get different line looks.