Unity: Android Native Crash – [Solved] MP4 Audio Encoding Problem

I’ve been in Beta Testing for a new game I’m about to release on the Google Play Store (the game is called Endless Elevator). I kept having Native Crashes on specific Android platforms in all my builds in the Pre-Launch Reports. Native Crashes can be terrible to work through if you get unlucky so I was a bit worried and figured I’d just have to leave it like it was and release with errors! But being a bit stubborn I threw a few days into sorting through it and am very glad I did. Working through the problem highlighted some things I didn’t know about Android Video support and was an interesting exercise in troubleshooting. So here is the method I followed and the resolution to the problem.

In each case it was always the armeabi-v7a package that was causing the issues. (I split my build into two APK’s for arm64 and armeabi to make it a smaller installation size – I haven’t gone the android bundle path yet).

These are some of my base Beta builds and in most cases there were 4 errors relating to specific platforms.

The Pre-Launch tests are run on a variety of Android platforms but usually they will include these four below in some form or other and my build kept crashing with a Native Error on each of them.

The usual suspects

When I looked at each of them in turn and played the video of the interactive session the fail point always seemed to be about the time when I had a full screen projected video playing or about to play. The video is used as an introduction and tutorial to the game so it was pretty important for me to get it working.

The drill down screen of the crash report where you can see the video of the session and get access to the logs.

I downloaded all the Logcat’s from the console above and looked for any errors or crash reports.

In each case I found this line (which was a bit of a dead giveaway):

——— beginning of crash

A half dozen lines above the likely culprit was writ large:

07-23 04:00:47.862: W/MediaAnalyticsItem(9345): Unable to record: (codec:0:-1:-11:0:3:android.media.mediacodec.mime=audio/ac3:android.media.mediacodec.mode=audio:android.media.mediacodec.encoder=0:) [forcenew=0]
07-23 04:00:47.890: W/Unity(9345): AndroidVideoMedia: Could not create decoder for mime type audio/ac3.
07-23 04:00:47.890: W/Unity(9345): (Filename: Line: 2177)
07-23 04:00:47.906: I/Robo(9288): No foreign elements detected, falling back to original ScreenState.
07-23 04:00:47.910: I/Robo-HyperMultiGraph(9288): New Screen: Optional.of(ScreenNode {Id=5, PackageName=com.ZuluOneZero.EndlessElevator, ActivityName=Optional.of(com.unity3d.player.UnityPlayerActivity)})
07-23 04:00:47.913: E/Unity(9345): Could not allocate memory: System out of memory!
07-23 04:00:47.913: E/Unity(9345): Trying to allocate: 4294705156B with 16 alignment. MemoryLabel: Audio
07-23 04:00:47.913: E/Unity(9345): Allocation happened at: Line:70 in
07-23 04:00:47.913: E/Unity(9345): Memory overview

A bit of googling about led me to believe that as per the error message above the audio codec used in the video was a problem. The AC3 codec is an Audio format that’s used in my MP4 Video. I’d never given it much thought but this format is not supported across all the Android platforms (one of the problems of Android development is that there is so many different platforms out there).

The Video Editing Software that I normally use is called OpenShotVideo. It’s fantastically good for the price (free) and is easy to use and powerful enough for my meagre needs. Turns out the default audio codec used is AC3 (there is probably a way to modify this with OpenShotVideo but I wasn’t in the mood to troubleshoot someone else’s software). I really hadn’t given the audio codec part of the MP4 a second thought.

This is the Export Panel from OpenShotVideo where I confirmed that the Codec was indeed ac3.

While I was doing all this work and after I worked out that the audio codec in the Video was the problem I had a look at the video settings in Unity. I found that there was already a built in transcoder that I’d never noticed right there in the Unity Video Asset Import screen.

Transcode !

That’s pretty cool! Unity has already solved all my problems before I even knew I had them. So I hit the Transcode tick box and waited for twenty minutes while it went to work transcoding. That wait time should have been a bit of a warning. I did the build and uploaded the new apks to the Google Developer Console but while doing that I found that my build size had jumped almost 17 MB!

This was my size before the transcoding:

And afterwards:

A quick look at the Editor.Log confirmed that the transcoding process had made my lovely low quality 7 MB Movie over 20 MB:

Used Assets and files from the Resources folder, sorted by uncompressed size:
22.1 mb 6.8% Assets/Art/IntroMovePlusFoyerClippedSlowLow.mp4

To fix this I downloaded the HandBrake Open Source Video Transcoder and transcoded my original video asset using the AAC Codec for Audio.

The HandBrake Tool

After importing this into my project and rebuilding again I was left with a similar package size and no Native Crashes. Hooray. I’m going to release this Beta Build to Production soon so getting over this little hurdle feels like a huge V for Victory. Huzzah.

Unity – Unable to update the SDK. Please run the SDK Manager manually.

I had this problem during a build this week and figured I’d better document it 1. In case anyone else needs to do it and 2. So I don’t forget it myself for next time.

