Random obstacle size, direction, and speed
Tutorial
·
Beginner
·
+10XP
·
45 mins
·
(450)
Unity Technologies

In this tutorial, you’ll write your first Unity script to control how each obstacle behaves. By assigning random properties — like size, direction, and speed — you’ll make your game world feel unpredictable and alive. Along the way, you’ll learn key C# scripting concepts, how to edit prefabs directly, and how to test and tune behaviors in real time.
Languages available:
1. Overview
In this tutorial, you’ll write a simple script that gives each obstacle a random size, direction, and speed. You’ll learn the basics of Unity scripting — including how to use variables, random number generation, vector math, and more — to make your game world feel dynamic and unpredictable.
2. A note about learning to code
If you’ve never done any programming before, here’s something important to keep in mind: coding can feel confusing at first — and that’s completely normal. It might feel like everything is happening in another language. That’s because, in many ways, it is. Programming is a new way of thinking, and it takes time to get used to the words, structure, and logic behind it.
Don’t expect to understand everything right away. Instead, think of these tutorials as an introduction to key ideas, or like planting a seed. The goal isn’t to memorize or totally understand it immediately. Instead, the goal is to start recognizing patterns that will make more sense to you each time you see them.
Just like learning to read or learning the controls in a new game, learning to code takes practice and repetition. You’re not falling behind, you’re just beginning.
3. Create and attach a new script
So far, you’ve added built-in components to your GameObjects — like the Rigidbody 2D and collider components — which were created by Unity. These components gave your GameObbjects physics and collision behavior without needing to write any code.
Now, you’re going to create your own component: a custom script that controls how each obstacle behaves when the game starts. A script is like a set of instructions you give to a GameObject — telling it how to behave when the game runs. The script you’re going to create will change the size, direction, speed, and spin of each obstacle.
Scripts in Unity are written in C#, a popular programming language used for games, apps, and more.
You’ll create the script, name it, and attach it to your Obstacle prefab, so every copy of that prefab uses the same behavior.
1. Create a new Scripts folder:
- In the Project window, right-click the Assets folder and select Create > Folder.
- Name the folder “Scripts”.
2. Create a new C# script:
- Right-click in the Scripts folder and select Create > MonoBehaviour Script.
- Name the script “Obstacle”.
Note: MonoBehaviour is the base class that all Unity scripts inherit from — it gives your script access to Unity’s built-in features like physics and lifecycle methods. Don’t worry about fully understanding it yet — you’ll get more comfortable with it over time.
Important: Unity requires that the script name exactly matches the class name inside it. If the names don’t match, you’ll get an error. If you make a mistake on its spelling, delete the script and create it again with the correct name.
3. Attach the script to the prefab:
- In the Project window, select the Obstacle prefab.
- In the Inspector window, select Add Component, then search for and add your newly-created Obstacle script component.
4. Confirm the script is attached:
- The Obstacle script will now appear in the Obstacle prefab’s Inspector window.
- If you select any of the Obstacle GameObjects in the scene, those instances of the prefab will now also have the Obstacle script component attached.
- Any changes you make in the script will automatically apply to all prefab instances.
You’ve now created your first custom component — one you’ll fully control with your own code.
4. Understand the script structure
Before you start writing code, it’s helpful to understand the structure of a basic Unity script. When you double-click your script file, Unity will open it in your code editor (like Visual Studio or VS Code).
The default script comes with two important methods: Start() and Update(). These are called lifecycle methods, and Unity calls them automatically at specific times during gameplay.

