Sign in to follow this  
clyde

Unity: What I needed to know.

Recommended Posts

As I'm sifting through the massive quantity of available resources in order to figure stuff out, sometimes I find something that tells me exactly what I needed to know. It is often not in the first place I look. I figure it may be interesting and helpful to see other people's examples of these decipherments.

Here we have an example of what the fuck Time.deltaTime actually does.
 

Share this post


Link to post
Share on other sites

That was incredibly nice to read. I've been playing around with Unity and I see Time.deltaTime used all the time, and the documentation is kind of... technical (I know thats the point, but when you just want to know what it *is*, it can be confusing.)

Thank you for that post and this thread, if I find anything that also fits this thread I'll be sure to post it!

Share this post


Link to post
Share on other sites

I wrote my very first Coroutine the other day. Here's a handy explanation of the advantages of Coroutines and the basics of using them. That site is also an excellent new, little site with a couple of tips and tricks (and some handy scripts) for Unity.

 

I'd definitely recommend reading a bit of that so you can go "Oh, this thing I want to do.. that might be easiest by using Coroutines!" later on..

Share this post


Link to post
Share on other sites

Coroutines, you can also use:

 

yield return new WaitForSeconds(float time);

where you would replace [float time] with the amount of seconds you wish to wait, e.g.

yield return new WaitForSeconds(5.5f); //waits five and a half seconds

A caution though, in experience there is a some unreliability with WaitForSeconds and as such any small and/or critical timers should be done in Update and use Time.deltaTime.

Share this post


Link to post
Share on other sites

Can't you just use Time.deltaTime inside a Coroutine, yield return null it to let it run each frame until the timer is up? I used that WaitForSeconds method. Brilliant stuff, although in my case I just needed a rough time before respawning the player, nothing accuracy-critical!

Share this post


Link to post
Share on other sites

One thing I wish I had known when I started using Unity was that you can make GameObjects that don't have a visual representation more visible in the scene view by changing the icon.

 

Just click on the little arrow left of the GameObject's name:

 

4yAL7Vb.png

 

Select one of the other icons, and it'll look like this in the scene:

OyEEa6U.png

 

Once I figured this out I started using GameObjects with only a transform any time I needed to do something positional. A lot easier than modifying the position with code and being unable to see exactly where your new position is.

Share this post


Link to post
Share on other sites

OZ1Mgxf.gif

 

View private variables in the inspector!

or tag them with [serializeField]

 

eg:

[serializeField]
 private UILabel percentCompleteLabel;

Share this post


Link to post
Share on other sites

Variable Scope

I had missed this. Variables are only accessible within the blocks where they are created. So if I want to use the variable "speed" in the Update method, I have to either create the variable in the class block (not within one of the method blocks) or in the Update method block. Creating the variable in the Start method block and then trying to call it in the Update method block will result in an error.

Share this post


Link to post
Share on other sites

You can make the editor require other components when you attach a script in the following way 

 

[RequireComponent(typeof(PutTypeHere))]

 

Put that right under your includes. I've commonly seen it to add things like ridgidbodies when a script wants to use physics. It's actually pretty useful if you start using classes that interdepend on one another. This way when a script is placed on an object the required components are added as well. 

 

Probably the most useful thing I could show people about Unity is the "singleton" design pattern. I don't know if it's utility is immediately evident but one day (like me) you'll find a place where it simplifies like in an amazing way.

 

So you may notice that all unity classes inherit from Monobehavior. If you want your script to participate in the scene this is necessary. Unfortunately this means it's a PAIN to have a static class that also participates in the scene. You certainly could properly scope all your variables as static (the ones you wanted to have as static). But really what fun is that when you can do something fast, easy, and dangerous like this!.

 

Basically this gives you a static reference to all public members of the class you create the singleton in. This is real useful in various manager scripts that you want to exist in an instance in the scene but also want to be able to access via static ref (to not have to always get components). You should be careful because you are copying data in memory so this can hurt your performance if you abuse it. However it can make many things MUCH simpler. This is only really useful in an instance where you would normally make an entire class static (meaning that only one object instances of the class will ever exist in the environment). In the case above all classes could access the bullShit property as SomeClass.instance.bullShit. 

 

I'll also add that coroutines can actually yield other coroutines. I find this to be EXTREMELY useful. You literally just 

 

yield return StartCoroutine(secondRoutine);

 