I’m running Unity 2019.4.1f1 and doing the final few Beta builds for the game I’m just about to release called Endless Elevator. (If you want a quick peek before it’s released the beta has a few more days to run). I uploaded a new build to the Google Play Developer Console and noticed a new message saying something along the lines that API 20 Support was going to be discontinued soon and to check my API minimum levels. I did this and also noticed that I hadn’t updated my game’s API support for the latest releases (API 29 and 30) .

I tried to update it from within the Player Settings of Unity:

This is where I encountered the problem of not being able to run the SDK update from within Unity (you can see API 29 & 30 are displayed differently)

… and after some time got a pop up message:

“Unable to update the SDK. Please run the SDK Manager manually to make sure you have the latest set of tools and the required platforms installed.”

I had not idea what it meant by “manually” so I went into my local copy of the Android Development Studio and performed a full update of all the APIs’ and Tool packs. This didn’t help. Probably because I’d forgotten that the Unity version I was running had it’s own set of API’s in another location.

This is where I found it: C:\Program Files\Unity\Hub\Editor\2019.4.1f1\ Editor\Data\PlaybackEngines\AndroidPlayer\SDK\tools\bin\

This is how I ran it manually from the Windows Command Prompt (cmd.exe):

“C:\Program Files\Unity\Hub\Editor\2019.4.1f1\Editor\ Data\PlaybackEngines\ AndroidPlayer\SDK\tools\bin\sdkmanager.bat” “platforms;android-29”

and

“C:\Program Files\Unity\Hub\Editor\2019.4.1f1\Editor\ Data\PlaybackEngines\AndroidPlayer\SDK\tools\bin\sdkmanager.bat” “platforms;android-30”

First time I ran this I had to accept the licence agreement (Y|n) from the command prompt and it seems that this was the problem. I’m guessing that the internal Unity update function didn’t allow for the licence prompt and was timing out.

I did some googling around and found a few examples of this issue – one person said they had to create a repositories.cfg file in their C:\<users>\.android folder (I already had one so not sure if this step is required).

Anyway fun days and looking forward to releasing the game later next week.

Endless Elevator – Last Week of Beta Testing

Hi Harmony here,

I’d like to thank the wonderful Beta Testers who have signed up for our Open Beta of Endless Elevator over the last month. I was really surprised how many people responded to our call and very grateful to all those who provided feedback.

The Open Beta is still running for another week so there is still time to try the pre-release game: https://play.google.com/apps/testing/com.ZuluOneZero.EndlessElevator

Then head over to our Beta Landing Page if you want to give us some feedback.

http://www.zuluonezero.net/endless-elevator-beta/

Your feedback helps us make a better game – thank you!

One feature of our Beta Testing was opening multiple channels to provide users to get back to us. Not only did we use the Google Play Beta Feedback and Stars system but we also took feedback on email and through social media. One new thing we did was to incorporate a chat channel on our Beta Landing Page where users could provide anonymous feedback directly on to our web site. I feel that the anonymity of this format was a really important source of quality comments for us.

Our Chat Page

Happy Playing – Harmony Out.

Endless Elevator – Early Access Beta

Endless Elevator went into Beta Testing on May 27, 2020, 8:10 PM.

Finally we made it to public testing! After a few months of keeping myself quiet and a seeming eternity of bug fixes I think I got a minimum viable product fit for your eyes, ears, and phone-ready fingers.

Please head over to our Beta Test Page and try it out. I’d love to get some feedback from other enthusiasts and developers.

Get it Here!

Chat With Us!

We have an anonymous Chat Channel right there on the page that you can trash talk into so go for broke! (You are also allowed to be supportive and kind as well if that is your nature).

🙂

The Beta Page has more information about the game as well links to articles written during development that explore the mechanics of the game.

Unity: Circular Movement with Triangles

My son asked to do some game programming with me last week. I was super excited. We did an eyeball rolling around in a circular motion (see image below). He did everything from working in Unity to making the assets and materials and I was very proud. I helped with the function to make it circle. It got me thinking how to explain circular movement and the use of Pythagorean triangles and cos and sin functions. They are simple maths but kind of hard to explain without a picture so hence this project about making circles with triangles.

Rolling Eyeballs!

The Basic Idea

To simplify I’ll work in 2D so we only got two Axis. X and Y. The Center of our circle will be on the 0 (zero, zero). So we could think of this as a co-ordinate system with two planes. If we were mathematicians we would call this a Cartesian Plane after Rene Descartes but being a Game Developer with Unity I’m going to call it the Scene view in 2D.

Our circle is defined by it’s Radius (ie. the distance from the Center).

On each Update() event our GameObject gets a new X,Y position on the Radius of the circle.

The Angle of Change

To start with we work out what the angle of difference is between this Update and the last one. The time passed during that period is known as the DeltaTime. Our “speed” is how many Radians we are travelling around the circle in that time. A radian is the length of the radius laid around the circumference of the circle. We multiply the Speed (how fast we are ticking through the radians) by the DeltaTime (time passed since last Update) to tell us that angle size.

# angleInRadians += RotateSpeed * Time.deltaTime;

Convert Polar to Cartesian

After working out the angle we have what is called a Polar Coordinate. That is we define our location by how far away it is (the distance – in this case as it’s a circle it’s always the same i.e. the radius), and what the angle (θ) is. Now we need to convert between that definition of a location in the Scene View to another one we can use in the Unity move function.

