---
title: "Random obstacle size, direction, and speed"
content_type: tutorial
url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/random-obstacle-size-direction-and-speed?language=en"
language: en
container_type: pathway
container_title: "Game Development"
container_url: "https://learn.unity.com/pathway/game-development.md?language=en&version=6.3"
unit_title: "Create a basic 2D game"
unit_url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game?language=en&version=6.3"
standalone_markdown_url: "https://learn.unity.com/tutorial/random-obstacle-size-direction-and-speed.md?language=en&version=6.3"
previous_title: "Make a flying obstacle prefab"
previous_url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/make-a-flying-obstacle-prefab?language=en&version=6.3"
previous_markdown_url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/make-a-flying-obstacle-prefab.md?language=en&version=6.3"
next_title: "Steer the player"
next_url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/steer-the-player?language=en&version=6.3"
next_markdown_url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/steer-the-player.md?language=en&version=6.3"
difficulty: beginner
duration_minutes: 45
unity_version:
  - "6.0"
  - "6.3"
supported_unity_versions:
  - name: "6.0"
    url: "https://learn.unity.com/tutorial/random-obstacle-size-direction-and-speed.md?language=en&version=6.0"
  - name: "6.3"
    url: "https://learn.unity.com/pathway/game-development/unit/create-a-basic-2d-game/tutorial/random-obstacle-size-direction-and-speed.md?language=en&version=6.3"
last_updated: "2026-08-04T14:22:36.000Z"
---

# Random obstacle size, direction, and speed

Write a Unity C# script to randomize obstacle behavior, edit prefabs, and test interactions in real time to enliven your game world.

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.

## 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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/e8dda387-dad9-46e0-a632-5837f058a6db_3.1_-_Overview.mp4)

## 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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/505e105b-a0d9-4590-9e70-747ff63a4fe5_3.3_-_Create_and_attach_a_new_script.mp4)

**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.

![](https://connect-mediagw.unity.com/h1/20250520/learn/images/fb7f415e-a670-4f49-9b8c-448080e6839e_3.4_-_Understand_the_script_structure.png)

**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](https://learn.unity.com/tutorial/project-setup-processes#6273ee10edbc2a0232556f15) or [check out the Unity manual page on Visual Studio C# integration](https://docs.unity3d.com/2022.3/Documentation/Manual/VisualStudioIntegration.html).

**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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/83085529-1cf5-4c63-88f6-95331dbe909d_3.5_-_Change_the_size_using_a_fixed_value.mp4)

**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:

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/0d929fbc-55b0-45db-b3cc-9358676dbaa3_3.6_-_Add_randomized_size_logic.mp4)

**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:

```csharp
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:

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/1e6f4b82-fc15-4963-8589-05a83cd84bfe_3.7_-_Create_variables_for_size_range.mp4)

**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:

```csharp
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:

```csharp
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 **Shift + Option + F**.
- 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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/589cac13-25d8-457d-96b7-e6cb12cbbbfc_3.8_-_Apply_force_to_the_obstacles.mp4)

**1.  Add a reference to the Rigidbody 2D component:**

- Underneath your **minSize** and **maxSize** variable declarations, add the following line of code:

```csharp
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:

```csharp
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:

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/11bcf08a-4bc6-44e6-9b74-55eb3f4d3ea0_3.9_-_Set_gravity_scale_to_zero.mp4)

**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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/1f230904-613e-4fa2-92df-bc5b319ea117_3.10_-_Randomize_the_speed.mp4)

**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:

```csharp
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:

```csharp
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:

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/63f9efc6-8a88-46ef-a479-d406dacae5a3_3.11_-_Randomize_direction.mp4)

**1.  Generate a random direction vector:**

- In your **Start()** method, above the **AddForce()** line, add the following line of code:

```csharp
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:

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/74a3932b-56f3-4611-85a9-6e8c8ceb17f6_3.12_-_Expose_variables_in_the_Inspector.mp4)

**1.  Change your variables to public:**

- At the top of your script, update the **Size** and **Speed** variables as follows to make them public:

```csharp
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

```csharp
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 _(Optional)_

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.

![](https://connect-mediagw.unity.com/h1/20250520/learn/images/e4b6e8aa-c4a1-46b4-85dc-5e92cac64a95_3.13_-_Easy_-_Create_a_unique_starting_layout.png)

- 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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/11bf8f9c-6093-4792-b03a-86f82366e34f_3.13_-_Medium_-_Make_larger_obstacles_move_slower.mp4)

- 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.

```csharp
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.

[Video](https://connect-mediagw.unity.com/h1/20250520/videos/319d66bf-c7d8-4471-9b0f-ad5f458bd501_3.13_-_Medium_-_Add_randomized_spin.mp4)

- In your **Obstacle** script, add the following new variable at the top:

```csharp
public float maxSpinSpeed = 10f;
```

- At the bottom of the **Start()** method, add the following lines of code:

```csharp
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.