This will halt the first coroutine until the second coroutine finishes execution.You can go real deep with this kind of thing. I think it's extremely useful anytime you're enforcing a ridgid order of events. In this case you can simply start a "CoRoutine chain" leading through the events.

 

I've actually been working with Unity for about 3 years now and would be more then happy to try and answer any questions anyone might have. 

Share this post


Link to post
Share on other sites

OZ1Mgxf.gif

 

View private variables in the inspector!

 

I am ridiculously disappointed in myself that I didn't learn about this sooner.   I was just making variables Public so I could spy on them, and 112% of the time I forgot to go back and clean them up.

Share this post


Link to post
Share on other sites

I'll also add that coroutines can actually yield other coroutines. I find this to be EXTREMELY useful. You literally just 

 

yield return StartCoroutine(secondRoutine);

 

This will halt the first coroutine until the second coroutine finishes execution.You can go real deep with this kind of thing. I think it's extremely useful anytime you're enforcing a ridgid order of events. In this case you can simply start a "CoRoutine chain" leading through the events.

 

This is actually so useful to what I'm working on right now I'm going to do a huge code refactor. So that's basically a simultaneous thank you and damn you for making me refactor, but mostly thanks.

Share this post


Link to post
Share on other sites

Something I was told recently that really shocked me is that GameObject.rigidbody and .transform are actually GetComponent<T>() calls, so if you use either in Update() or FixedUpdate(), it could cause performance issues. The solution seems to be to store them in member variables if you'll need them frequently. I'm not really sure what the best solution for this is, I've just been assigning a thisTransform and thisRigidbody member in Awake() and wouldn't be surprised if there's a more elegant solution.

 

I was initially told that .gameObject behaved this way too, but this UnityAnswer seems to disagree and the logic seems sound to me.

Share this post


Link to post
Share on other sites