This is where Pythagoras and right angled triangles comes in – to convert from Polar Coordinates (r,θ) to Cartesian Coordinates (x,y) we use cos and sin :
x = r × cos( θ )
y = r × sin( θ )

In Unity there is already a function that does this:

newPosition = new Vector2(Mathf.Cos(angleInRadians), Mathf.Sin(angleInRadians)) * Radius;

But what does this really mean? Cos and Sin are just numbers. They represent the relationship between two sides of the triangle.

For example cos is the value of the relationship between the side of the triangle that is adjacent to the angle (the side next to the angle) and the hypotenuse (the long side on the other side of the angle). We are going to use cos to find the x value (how far along the horizon it is) in our Vector2 position. The same way we use Sin to find the y position (how far up or down).

In the image below see how there are squares built off each side of the triangle. Pythagorean theory for right angled triangles states that the area/volume of the two squares built of the two smaller sides will be equal to the area/volume of the big square built off the longest (hypotenuse) side of the triangle.

The big blue square has a volume of 1 because the radius of the circle is 1 unit on the Cartesian plane and One Squared is One. The volume of the other two squares (Magenta and Yellow) will always add up to one. Their volumes added together will always equal the volume of the blue square. This is the Pythagorean theory of right angled triangles in action. The length of a side of the Yellow box is the x value and the length of a side on the Magenta box is the y value. That’s our current position in (x, y) format which we can pass to the transform.position function.

The two images below show two Updates() that are reasonably close together so you can see in detail and in “freeze frame” what’s going on between the Updates() with all the variables. You can see the angle go from about 8 degrees to 20 degrees and the changing values for sin and cos which result in changing (x,y) values and volumes of the squares.

One Position on Update()
The next position on Update()

That’s basically it apart from some modifications to the values for being on the negative sides of the circle.

The script attached to the moving object is below but I’ve also put it on github here: https://github.com/zuluonezero/MoveInACircleWithTriangles

I’m finding it deeply satisfying to watch the triangles and squares get used to define a circle going round over and over again.

If this sort of thing floats your boat I’ve done some other posts on making curves using intersecting lines:

http://www.zuluonezero.net/2019/06/04/unity-2d-curves-using-triangles/