Tip: If nothing happens or you see an error, you might need to install or set up a code editor. Follow these instructions on how to set up your IDE integration with Unity or check out the Unity manual page on Visual Studio C# integration.
2. Understand the structure:
- At the top of the script, you’ll see the using statements — these tell the script what code libraries the script can reference.
- Below that, you’ll see a class definition that matches your script’s name: public class Obstacle : MonoBehaviour.
- Start() runs once, when the GameObject is first created in the scene.
- Update() runs once per frame — it’s used to check things like input or movement.
Note: Your script might look a bit different depending on your version of Unity or which IDE you're using — and that’s okay!
You don’t need to fully understand what each part of the code does yet. For now, just focus on recognizing the basic structure — you’ll add your own code inside these methods soon.
5. Change the size using a fixed value
Let’s write your first real line of code. You’ll use the Start() method to change the scale of the obstacle when the game begins. You’ll set the obstacle’s size using a piece of data called a Vector3 — which holds three values: X, Y, and Z.
You’ll set the scale by accessing the GameObject’s Transform component, the component Unity uses to store an object’s position, rotation, and scale. In your code, setting the transform.localScale affects how big or small the object appears in the scene.
Tip: Rather than copying and pasting the code below, try typing it out yourself. As you type, you might notice that your code editor suggests autocomplete options — including method names, definitions, and parameters. This is a feature of most modern editors (like Visual Studio or VS Code), and it makes coding faster and less error-prone.
If you don’t see suggestions as you type — and you’re using a macOS — you might need to configure your editor to properly support Unity and C#. Once it’s working, autocomplete will save you a lot of time.
1. Add code inside the Start() method:
- In the Obstacle script, find the empty Start() method.
Inside the opening and closing curly braces { }, add the following line of code:
transform.localScale = new Vector3(2, 2, 1);Explanation:
- The X and Y values control the width and height.
- The Z value is required, even though it doesn’t affect 2D visuals.
- The = sign here doesn’t mean "is equal to" like in math — it means you’re setting the variable on the left to be equal to the value on the right.
2. Save your script:
- Press Ctrl+S (macOS: Cmd+S) to save the file.
- Don’t close your code editor — you’ll be coming back to it.
3. Test in Unity:
- Switch back to the Unity Editor and select the Play button. You’ll see your obstacles appear at twice the scale they were originally.
Exit Play mode when you’re done testing.
You’ve just written your first line of gameplay code — and seen how scripting directly affects your prefab. Next, you’ll take this further by giving each obstacle a random size instead of a fixed one.
6. Add randomized size logic
In this step, you’ll use Unity’s Random.Range() function to give every obstacle a random scale when the game starts.
You’ll also declare your first variable — a piece of data that can change. In this case, you'll store a random number in a variable and then use it to scale the obstacle.
1. Declare a new variable to store a random size:
- In the Start() method, above the transform.localScale line, add the following line of code:
float randomSize = Random.Range(0.5f, 2.0f);Explanation:
- float is short for “floating point number”, which means the variable can store a number with decimals.
- Random.Range(min, max) picks a value between the two numbers you give it (including the minimum, excluding the maximum).
You can name your variable anything, but randomSize is clear and descriptive. - 0.5f and 2.0f mean that the object can scale anywhere from half its default size (0.5) to double its default size (2.0)
2. Use the variable to set the scale:
- Replace your previous hard-coded X and Y values with your new randomSize variable:
transform.localScale = new Vector3(randomSize, randomSize, 1);Now both the X and Y scale will use your random value — creating a proportional shape that changes size with each new instance.
3. Quickly test and retest with a keyboard shortcut in Unity:
- Press Ctrl+S (macOS: Cmd+S) to save the script.
- Return to Unity and press Ctrl+P (macOS: Cmd+P) to quickly enter and exit Play mode.
- Each obstacle will now appear at a slightly different size.
- Try exiting and entering Play mode a few more times to see the obstacles change in size each time.
Tip: To decrease loading time each time you enter Play mode, you can disable reloading the domain and scene in the Editor settings.
You’ve now used a variable and random number generation to make your obstacles more dynamic — a key part of making games feel less repetitive.
7. Create variables for size range
Right now, your script uses specific numbers (0.5f and 2.0f) to set the random size. This works — but what if you wanted to adjust those values later? Rather than editing them directly inside the Random.Range() function somewhere in the middle of your code, it’s better to store them as global variables at the top of your script. This makes your code easier to read and modify.
In this step, you’ll move your size range values into variables and make your code more flexible.
1. Add two new variables at the top of your script:
- In your Obstacle script, after the first opening curly brace ({), add the following lines of code:
float minSize = 0.5f;
float maxSize = 2.0f;Tip: Placing variables outside of methods lets you reuse them in multiple places. You’ll learn more about scope and variable placement later.
2. Update your random size line to use the new variables:
- In your Start() method, change the Random.Range() line to use your new variables:
float randomSize = Random.Range(minSize, maxSize);4. Save and test:
- Press Ctrl+S (macOS: Cmd+S) to save.
- Return to Unity and enter Play mode — you should still see varying obstacle sizes as you did before, but now they’re using cleaner code!
You’ve cleaned up your code by using variables instead of hard-coded numbers — a best practice in programming.
8. Auto-format your code
It can be surprisingly frustrating when your code looks messy — misaligned brackets and inconsistent spacing can make even simple logic harder to read and debug. Keeping your code nicely indented not only improves its readability, but it also helps you spot structural mistakes faster. Fortunately, most code editors come with shortcuts that let you automatically format your code with proper indentation.
1. Mess up the indentation temporarily:
- Change the spacing or alignment of some of your code to simulate disorganized formatting.
- This will help you see the effect of the auto-indent clearly.
2. Use the shortcut to auto-indent:
- If you're using Visual Studio Code on macOS, press Cmd+K, then Cmd+J.
- If you're using Visual Studio on Windows, press Ctrl+K, then Ctrl+D.
- If you're using another IDE or if the above shortcuts aren’t working for some reason, search for the keyboard shortcut to "Format Document" or "Auto-indent".
Your code should now snap back into a clean, well-structured format — making it easier to follow and maintain. Use this shortcut as often as you need to keep your code nice and organized.
9. Apply force to the obstacles
So far, your obstacles can fall and bounce, but they don’t move on their own. In this step, you’ll apply a force to each one using Unity’s physics system so they shoot off in a direction when the game starts.
To do this, you’ll first need to access the Rigidbody 2D component through code using a method called GetComponent. Then, you’ll use the AddForce() method to push the obstacle in a direction.
This step introduces a core Unity concept: getting references to components in code.
1. Add a reference to the Rigidbody 2D component:
- Underneath your minSize and maxSize variable declarations, add the following line of code:
Rigidbody2D rb;This creates a variable that will hold a reference to the obstacle’s Rigidbody 2D component. It’s very common among Unity developers to give Rigidbody variables the name “rb” for short.
2. Get the Rigidbody 2D component in Start():
- Inside the Start() method, below your code that scales the Obstacle, add the following line of code:
rb = GetComponent<Rigidbody2D>();Explanation:
- GetComponent searches the current GameObject for a specific type of component. Unity will find the Rigidbody 2D component so you can use it in your code.
- The <Rigidbody2D> part tells Unity what type of component to look for.
- The empty () is required syntax — it just means “run this method with no extra info.” Yes, it looks strange at first, but you’ll see this pattern a lot in C# scripts.
3. Apply force in a direction:
- Still in Start(), add the following line of code below your other code:
rb.AddForce(Vector2.right * 100);Explanation:
- Vector2.right means “move right along the x-axis.”
- The number 100 is the strength of the force.
- You can also experiment with Vector2.up, Vector2.left, or Vector2.down to try other directions.
- You are just moving all the obstacles in a single specific direction for now — you’ll randomize this direction in the coming steps.
4. Save and test:
- Press Ctrl+S (macOS: Cmd+S) to save.
- Return to Unity and enter Play mode — the obstacle should now initially move to the right as it’s falling down.
10. Set gravity scale to zero
Right now, your obstacle moves — but gravity is still pulling it downward. In your game, you want the obstacles to float and bounce freely without falling over time. To achieve that, you’ll set the Gravity Scale property on the Rigidbody 2D component to 0.
Since the obstacle is a prefab, you’ll update the value directly in the prefab so all instances inherit the change.
1. Select the Obstacle prefab:
- In the Project window, locate and select the Obstacle prefab.
2. Set Gravity Scale to 0:
- In the Inspector window, find the Rigidbody 2D component.
- Change the Gravity Scale property from 1 to 0.
3. Save and test:
- Enter Play mode. The obstacle will now move in a straight line without falling.
11. Randomize the speed
In this step, you’ll make each obstacle move at a random speed using the same technique you used to randomize the size: define a range and pick a random value within it.
This will add variety and make the game feel more dynamic.
1. Add two new variables for speed range:
- At the top of your script, below your minSize and maxSize variables, add the following lines of code:
float minSpeed = 50f;
float maxSpeed = 150f;These values define the slowest and fastest speeds each obstacle can have.
2. Generate a random speed:
- In the Start() method, above your AddForce line, add the following line of code:
float randomSpeed = Random.Range(minSpeed, maxSpeed);This picks a new speed for each obstacle when the game starts.
3. Replace the fixed force with your random value.
- Update the AddForce() line to use your new variable instead of the hardcoded 100 value:
rb.AddForce(Vector2.right * randomSpeed);4. Save and test:
- Press Ctrl+S (macOS: Cmd+S) to save.
- Return to Unity and enter Play mode — each obstacle will now launch at slightly different speeds each time you test the game.
12. Randomize direction
Right now, all obstacles launch in the same direction. In this step, you’ll replace the fixed Vector2.right direction with a random 2D direction using the very helpful Random.insideUnitCircle function
This function gives you a random point inside a circle with a radius of 1 — perfect for generating unpredictable motion in 2D space.
1. Generate a random direction vector:
- In your Start() method, above the AddForce() line, add the following line of code:
Vector2 randomDirection = Random.insideUnitCircle;Explanation:
- insideUnitCircle gives you a Vector2 with both X and Y values between -1 and 1 — pointing in a random direction within a circular area.
2. Use the random direction to apply force:
- Update your force line to use the following new variable:
rb.AddForce(randomDirection * randomSpeed);This will apply your random speed in a random direction for each obstacle.
3. Save and test:
- Press Ctrl+S (macOS: Cmd+S) to save.
- Return to Unity and enter Play mode — each obstacle will now launch in a new random direction and speed each time you start the game.
You've now combined randomized direction and speed — creating the chaotic motion that makes your game feel lively and replayable.
13. Expose variables in the Inspector window
At this point, your Obstacle script uses several variables — like minSize, maxSize, minSpeed, and maxSpeed. These values are currently hidden inside the script, which means you have to edit code every time you want to tweak them.
In this step, you’ll make those variables public, so they appear in the Inspector window. This lets you experiment and adjust behavior without touching the code again — a key workflow when collaborating with designers or fine-tuning gameplay.
1. Change your variables to public:
- At the top of your script, update the Size and Speed variables as follows to make them public:
public float minSize = 0.5f;
public float maxSize = 1.5f;
public float minSpeed = 50f;
public float maxSpeed = 150f;Explanation:
- When a variable is public, Unity automatically shows it in the Inspector window for any GameObject that uses the script.
2. Save your script and check the Inspector window:
- Press Ctrl+S (macOS: Cmd+S) to save.
- Select one of the Obstacle prefabs in the scene.
- In the Inspector window, you’ll now see the exposed variables listed under the Obstacle script component.
3. Try adjusting the values:
- Change the speed and size ranges in the Inspector window to test how they affect gameplay.
- Select the Play button and observe the changes — no code edits needed!
This use of variables is how Unity lets you separate logic (code) from tuning (Inspector window values), which is especially useful when working with non-programmers like artists and designers.
14. Final script sample
If you have any errors in your code or you just want to make sure your script matches exactly what has been taught up to this point, feel free to reference or copy the final code sample below.
Obstacle.cs
using UnityEngine;
public class Obstacle : MonoBehaviour
{
public float minSize = 0.5f;
public float maxSize = 2.0f;
public float minSpeed = 50f;
public float maxSpeed = 150f;
Rigidbody2D rb;
void Start()
{
float randomSize = Random.Range(minSize, maxSize);
transform.localScale = new Vector3(randomSize, randomSize, 1);
float randomSpeed = Random.Range(minSpeed, maxSpeed);
Vector2 randomDirection = Random.insideUnitCircle;
rb = GetComponent<Rigidbody2D>();
rb.AddForce(randomDirection * randomSpeed);
}
}15. Optional: More things to try
Try these optional activities to challenge yourself, build your skills, and improve your project.
Each challenge is tagged as Easy, Medium, or Expert difficulty so that you know what to expect. You can complete one, all, or none of them — it’s totally up to you. If you’re not interested in doing these challenges, mark this step as complete and proceed to the next tutorial.
Easy: Create a unique starting layout
Take some time to carefully place the obstacles in strategic locations on the screen.

- Move the copies around the screen to create an interesting pattern or obstacle field.
- Adjust their rotation for more variety.
Medium: Make larger obstacles move slower
Give your obstacles more weight by adjusting their speed based on their size.
- In your Obstacle script, before you add force, divide the speed variable by the size variable.
- This will make larger obstacles relatively slower than the smaller ones.
float randomSpeed = Random.Range(minSpeed, maxSpeed) / randomSize;Tip: You’ll likely want to increase the minSpeed and maxSpeed variables in the Obstacle component in the Inspector to compensate for this new reduction in speed.
Medium: Add randomized spin
Make your obstacles rotate unpredictably when they spawn.
- In your Obstacle script, add the following new variable at the top:
public float maxSpinSpeed = 10f;- At the bottom of the Start() method, add the following lines of code:
float randomTorque = Random.Range(-maxSpinSpeed, maxSpinSpeed);
rb.AddTorque(randomTorque);16. Next steps
You’ve written your first full Unity script — giving each obstacle a random size, direction, and speed. In the next tutorial, you’ll create a controllable player GameObject and learn how to have the player GameObject detect mouse input, rotate toward the cursor, and move using thrust.