Judging from the example on that page, maybe they expected people to primarily use the Random Int function to select a random element from a list / array, which are zero-indexed (and so for a list of 5 things, you'd want to to pick a number between 0 and 4).

 

Seems like the inconsistency would create more problems than it solves, though. ¯\_(ツ)_/¯

Share this post


Link to post
Share on other sites

Judging from the example on that page, maybe they expected people to primarily use the Random Int function to select a random element from a list / array, which are zero-indexed (and so for a list of 5 things, you'd want to to pick a number between 0 and 4).

 

Seems like the inconsistency would create more problems than it solves, though. ¯\_(ツ)_/¯

 

I think the inconsistency is there because it is more intuitive to the typical uses you describe. Seeing code snippets like:

float fromZeroToOne = Random.Range(0.0f,1.0f);
int arrayElement = Random.Range(0,array.Length);

You can pretty quickly infer what they do without looking at the docs. Of course, I could change the first line to:

float fromZeroToOne = Random.value;

and achieve the same results.

Share this post


Link to post
Share on other sites

Agreed, but the tradeoff is a bit of weirdness in situations like calculating a 1d6 roll by specifying a range of [1,7)  :P

Share this post


Link to post
Share on other sites

Hahaha thanks for the thread, I am such a dope with code.

 

Someone pointed out to me yesterday that I keep describing features in terms of how many FRAMES an action takes instead of cycles and updates and miliseconds. This is because I mainly come from animation, and I learned to code working on Flash games. Apparently that language isn't useful to anyone!

Share this post


Link to post
Share on other sites

DeltaTime took me the longest time to figure out. I still have to think really hard when I explain it to someone but it's basically like this:

 

Take one second of gameplay from your game and imagine it as a white picket fence (or a timeline in Flash, if you will).

Each fencepost represents a frame, a still image, so in a regular game your fence would have 30 posts. (30 fps)

 

If your computer is slower, there are less posts in your fence. This makes the space between the posts bigger. That space between the posts is the deltaTime.

 

So if you want your guy to move from A to B, and it takes 30 frames to get to B, players on 30fps will get there in one second, and players on 15fps get there in two seconds. Obviously unacceptable, especially in a multiplayer game.

 

So if you multiply the movement speed with the gap between the frames (the deltaTime), you ensure that every player always reaches point B in one second, regardless of how fast their computer is.

 

Because when you run at a lower fps your deltaTime is LARGER, because the GAP between frames is larger, and so each movement gets multiplied with a LARGER number, which means your dude will move FASTER so he can keep up with the intended pace of the game.

Share this post


Link to post
Share on other sites

Something I was told recently that really shocked me is that GameObject.rigidbody and .transform are actually GetComponent<T>() calls, so if you use either in Update() or FixedUpdate(), it could cause performance issues. The solution seems to be to store them in member variables if you'll need them frequently. I'm not really sure what the best solution for this is, I've just been assigning a thisTransform and thisRigidbody member in Awake() and wouldn't be surprised if there's a more elegant solution.

 

I was initially told that .gameObject behaved this way too, but this UnityAnswer seems to disagree and the logic seems sound to me.

 

I'm having having a hard time understanding what the remedy for this type of thing is. 

 

If I want to change the color of an object a lot, is this the optimal way to do it? Is there any disadvantage caching all the components that you will be changing for every object. Should I be doing this for rigidbody components?

using UnityEngine;
using System.Collections;

public class SelectSquare : MonoBehaviour {

	public Color blankColor;
	public Color selectedColor;
	Renderer cubeRenderer;

	bool selected;


	void Start () {
		cubeRenderer = GetComponent<Renderer> ();
	}

	void OnMouseDown(){
		SelectCube ();
	}

	void SelectCube(){
		selected = !selected;
		if (selected) {
			cubeRenderer.material.color = selectedColor;
		} else {
			cubeRenderer.material.color=blankColor;
		}
	}
}

 

Also, should I cache public static variables from another script as local variables if many scripts are accessing it in the Update()? I'm using a public static variable as a clock that determines what step my musical sequencer should be on.

Share this post


Link to post
Share on other sites

Random.Range includes the min, but does not include the max when you use ints for the min and max. This is different from using floats for the min and max in which case both are included. What a strange thing to do. Why would you do that? 

http://docs.unity3d.com/Documentation/ScriptReference/Random.Range.html

 

This could be for a number of reasons, and believe it or not it actually works in your favor in some cases.  For example, if you are looking for a random element in a list or array, you can call Random.Range(0, List.count) to get the index, since the highest available index in a list or array is actually one less than its count/length properties respectively.  It doesn't make sense at first, but remember collections are zero based in C#.  This means the first element in an array/list is at index 0, as opposed to index 1.

Share this post


Link to post
Share on other sites

I'm having having a hard time understanding what the remedy for this type of thing is. 

 

If I want to change the color of an object a lot, is this the optimal way to do it? Is there any disadvantage caching all the components that you will be changing for every object. Should I be doing this for rigidbody components?

 

Caching component references is actually a good idea in most cases, as mentioned above the Unity supplied properties are just GetComponent calls, which essentially work the same way every time but require a few extra instructions to be fired.  In terms of the color swapping, the method you have will work  just fine.  One thing to note is that any time you reference a renderer's material's property (for any reason) it creates a new instance of the material on the stack.  I'm not sure how familiar you are with instancing, but here goes with a quick explanation. Instancing is a process that allows for multiple objects to reference the same model, material, etc.  This way you only have to store the model/material/whatever in memory once then copy its values as necessary.  By referencing any property on a material, this instancing is broken and a new version of that material is created in the program's memory.  What that means is that if you don't reference the material's properties for any reason there will only ever be 1 version of that material in memory throughout the entire program, however if you do reference one of those properties a new version of that material will be created for each object that process is called on.  So if the script you posted is added to 5 gameobjects, it will create 5 new instances of that material.

 

This probably isn't a big deal at the moment, but its something I've had to be aware of recently since the game I'm working on has over 10,000 frames of hand drawn sprites (tons of texture memory).  If you want the most memory efficient way of doing this, just store a reference to both a red material and a blue material, and swap them as necessary.  In the end either way works just fine, but one has some memory considerations to go along with it.  Again, this probably isn't something you need to be concerned with at the moment.

 

 

Also, should I cache public static variables from another script as local variables if many scripts are accessing it in the Update()? I'm using a public static variable as a clock that determines what step my musical sequencer should be on.

 

With static variables you shouldn't need to cache references, just reference the class, then the variable.  In most cases just storing a reference to the component containing the variable is enough for member variables.

Share this post


Link to post
Share on other sites

I made a web-player build of the my sequencer, and OnMouseDown() was doing nothing. This was odd since it worked fine in Unity and in PC-builds. After some experimentation, I got OnMouseDown() to work fine when I checked the "is trigger" box on the collider. Not sure if I should report it as a bug or if this is just an example of me not understanding something I should understand.

Share this post


Link to post
Share on other sites

Weird things like that can happen when you've got multiple colliders stacked, maybe?

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this