Also on using sin to use curves in movement: http://www.zuluonezero.net/2018/06/20/fly-birdy-fly-2d-curved-movement-in-unity/.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
public class CircleMe : MonoBehaviour
{
public float RotateSpeed = 5f;      // How fast we move through the radians
public float Radius = 0.1f;         // How "deep" the circle is
public Vector2 centreOfCircle;      // The Centre of our circle
public float angleInRadians;        // The angle (in radians) between our position between one update and the next
// A radian is the angle created if the length of the radius 
// is laid along the circumference of the circle (about 57.2958 degrees)
public Vector2 newPosition;         // The new position for every new Update event
public Text displayText;
public float angleInDegrees;
private LineRenderer triLine;
private Vector3 centre;
private Vector3 yLoc;
public float angle4Display;
private Vector3 sq1;
private Vector3 sq2;
private Vector3 sq3;
private Vector3 sq4cyan1;
private Vector3 sq4cyan2;
public Vector2 slopecyan;
public Vector2 p1cyan;
public Vector2 p2cyan;
private void Start()
{
centreOfCircle = transform.position;
// (0, 0) but could be anywhere
centre = transform.position;
}
private void Update()
{
angleInRadians += RotateSpeed * Time.deltaTime;
if (angleInRadians > 6.28319f)
{
angleInRadians = (angleInRadians % 6.28319f);
}
// eg.       0 += 5 * 0.25  (answer is 1.25)    // if deltaTime was 0.25 of a second
// and our initial angle was 0 radians. 
// Remember += is short for x = the current value of x plus itself (x = x + x)
// we need to convert the angle and radius into an x, y position
newPosition = new Vector2(Mathf.Cos(angleInRadians), Mathf.Sin(angleInRadians)) * Radius;
//          = new Vector2(opposite/hypotenuse(1.25), adjacent/hypotenuse(1.25)) * Radius;
// (x, y)   =            (0.9997, 0.0218) * 0.1
// (x, y)   =            (0.09997, 0.00218)
transform.position = centreOfCircle + newPosition;   // Adding Vectors
// (0.09997, 0.00218) = (0, 0) + (0.09997, 0.00218)
// this is our starting (x, y) position
// Now do it again for the next Update - the code below has been duplicated for this example
/*
angleInRadians += RotateSpeed * Time.deltaTime;
// eg.       1.25 += 5 * 0.25  (answer is now 1.25 + 1.25 = 2.5)    // if deltaTime was 0.25 of a second 
newPosition = new Vector2(Mathf.Cos(angleInRadians), Mathf.Sin(angleInRadians)) * Radius;
//          = new Vector2(opposite/hypotenuse(2.5), adjacent/hypotenuse(2.5)) * Radius;
// (x, y)   =            (0.99904, 0.0436) * 0.1
// (x, y)   =            (0.09990, 0.00436)
transform.position = centreOfCircle + newPosition;   // Adding Vectors
// (0.09990, 0.00436) = (0, 0) + (0.09990, 0.00436)
*/
if (transform.position.x > 0)
{
yLoc = new Vector3(centre.x + Radius, centre.y, centre.z);
}
else
{
yLoc = new Vector3(centre.x - Radius, centre.y, centre.z);
}
angleInDegrees = angleInRadians * 57.2958f;
}
public void OnDrawGizmos()
{
// Radius
Gizmos.color = Color.blue;
Gizmos.DrawWireSphere(centre, Radius);
// Yellow square
Gizmos.color = Color.yellow;
sq1 = new Vector3((transform.position.x / 2), (transform.position.x / 2f), 0f);
if (transform.position.x > 0)
{
if (transform.position.y > 0)
{
Gizmos.DrawWireCube(new Vector3((transform.position.x / 2), -(transform.position.x / 2f), 0f), new Vector3((transform.position.x), (transform.position.x), (transform.position.x)));
Handles.Label(new Vector3((transform.position.x / 2), -(transform.position.x / 2f), 0f), "Vol: " + (transform.position.x * transform.position.x));
}
else
{
Gizmos.DrawWireCube(sq1, new Vector3((transform.position.x), (transform.position.x), (transform.position.x)));
Handles.Label(sq1, "Vol: " + (transform.position.x * transform.position.x));
}
}
else
{
if (transform.position.y > 0)
{
Gizmos.DrawWireCube(sq1, new Vector3((transform.position.x), (transform.position.x), (transform.position.x)));
Handles.Label(sq1, "Vol: " + (transform.position.x * transform.position.x));
}
else
{
Gizmos.DrawWireCube(new Vector3((transform.position.x / 2), -(transform.position.x / 2f), 0f), new Vector3((transform.position.x), (transform.position.x), (transform.position.x)));
Handles.Label(new Vector3((transform.position.x / 2), -(transform.position.x / 2f), 0f), "Vol: " + (transform.position.x * transform.position.x));
}
}
// Magenta square
Gizmos.color = Color.magenta;
sq2 = new Vector3((transform.position.y / 2), (transform.position.y / 2f), 0f);
if (transform.position.x > 0)
{
if (transform.position.y > 0)
{
Gizmos.DrawWireCube(new Vector3((transform.position.x + transform.position.y / 2), (transform.position.y / 2f), 0f), new Vector3((transform.position.y), (transform.position.y), (transform.position.y)));
Handles.Label(new Vector3((transform.position.x + transform.position.y / 2), (transform.position.y / 2f), 0f), "Vol: " + (transform.position.y * transform.position.y));
}
else
{
Gizmos.DrawWireCube(new Vector3((transform.position.x + Mathf.Abs(transform.position.y) / 2), (transform.position.y / 2f), 0f), new Vector3((transform.position.y), (transform.position.y), (transform.position.y)));
Handles.Label(new Vector3((transform.position.x + Mathf.Abs(transform.position.y) / 2), (transform.position.y / 2f), 0f), "Vol: " + (transform.position.y * transform.position.y));
}
}
else
{
if (transform.position.y > 0)
{
Gizmos.DrawWireCube(new Vector3((transform.position.x - transform.position.y / 2), (transform.position.y / 2f), 0f), new Vector3((transform.position.y), (transform.position.y), (transform.position.y)));
Handles.Label(new Vector3((transform.position.x - transform.position.y / 2), (transform.position.y / 2f), 0f), "Vol: " + (transform.position.y * transform.position.y));
}
else
{
Gizmos.DrawWireCube(new Vector3((transform.position.x + transform.position.y / 2), (transform.position.y / 2f), 0f), new Vector3((transform.position.y), (transform.position.y), (transform.position.y)));
Handles.Label(new Vector3((transform.position.x + transform.position.y / 2), (transform.position.y / 2f), 0f), "Vol: " + (transform.position.y * transform.position.y));
}
}   
// Red Triangle
Gizmos.color = Color.red;
Gizmos.DrawLine(centre, new Vector3(transform.position.x, centre.y, centre.z));
Gizmos.DrawLine(new Vector3(transform.position.x, centre.y, centre.z), transform.position);
Gizmos.DrawLine(transform.position, centre);
if (transform.position.x > 0)
{
if (transform.position.y > 0)
{
Gizmos.DrawLine(new Vector3(transform.position.x - 0.1f, 0f, 0f), new Vector3(transform.position.x - 0.1f, 0.1f, 0f));
Gizmos.DrawLine(new Vector3(transform.position.x - 0.1f, 0.1f, 0f), new Vector3(transform.position.x, 0.1f, 0f));
}
else
{
Gizmos.DrawLine(new Vector3(transform.position.x - 0.1f, 0f, 0f), new Vector3(transform.position.x - 0.1f, -0.1f, 0f));
Gizmos.DrawLine(new Vector3(transform.position.x - 0.1f, -0.1f, 0f), new Vector3(transform.position.x, -0.1f, 0f));
}
}
else
{
if (transform.position.y > 0)
{
Gizmos.DrawLine(new Vector3(transform.position.x + 0.1f, 0f, 0f), new Vector3(transform.position.x + 0.1f, 0.1f, 0f));
Gizmos.DrawLine(new Vector3(transform.position.x + 0.1f, 0.1f, 0f), new Vector3(transform.position.x, 0.1f, 0f));
}
else
{
Gizmos.DrawLine(new Vector3(transform.position.x + 0.1f, 0f, 0f), new Vector3(transform.position.x + 0.1f, -0.1f, 0f));
Gizmos.DrawLine(new Vector3(transform.position.x + 0.1f, -0.1f, 0f), new Vector3(transform.position.x, -0.1f, 0f));
}
}
// Cyan Square
Gizmos.color = Color.cyan;
if ((transform.position.x > 0 && transform.position.y > 0) || (transform.position.x < 0 && transform.position.y < 0))
{
slopecyan = new Vector2(transform.position.x, transform.position.y);
p1cyan = new Vector2((transform.position.x - slopecyan.y), (transform.position.y + slopecyan.x));
p2cyan = new Vector2((centre.x - slopecyan.y), (centre.y + slopecyan.x));
Gizmos.DrawLine(transform.position, p1cyan);
Gizmos.DrawLine(centre, p2cyan);
Gizmos.DrawLine(p1cyan, p2cyan);
}
else
{
slopecyan = new Vector2(transform.position.x, transform.position.y);
p1cyan = new Vector2((transform.position.x + slopecyan.y), (transform.position.y - slopecyan.x));
p2cyan = new Vector2((centre.x + slopecyan.y), (centre.y - slopecyan.x));
Gizmos.DrawLine(transform.position, p1cyan);
Gizmos.DrawLine(centre, p2cyan);
Gizmos.DrawLine(p1cyan, p2cyan);
}
Vector3 lbl = new Vector3((p1cyan.x / 2), (p1cyan.y / 2), 0f);
Handles.Label((lbl), "Vol: " + (Radius * Radius));
// Angle Marker
if (transform.position.y > 0)
{
if (transform.position.x > 0)
{
angle4Display = angleInDegrees;
Handles.DrawSolidArc(centre, Vector3.forward, yLoc, angle4Display, 0.25f);
}
else
{
angle4Display = -(angleInDegrees - 180f);
Handles.DrawSolidArc(centre, Vector3.forward, transform.position, angle4Display, 0.25f);
}
}
else
{
if (transform.position.x < 0)
{
angle4Display = (angleInDegrees - 180f);
Handles.DrawSolidArc(centre, Vector3.forward, yLoc, angle4Display, 0.25f);
}
else
{
angle4Display = -(angleInDegrees - 360f);
Handles.DrawSolidArc(centre, Vector3.forward, transform.position, angle4Display, 0.25f);
}
}
// Labels
Handles.color = Color.blue;
Handles.Label(centreOfCircle, angle4Display.ToString());
Handles.color = Color.white;
Handles.Label(transform.position, "X: " + System.Math.Round(transform.position.x, 2) + " Y: " + System.Math.Round(transform.position.y, 2));
// sin opposite/hypotenuse
Handles.Label(new Vector3(1.2f, 0.8f, 0f), "sin opposite/hypotenuse");
Handles.Label(new Vector3(1.3f, 0.7f, 0f), "sin: " + Vector3.Distance(centre, (new Vector3(transform.position.y, 0f, 0f))) / Vector3.Distance(centre, (transform.position)) );
// cos adjacient/hypotenuse
Handles.Label(new Vector3(1.2f, 0.6f, 0f), "cos adjacient/hypotenuse");
Handles.Label(new Vector3(1.3f, 0.5f, 0f), "cos: " + Vector3.Distance(centre, (new Vector3(transform.position.x, 0f, 0f))) / Vector3.Distance(centre, (transform.position)));
// tan opposite/adjacient
Handles.Label(new Vector3(1.2f, 0.4f, 0f), "tan opposite/adjacient");
Handles.Label(new Vector3(1.3f, 0.3f, 0f), "tan: " + Vector3.Distance(centre, (new Vector3(transform.position.y, 0f, 0f))) / Vector3.Distance(centre, (new Vector3(transform.position.x, 0f, 0f))));
Handles.Label(new Vector3(1f, -0.3f, 0f), "Next Position on Update()");
Handles.Label(new Vector3(1f, -0.4f, 0f), "newPosition = new Vector2(Mathf.Cos(angleInRadians), Mathf.Sin(angleInRadians)) * Radius");
Handles.Label(new Vector3(1f, -0.5f, 0f), "= new Vector2(opposite/hypotenuse(angleInRadians), adjacent/hypotenuse(angleInRadians)) * Radius");
Handles.Label(new Vector3(1f, -0.6f, 0f), "" + Mathf.Cos(angleInRadians) + ", " + Mathf.Sin(angleInRadians) + " * "  + Radius + " = " + newPosition);
}
}
/*
Using Cartesian Coordinates we mark a point by how far along (x) and how far up (y) it is:
Using Polar Coordinates we mark a point by how far away (magnitude or in this case as it's a circle always the radius is the same), and what angle (θ) it is:
To convert from Polar Coordinates (r,θ) to Cartesian Coordinates (x,y) :
x = r × cos( θ )
y = r × sin( θ )
Example: add the vectors a = (8,13) and b = (26,7)
c=a+b
c= (8,13) + (26,7) = (8+26,13+7) = (34,20)
*/

Unity Script: Find all Assets and Prefabs with a given Component by Type

Hi Xander here…

The current game in development is Endless Elevator. During the development cycle we have used a bunch of placeholder audio files and Audio.Play() functions. This is to get some quick auditory feedback from the game during testing phases. It’s much more fun to hear a gun go off and have the bullet zing past to impact on the wall and make a satisfying “Crack-Bang! Zoom! Whhhumppp!” noise than hearing nothing at all.

But now we are ramping up development of the noises and soundtracks in the game and while it’s not my favourite part (and not my skill set) I have enjoyed watching The Baron get all Foley artist. I recently witnessed the birth of a gun noise by repeatedly slamming a dryer door with a bunch of copper wire and a microphone taped to the inside. Game development is really fun and you get to do a shocking amount of creative weirdness. I digress.

Since we now have to start replacing all the temporary raw audio calls with some proper artistry, and serious sound work I had to find all those existing audio components out there in the project and add them to Unity Mixer channels. At the moment Endless Elevator is not huge but it’s not small either. There are are maybe a hundred prefabs sorted into four sub-folders in the Project explorer and I didn’t really want to go searching through them all and open up each one looking for Audio Sources. (Does anyone else find the new Prefab workflow of having to open up a prefab for editing a few clicks too many?)

So this script is my solution for finding all the Audio Sources in the project.

(I do like to make a Zulu heading in the Editor Window to run scripts from)

Finding Audio Sources in the Current Scene

Firstly I wanted to know how many Assets in the current scene had Audio Components. This wasn’t too hard as the game is mostly procedural (and endless…) so there isn’t too many objects to a scene in the Edior.

I’ll put the full script at the end but this is the code snippet to do that:

Debug.Log("Finding all Assets in the Current Scene that have an Audio Component...");
AudioSource[] myAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
Debug.Log("Found " + myAudioSources.Length + " objects with an AudioSource attached");
foreach (AudioSource item in myAudioSources)
{
Debug.Log(item.gameObject.name);
}

The main function here is the FindObjectsOfType() which I rarely have cause to use but is perfect for this sort of thing. The output in the Console is shown below…

I also found a really useful tool on the Asset Store that looked interesting for those who need a bit more power for doing this: Asset Usage Detector. It looks pretty full featured and is free! Shout out and respect to the dev Süleyman Yasir Kula who has a whole heap of good looking tools up there.

Finding Audio Sources in Prefabs

The next bit took a longer to write. I had never really delved into the Asset Database API and I found it really interesting and a bit of an eye-opener. Which is why I decided to write it up in this post.

This is how I found all the Prefabs in my project with an Audio Component:

Debug.Log("Finding all Prefabs that have an Audio Component...");
string[] guids = AssetDatabase.FindAssets("t:Object", new[] { "Assets/Prefabs" });
foreach (string guid in guids)
{
//Debug.Log(AssetDatabase.GUIDToAssetPath(guid));
string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);
//Debug.Log("printing myObs now...");
foreach (Object thisObject in myObjs)
{
//Debug.Log(thisObject.name);
//Debug.Log(thisObject.GetType().Name); 
string myType = thisObject.GetType().Name;
if (myType == "AudioSource")
{
Debug.Log("Audio Source Found in...  " + thisObject.name + " at " + myObjectPath);
}
}
}

The first step was this line:

string[] guids = AssetDatabase.FindAssets(“t:Object”, new[] { “Assets/Prefabs” });

This makes an array of all the Objects under my Prefabs folder in the Project Hierarchy. You can replace t:Objects with any other Type but I was playing around with what I could find using this method so left it in there in case I wanted to look at other things. It’s also important to note that as the Audio Component is attached to a Game Object as a Component, and is not an Object in it’s own right, we have to reference the Object first so we can start to access the added components.

Next we get a reference to the path of the Object and use LoadAllAssetsAtPath to make an array of the “Assets” that we can start to interrogate. These are the active lines:

string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);

Next we run a foreach loop through those Objects and test for the AudioSource name in the component. The output in the console looks like this:

The Whole Script…

I’ll put the whole script below:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
public class FindAssets : MonoBehaviour
{
// Find all object that have an Audio component
[MenuItem("Zulu/FindAssets Audio")]
static void FindAudio()
{
Debug.Log("Find Assets Script started...");
// Find all Prefabs that have an Audio component under my Prefabs folder
Debug.Log("Finding all Prefabs that have an Audio Component...");
string[] guids = AssetDatabase.FindAssets("t:Object", new[] { "Assets/Prefabs" });
foreach (string guid in guids)
{
//Debug.Log(AssetDatabase.GUIDToAssetPath(guid));
string myObjectPath = AssetDatabase.GUIDToAssetPath(guid);
Object[] myObjs = AssetDatabase.LoadAllAssetsAtPath(myObjectPath);
//Debug.Log("printing myObs now...");
foreach (Object thisObject in myObjs)
{
//Debug.Log(thisObject.name);
//Debug.Log(thisObject.GetType().Name); 
string myType = thisObject.GetType().Name;
if (myType == "AudioSource")
{
Debug.Log("Audio Source Found in...  " + thisObject.name + " at " + myObjectPath);
}
}
}
// Find all object that have an Audio component in the current Scene
Debug.Log("Finding all Assets in the Current Scene that have an Audio Component...");
AudioSource[] myAudioSources = FindObjectsOfType(typeof(AudioSource)) as AudioSource[];
Debug.Log("Found " + myAudioSources.Length + " objects with an AudioSource attached");
foreach (AudioSource item in myAudioSources)
{
Debug.Log(item.gameObject.name);
}
}
}

I should finish off that this is an Editor only tool and will not impact the performance of your game or blow out your memory by loading in all those assets (if you got heaps). Also make sure you put this script in a folder called Editor otherwise you build will fail 🙂

Enjoy and happy coding… Xander.

Endless Elevator Weapons

The last few weeks I’ve been working up a couple of new weapons for the main protagonist in our upcoming game Endless Elevator.

This is a bit of a “Screen Shot Saturday” demo.

The first bad guy is dispatched with the standard issue firearm (with the big red bullets).

The next two are fried by the new Electricity Gun.

The last huddle are amiably frozen with the non-lethal Freeze Ray or Ice Gun.

I’m going to release a beta/demo for general testing and fun pretty soon so I’ll post again when it’s ready.

Unity Code Review and Style Guide

Hi Trixie here. It’s Code Review time! Yay. Time to clean up that code and start really looking at all the crap work you’ve done over the last months and clean that sh!t up!

I’ll post our in-house Style Guide (which of course goes out the window when you are coding in anger) at the bottom of the post. Hopefully someone else will follow it or find it useful.

This is how the code review works:

  • Make a list of all your scripts and the game objects they are attached to.
  • Go through all the variables/functions/iterators and make them follow the standard in the Style Guide (which includes making logical names sensible to humans).
  • Check all your Public references and make Private if you are really not using them.
  • Trawl the console output and clean up the extraneous debugging guff.
  • Start grouping your code into functions that do a similar thing and try and make them standardised.
  • If you are lucky you will find some optimisations in there as well to make your game run faster, better, more efficient, lighter.

Then at least it will be another few months before you muck it up again.

I know there are automated tools to do some of this work but I prefer to work though my own methods. I like to have complete control over the process. My favourite tool for analysis is the Unix Command line (I know weird right?). My workstation is Windows 10 but I have a Cygwin like utility called MobaXterm installed which allows me to interrogate the file system like a Unix machine and use grep and other commands on all the files that make up my scripts.

Basically I want to build a big spreadsheet of information that lists all my scripts and the Game Objects they attach to and the Public interfaces and variables etc.

This is one that I started for Endless Elevator:

Then I start extracting Game Objects and Code loops using the Unix Command Line so I can start to build a picture of what’s going on.

One of the outcomes of this process is that I want to be left with a map of how stuff works that I can connect the dots on in the future. It’s kind of like a Design Document in reverse.

Here are a few examples of the commands I’m using and how the information is extracted:

# grep bool *.cs # Getting out all my bools – I tend to use true or false tests a lot to explicitly define functions and events.

As you can see above the bool names are mostly descriptive and the variable name is mostly in camelCase. Those few like swingme will get updated to swingMe and the overly generic “yes” and “yesNow” (what was I thinking!) will be made more descriptive of what we are really agreeing to in that code.

This command looks at all the sort of functions I am using and where. It’s nice to know which one’s don’t have an Update() function and where all my Collisions and Triggers are.

# egrep “{|}” AI.cs # I use something like this to collect an idea of the complexity of my loops and functions.

# egrep “{|}(|)|if|for|else” AI.cs # This is my favourite type of command. Like the command above I use it for working out the structure of a script. This is way easier than scrolling through lines and lines of code and comment and makes it really easy to spot areas where you have gone loopy crazy pants.

# grep GameObject *.cs # This one makes a good list of all the scripts that I reference another Game Object in. It helps build a visual map of what dependencies there are between objects.

# grep script *.cs # This one does a similar thing in that it grabs all the times that I am calling something from within another script attached to another Game Object..

The command line is also a nice quick way to check how many lines of code you have written.

There are some good Style Guides out there.

I like this one for it’s organised folder structure and naming convention for files: https://github.com/stillwwater/UnityStyleGuide

I like the Microsoft C# one for layout and block style: https://docs.microsoft.com/en-us/dotnet/csharp/programming-guide/inside-a-program/coding-conventions

I like this for it’s use of camelCase and Capitals and it’s preferred block style: https://github.com/raywenderlich/c-sharp-style-guide

As a basic guide though I always try and mimic the Unity API manual. For example this page for OnCollisionEnter:

// A grenade
// - instantiates an explosion Prefab when hitting a surface
// - then destroys itself
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
public Transform explosionPrefab;
void OnCollisionEnter(Collision collision)
{
ContactPoint contact = collision.contacts[0];
Quaternion rotation = Quaternion.FromToRotation(Vector3.up, contact.normal);
Vector3 position = contact.point;
Instantiate(explosionPrefab, position, rotation);
Destroy(gameObject);
}
}

The comments are appropriate. The Class name uses a Capital for each word. The curly brackets are on a new line and indented block space. Varables are in camelCase.

Here is our minimal Style Guide. This is the basics of how we roll things:

Thanks for reading. See you all in the New Year… Trixie.

Unity: How to Create a Cut-Scene with Cinemachine and Unity Recorder

Hi Xander here,

For Endless Elevator we wanted to do an Introduction Scene for the game. The gameplay, as the name suggests, consists of climbing endless elevators and escalators. The player navigates floor after floor in the bad guys luxury hotel and tries to climb as high as possible while defeating the bad guys. It’s a 2.5D top down scroll mechanism and clipped into the limits of the building. Just dumping the player into the start of the game in the levels of the building felt a little weird as there was no context to where you were in the story. Hence the need for an opening shot to set the scene and to literally drop the player into the game.

Our hero flies into the enemies’ oasis headquarters in a helicopter and storms into the foyer of their luxury hotel. We mocked up a scene and a helicopter in Blender and imported the assets into the main foyer scene of the game. I hadn’t used Unity’s Cinemachine before but wanted to try it out. Previously, in other projects, we had captured gameplay for cut-scenes using external software and video editing suites which was OK but the experience with Cinemachine and Unity Recorder was way smoother. It was much easier to work with and much better quality avi files. Plus we didn’t have to do custom scripts for switching cameras and panning. It was so easy it kind of made me excited about movie making with Unity but you know I don’t need another distraction.

To start working with Cinemachine and Unity Recorder you can download them using the Package Manager. Unity Recorder has only recently been added (it’s still also on the Asset Store) so you need to enable the “Preview Packages” selection from the Advanced menu in the Package Manager.

Cinemachine in the Package Manager

Have a look at the Unity Manual and tutorials for more info about Cinemachine and Unity Recorder.

Below is a screen shot of my scene in Unity. You can see the main building in green and the surrounding buildings and water in the bad guys oasis HQ. The helicopter is just visible down where the camera sight lines join and on the left in the Hierarchy you can see my Timeline component and my two vcams (Virtual Cameras).

The Timeline is where all the magic happens and was very easy to set up.

First we did a few animations on the helicopter to fly it in to the building and make the rotor spin. Then we added an animation to move the character from the helicopter into the building (which looks terrible but remember this is a quick mock up)

The Helicopter Animation

We dragged this animation into a new Animation track on the Timeline object (right click and Add Animation Track). Then we created two Virtual Cameras in the scene. One Camera (vCam1) was set using the properties in the Inspector to automatically Loot At and Follow the helicopter. This means that where ever we flew the Helicopter the camera would follow it round from behind at a set distance and keep it in the frame automatically. This was really fun when we had it under manual control for testing and worked well when under the control of the Animator. We used a preset for a bit of camera jitter and shake to mimic a real camera man in a second helicopter.

The second Camera (vCam2) was stationary at the building site but set to Follow (ie. Look At) the Main Character. We timed the cut from one camera to the other so that once the helicopter landed it would pass control to the second camera and seamlessly start focusing on the Player. This was so easy it was ridiculous. The Camera objects were added to the Timeline and the split where we cut from one camera to the next is clearly visible in the screenshot below (two triangles). The first time I ran it and that view cut automatically from one vcam to the other gave me an enormous sense of satisfaction like I’d just been named a modern day Hitchcock.

The Timeline Editor Window

To record what we had done as an AVI we opened the Recorder Window:

Opening the Recorder Window.

We used the default settings and triggered the Start of the Recording with the start of the animation by having it in the Timeline. The Capture target was the Game View (you can also get the other elements of the Editor if you need it). The Output Resolution is interesting as you can use the Size of the Editor Game window on your screen or set it to standard default movie formats.

The Recorder Window

That’s about it. We hit Play in the Editor and the Timeline starts the Recording of the AVI and synchronises the Animations and the Camera movement automatically. Once we are done we are left with a good quality moving image of our game screen that we will use as the cut-scene to drop the player into the start of our game. Obviously what we got here is just a “screen test” but I was really happy with what we could achieve in just a few hours and with so little complexity.

Xander out…

Unity SVG Screen Test

I been toying with an idea for a new text adventure game. I wanted to finally start using the framework we built earlier in the year (See this post and check out the code for yourself). I also wanted to get into the new-ish support for SVG graphics in Unity. I love Vector Graphics and I think this project is going to be a great way to use their simple clean aesthetic.

I did a “screen test” of a very quick vector image using InkScape. (I have a deep respect for the Linux and Open Source community and want to thank them now for such awesome software).

To get started with SVG files in Unity 2018.x you need to import the package using the Package Manager (it’s called Vector Graphics). This allows you to pick up SVG files when you import a new asset. You can also drag and drop from your explorer into your project hierarchy.

The SVG image shown below is the three receding black squares. The SVG sprite is on a separate canvas to my text (and sorted behind it). I’ve added a couple of raw images in the same color as my background and an animator component to move them around to give the “drawing” effect.

I have to say I’m pretty happy with the resulting mock up and think this will be the way forward in developing this project. Resizing the screen view into different formats works as expected with the Vector image staying crisp (which is more than you can say for the poor four color buttons below it that use a scaled sprite – very fuzzy).

Zulu out.