10 GameDev Prompts for Unity, Unreal Engine, and Godot

Why You Need Specialized GameDev Prompts

Developing a game involves dozens of repetitive tasks — from writing boilerplate code to setting up physics and animating characters. Instead of searching Stack Overflow every time, you can use a well-crafted prompt that gets you a ready-to-use solution. This collection covers Unity (C#), Unreal Engine (Blueprints), and Godot (GDScript). Each prompt is tested and includes a real example so you can copy-paste and adapt it immediately.

1. Unity C#: Player Controller with Jump and Dash

Prompt: "Write a Unity C# script for a 2D player controller. The player moves horizontally with WASD, jumps with Space, and dashes in the movement direction with Left Shift. Dash should have a cooldown of 2 seconds and a distance of 5 units. Use Rigidbody2D for physics and check if the player is grounded with a Raycast. Include comments explaining each section."

Why this works: This prompt specifies the movement keys, physics component, ground detection method, and dash parameters. It eliminates ambiguity and gives you a production-ready controller.

using UnityEngine;

public class PlayerController : MonoBehaviour
{
    public float moveSpeed = 5f;
    public float jumpForce = 10f;
    public float dashSpeed = 20f;
    public float dashDuration = 0.2f;
    public float dashCooldown = 2f;
    public LayerMask groundLayer;

    private Rigidbody2D rb;
    private bool isGrounded;
    private bool canDash = true;
    private bool isDashing;
    private float dashTimeLeft;
    private float dashCooldownLeft;
    private Vector2 moveDirection;

    void Start()
    {
        rb = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        // Ground check using Raycast from the player's position downward
        isGrounded = Physics2D.Raycast(transform.position, Vector2.down, 0.1f, groundLayer);

        // Horizontal input
        float horizontalInput = Input.GetAxisRaw("Horizontal");
        moveDirection = new Vector2(horizontalInput, 0);

        // Jump only when grounded
        if (Input.GetKeyDown(KeyCode.Space) && isGrounded)
        {
            rb.AddForce(Vector2.up * jumpForce, ForceMode2D.Impulse);
        }

        // Dash logic with cooldown
        if (Input.GetKeyDown(KeyCode.LeftShift) && canDash && !isDashing && moveDirection != Vector2.zero)
        {
            isDashing = true;
            dashTimeLeft = dashDuration;
            canDash = false;
            dashCooldownLeft = dashCooldown;
        }

        // Handle dash duration
        if (isDashing)
        {
            if (dashTimeLeft > 0)
            {
                rb.velocity = moveDirection.normalized * dashSpeed;
                dashTimeLeft -= Time.deltaTime;
            }
            else
            {
                isDashing = false;
            }
        }

        // Cooldown timer
        if (!canDash)
        {
            dashCooldownLeft -= Time.deltaTime;
            if (dashCooldownLeft <= 0)
            {
                canDash = true;
            }
        }
    }

    void FixedUpdate()
    {
        // Apply horizontal movement only when not dashing
        if (!isDashing)
        {
            rb.velocity = new Vector2(moveDirection.x * moveSpeed, rb.velocity.y);
        }
    }
}

Usage example: Attach this script to your player GameObject. Set the groundLayer to the layer of your floor tiles. Adjust moveSpeed, jumpForce, and dashSpeed in the Inspector to match your game feel.

2. Unreal Engine Blueprint: Health System with Damage and Healing

Prompt: "Create an Unreal Engine Blueprint for a health system. The actor should have a Health integer variable (max 100) and a bIsDead boolean. Expose functions: TakeDamage(int Amount) and Heal(int Amount). TakeDamage reduces Health by Amount, clamps to 0, and if Health <= 0, sets bIsDead to true and prints 'Player Died'. Heal increases Health by Amount up to MaxHealth. Use a Timeline to play a red flash on damage. The blueprint should be well-organized with comment nodes."

Why this works: This prompt asks for a complete system with visual feedback, state management, and clear public functions. It avoids vague requests like "make health" and instead defines exact behavior.

Usage example: In the Blueprint Editor, create a new Actor Blueprint. Add a Health integer variable (default 100) and a MaxHealth integer variable (default 100). Add a bIsDead boolean (default false). Create these custom events:

  • Event TakeDamage (int Amount): Get Health, subtract Amount, clamp to 0. If Health <= 0, set bIsDead to true, print "Player Died" (Print String). Use a Timeline to lerp a DamageFlash material parameter from 0 to 1 and back over 0.2 seconds.
  • Event Heal (int Amount): Get Health, add Amount, clamp to MaxHealth.

Practical tip: Use a Branch node after the clamp to check Health <= 0 and a Sequence node to run the death logic and flash simultaneously.

3. Godot GDScript: Inventory System with Grid

Prompt: "Write a GDScript for a grid-based inventory system in Godot 4. The inventory is an array of arrays (grid). Each cell can be null or contain an item resource with a name, icon texture, and stack size. Implement functions: add_item(item, position) which places item if cell is empty and stackable, remove_item(position) returning the item, and move_item(from, to). Use a GridContainer in the UI to display icons. Include signal emission when inventory changes."

Why this works: This prompt clearly defines the data structure (grid), the item resource, required functions, UI component, and signal integration. It's a complete specification.

extends Node

# The inventory grid: array of arrays
var grid: Array = []
@export var grid_width: int = 5
@export var grid_height: int = 5

signal inventory_changed

func _ready():
    # Initialize grid with empty cells
    for x in range(grid_width):
        grid.append([])
        for y in range(grid_height):
            grid[x].append(null)

func add_item(item: Resource, pos: Vector2i) -> bool:
    # Check bounds and if cell is empty
    if pos.x < 0 or pos.x >= grid_width or pos.y < 0 or pos.y >= grid_height:
        return false
    if grid[pos.x][pos.y] != null:
        return false
    grid[pos.x][pos.y] = item
    inventory_changed.emit()
    return true

func remove_item(pos: Vector2i) -> Resource:
    if pos.x < 0 or pos.x >= grid_width or pos.y < 0 or pos.y >= grid_height:
        return null
    var item = grid[pos.x][pos.y]
    grid[pos.x][pos.y] = null
    if item:
        inventory_changed.emit()
    return item

func move_item(from: Vector2i, to: Vector2i) -> bool:
    var item = remove_item(from)
    if item == null:
        return false
    if add_item(item, to):
        return true
    else:
        # Put it back if destination is invalid
        add_item(item, from)
        return false

Resource definition (in separate file):

extends Resource
class_name InventoryItem

@export var item_name: String = ""
@export var icon: Texture2D
@export var stack_size: int = 1

Usage example: Create a scene with a GridContainer. In _ready(), connect the inventory_changed signal to a function that clears and rebuilds the UI (instantiate TextureRect nodes with the item icons).

4. Unity C#: Object Pooling for Bullets

Prompt: "Write a Unity C# object pool for bullets. The pool should have a Queue of GameObjects, an Initialize method that creates a set number of bullet instances (default 20) under a parent transform, and a GetBullet method that activates and returns a bullet from the queue. If the queue is empty, instantiate a new bullet. Include a ReturnBullet method that deactivates the bullet and puts it back. Use a Bullet script with OnDisable to automatically return to pool. Use a static instance for global access."

Why this works: Object pooling is critical for performance in shooters. This prompt covers instantiation, reuse, auto-return, and singleton access.

using System.Collections.Generic;
using UnityEngine;

public class BulletPool : MonoBehaviour
{
    public static BulletPool Instance;
    public GameObject bulletPrefab;
    public int poolSize = 20;
    private Queue<GameObject> pool = new Queue<GameObject>();

    void Awake()
    {
        Instance = this;
        Initialize();
    }

    void Initialize()
    {
        for (int i = 0; i < poolSize; i++)
        {
            GameObject bullet = Instantiate(bulletPrefab, transform);
            bullet.SetActive(false);
            pool.Enqueue(bullet);
        }
    }

    public GameObject GetBullet()
    {
        if (pool.Count == 0)
        {
            // Expand pool if empty
            GameObject newBullet = Instantiate(bulletPrefab, transform);
            newBullet.SetActive(false);
            pool.Enqueue(newBullet);
        }
        GameObject bullet = pool.Dequeue();
        bullet.SetActive(true);
        return bullet;
    }

    public void ReturnBullet(GameObject bullet)
    {
        bullet.SetActive(false);
        pool.Enqueue(bullet);
    }
}

Bullet script (attached to prefab):

using UnityEngine;

public class Bullet : MonoBehaviour
{
    public float speed = 10f;

    void OnEnable()
    {
        // Reset position and velocity if needed
        Invoke(nameof(DisableAfterTime), 2f);
    }

    void Update()
    {
        transform.Translate(Vector3.forward * speed * Time.deltaTime);
    }

    void DisableAfterTime()
    {
        gameObject.SetActive(false);
    }

    void OnDisable()
    {
        CancelInvoke();
        BulletPool.Instance.ReturnBullet(gameObject);
    }
}

Usage example: Call BulletPool.Instance.GetBullet() when the player shoots. The bullet automatically returns to the pool after 2 seconds or when disabled.

5. Unreal Engine Blueprint: Patrol AI with Waypoints

Prompt: "Create an Unreal Engine AI controller Blueprint for a patrolling enemy. The AI should have an array of waypoints (Actors). In the Event Tick, move the AI Character toward the current waypoint at a speed of 200 units per second. When the AI reaches within 50 units of the waypoint, switch to the next waypoint (loop back to the first after the last). Use a FindPath node to navigate and a Branch to check distance. Add a comment explaining the logic."

Why this works: This prompt gives a concrete movement speed, distance threshold, and pathfinding method, making the Blueprint non-ambiguous.

Usage example: In your AI Character Blueprint, add an array variable Waypoints (type Actor). In the Event Graph of the AI Controller:

  1. Event BeginPlay: Set a variable CurrentWaypointIndex to 0.
  2. Event Tick: Get CurrentWaypointIndex, use Get from Waypoints array. Use FindPath (AI Move To) with the target as the current waypoint's location. Use a Branch to check if the distance from the AI to the waypoint is less than 50 units. If true, increment CurrentWaypointIndex (if >= array length, set to 0).

Practical tip: Use Simple Move to Location node (not FindPath) for a simpler implementation. Place Sphere actors in the level as waypoints and assign them to the array in the Details panel.

6. Godot GDScript: Procedural Dungeon Generation

Prompt: "Write a GDScript for generating a simple dungeon using a basic cellular automata algorithm in Godot 4. The script should create a 2D TileMap, fill it randomly with wall tiles (40% chance), then run 3 iterations of smoothing: a cell becomes a wall if it has 4 or more wall neighbors, otherwise it becomes floor. Use TileSet with two tiles: floor (index 0) and wall (index 1). The dungeon should be 50x50 tiles. Include comments explaining each step."

Why this works: This prompt specifies the algorithm (cellular automata), parameters (40% fill, 4 neighbor threshold, 3 iterations), tile indices, and map size.

extends TileMap

@export var width: int = 50
@export var height: int = 50
@export var wall_chance: float = 0.4
@export var smoothing_iterations: int = 3
@export var wall_neighbor_threshold: int = 4

var map: Array = []

func _ready():
    generate_dungeon()

func generate_dungeon():
    # Step 1: Random fill
    for x in range(width):
        map.append([])
        for y in range(height):
            if randf() < wall_chance:
                map[x].append(1)  # wall
            else:
                map[x].append(0)  # floor

    # Step 2: Smoothing
    for iteration in range(smoothing_iterations):
        var new_map = map.duplicate(true)
        for x in range(width):
            for y in range(height):
                var neighbor_walls = count_wall_neighbors(x, y)
                if neighbor_walls >= wall_neighbor_threshold:
                    new_map[x][y] = 1
                else:
                    new_map[x][y] = 0
        map = new_map

    # Step 3: Draw to TileMap
    clear()
    for x in range(width):
        for y in range(height):
            set_cell(0, Vector2i(x, y), 0, Vector2i(map[x][y], 0))

func count_wall_neighbors(cell_x: int, cell_y: int) -> int:
    var count = 0
    for dx in [-1, 0, 1]:
        for dy in [-1, 0, 1]:
            if dx == 0 and dy == 0:
                continue
            var nx = cell_x + dx
            var ny = cell_y + dy
            if nx < 0 or nx >= width or ny < 0 or ny >= height:
                count += 1  # treat out-of-bounds as wall
            elif map[nx][ny] == 1:
                count += 1
    return count

Usage example: Create a new TileMap node in your scene. Assign a TileSet with at least two tiles (floor at (0,0) and wall at (1,0) in the tileset). Attach this script. Adjust wall_chance and smoothing_iterations for different cave-like or room-like dungeons.

7. Unity C#: Saving Game State with JSON

Prompt: "Write a Unity C# script that saves and loads game state using JSON and PlayerPrefs. Create a GameData class (serializable) with int score, float health, and Vector3 playerPosition. Use a SaveManager with static methods SaveGame(GameData data) that serializes data to JSON and saves it under the key 'savegame', and LoadGame() that deserializes and returns GameData. Handle missing save file gracefully by returning new GameData with default values. Use JsonUtility."

Why this works: This prompt defines the data structure, serialization method, storage medium, and error handling, making it a complete save system.

using UnityEngine;
using System.IO;

[System.Serializable]
public class GameData
{
    public int score;
    public float health;
    public float[] playerPosition; // Vector3 serialized as array

    public GameData()
    {
        score = 0;
        health = 100f;
        playerPosition = new float[] { 0, 0, 0 };
    }
}

public static class SaveManager
{
    private static string savePath = Application.persistentDataPath + "/savegame.json";

    public static void SaveGame(GameData data)
    {
        string json = JsonUtility.ToJson(data);
        File.WriteAllText(savePath, json);
        Debug.Log("Game saved to " + savePath);
    }

    public static GameData LoadGame()
    {
        if (File.Exists(savePath))
        {
            string json = File.ReadAllText(savePath);
            GameData data = JsonUtility.FromJson<GameData>(json);
            return data;
        }
        else
        {
            Debug.LogWarning("Save file not found. Returning default data.");
            return new GameData();
        }
    }
}

Usage example: In your game manager, create a GameData instance, fill it with current score, health, and player position (convert Vector3 to float array: new float[] { transform.position.x, transform.position.y, transform.position.z }). Call SaveManager.SaveGame(data) on level complete or manually. On game start, call GameData loaded = SaveManager.LoadGame() and apply values.

8. Unreal Engine Blueprint: Pickup Item with Custom Event

Prompt: "Create an Unreal Engine Blueprint for a pickup item. The actor should have a Sphere Collision component and a Static Mesh (a small sphere or coin). When the player overlaps the collision, call a Custom Event 'OnPickup' that plays a sound cue from a variable, adds 10 points to the player's score (using a GameInstance variable or direct print), and destroys the actor. Use a Branch to check that the overlapping actor has a specific tag 'Player'. Attach a comment to each node."

Why this works: This prompt defines collision shape, visual, sound, score logic, tag filtering, and cleanup.

Usage example: Create a new Actor Blueprint. Add a Sphere Collision (set radius to 100) and a Static Mesh (set to a sphere or coin mesh). Add a variable PickupSound (type SoundCue). In the Event Graph:

  1. Add Event OnComponentBeginOverlap (SphereCollision).
  2. From the Other Actor pin, use a Branch with Equal (Object) comparing Other Actor to a Get Player Character node? Actually, simpler: use Get Actor Tag node on Other Actor and compare to string "Player" with a Branch.
  3. If true, call OnPickup custom event (create it: right-click > Add Custom Event).
  4. In OnPickup: Play Sound 2D (PickupSound), Add to Score (if you have a GameInstance) or print "+10 Points", then Destroy Actor.

Practical tip: Use Get Player Character for a more direct reference if only the player can pick up. The tag method is more flexible for multiplayer.

9. Godot GDScript: Dialogue System with Choices

Prompt: "Write a GDScript for a simple dialogue system in Godot 4. The script should read dialogue data from a JSON file. Each dialogue entry has: id (string), speaker (string), text (string), and choices (array of { text: string, next_id: string }). The script displays the speaker name and text in a RichTextLabel, and choice buttons in a VBoxContainer. When a choice is clicked, load the next dialogue entry by its id. Include a function to start dialogue with a specific id. Use signals to notify when dialogue ends (when next_id is empty)."

Why this works: This prompt specifies data format, UI components, navigation logic, and completion signaling.

extends Control

@onready var speaker_label: Label = $SpeakerLabel
@onready var text_label: RichTextLabel = $TextLabel
@onready var choices_container: VBoxContainer = $ChoicesContainer

var dialogue_data: Dictionary = {}
var current_id: String = ""

signal dialogue_ended

func _ready():
    # Load JSON file from res://dialogue.json
    var file = FileAccess.open("res://dialogue.json", FileAccess.READ)
    var json_text = file.get_as_text()
    dialogue_data = JSON.parse_string(json_text)

func start_dialogue(start_id: String):
    current_id = start_id
    show_entry(current_id)

func show_entry(entry_id: String):
    # Clear previous choices
    for child in choices_container.get_children():
        child.queue_free()

    var entry = dialogue_data[entry_id]
    speaker_label.text = entry["speaker"]
    text_label.text = entry["text"]

    if entry.has("choices") and entry["choices"].size() > 0:
        for choice in entry["choices"]:
            var button = Button.new()
            button.text = choice["text"]
            button.pressed.connect(_on_choice_pressed.bind(choice["next_id"]))
            choices_container.add_child(button)
    else:
        # No choices -> end dialogue
        dialogue_ended.emit()

func _on_choice_pressed(next_id: String):
    if next_id == "" or next_id == null:
        dialogue_ended.emit()
    else:
        show_entry(next_id)

Example JSON (dialogue.json):

{
  "start": {
    "speaker": "Old Man",
    "text": "Welcome, traveler. Do you seek adventure?",
    "choices": [
      { "text": "Yes!", "next_id": "adventure_yes" },
      { "text": "Not now.", "next_id": "" }
    ]
  },
  "adventure_yes": {
    "speaker": "Old Man",
    "text": "Then go to the dark forest and find the crystal.",
    "choices": []
  }
}

Usage example: Create a UI scene with a Panel, a Label (speaker), a RichTextLabel (text), and a VBoxContainer (choices). Attach this script. Call start_dialogue("start") when the player talks to an NPC. Connect dialogue_ended to close the UI.

10. Unity C#: Coroutine-Based Timer with Events

Prompt: "Write a Unity C# script for a countdown timer using coroutines. The timer should have methods: StartTimer(float duration), PauseTimer(), ResumeTimer(), and StopTimer(). It should invoke an event OnTimerFinished when the timer reaches zero. Use a bool to track if paused. The timer should display remaining time in a Unity UI Text element. Include comments."

Why this works: This prompt specifies coroutine usage, pause/resume functionality, event-driven completion, and UI integration.

using UnityEngine;
using UnityEngine.UI;
using System.Collections;

public class CountdownTimer : MonoBehaviour
{
    public Text timerText;
    public float remainingTime;
    private bool isPaused = false;
    private Coroutine timerCoroutine;

    public delegate void TimerFinished();
    public event TimerFinished OnTimerFinished;

    public void StartTimer(float duration)
    {
        if (timerCoroutine != null)
            StopCoroutine(timerCoroutine);
        remainingTime = duration;
        isPaused = false;
        timerCoroutine = StartCoroutine(TimerRoutine());
    }

    IEnumerator TimerRoutine()
    {
        while (remainingTime > 0)
        {
            if (!isPaused)
            {
                remainingTime -= Time.deltaTime;
                UpdateUI();
            }
            yield return null;
        }
        remainingTime = 0;
        UpdateUI();
        OnTimerFinished?.Invoke();
    }

    public void PauseTimer()
    {
        isPaused = true;
    }

    public void ResumeTimer()
    {
        isPaused = false;
    }

    public void StopTimer()
    {
        if (timerCoroutine != null)
            StopCoroutine(timerCoroutine);
        remainingTime = 0;
        UpdateUI();
    }

    void UpdateUI()
    {
        if (timerText != null)
            timerText.text = Mathf.Ceil(remainingTime).ToString();
    }
}

Usage example: Attach to a GameObject with a UI Text. Call StartTimer(60f) for a 60-second countdown. Subscribe to OnTimerFinished to trigger game over or level fail.

11. Unreal Engine Blueprint: Simple HUD with Health Bar

Prompt: "Create an Unreal Engine Widget Blueprint for a health bar. It should have a Progress Bar named 'HealthBar' and a Text Block named 'HealthText' showing 'Health: X / 100'. Expose a function 'UpdateHealth(float CurrentHealth, float MaxHealth)' that sets the percent of the Progress Bar and updates the text. The bar should be green when health > 50, yellow when between 25 and 50, red when below 25. Use a sequence of Branch nodes or a Switch on Int. Add comments."

Why this works: This prompt specifies UI components, function signature, color logic, and readability.

Usage example: Create a Widget Blueprint, add a Canvas Panel, then a Progress Bar (named HealthBar) and a Text Block (named HealthText). In the Graph, create a custom function UpdateHealth with inputs CurrentHealth (float) and MaxHealth (float). Inside:

  1. Set HealthBar.Percent = CurrentHealth / MaxHealth.
  2. Set HealthText.Text = "Health: " + CurrentHealth + " / " + MaxHealth.
  3. Use a Branch to check CurrentHealth / MaxHealth > 0.5. If true, set HealthBar.Fill Color to green. Else, use another Branch to check CurrentHealth / MaxHealth > 0.25. If true, set to yellow; else red.

Practical tip: To call this from your player character, get the HUD (via Get Player Controller > Get HUD) and then get the widget (if you added it to viewport).

12. Godot GDScript: Animation State Machine

Prompt: "Write a GDScript for an AnimationTree-based state machine for a 2D character. The character has three states: idle, walk, and jump. The AnimationTree should use a blend space for idle and walk based on a speed parameter, and a separate animation for jump that plays once. Use a state machine with two states: Ground (idle/walk) and Air (jump). Transition from Ground to Air when is_jumping becomes true, and from Air to Ground when is_on_floor(). Include comments."

Why this works: This prompt defines states, transitions, blend method, and parameter control.

extends AnimationTree

@export var speed: float = 0.0
@export var is_jumping: bool = false

func _ready():
    # Assuming an AnimationTree node with a state machine
    # The root is a StateMachine with Ground and Air states
    # Ground state contains a BlendSpace2D with idle and walk animations
    # Air state contains a single jump animation
    pass

func _process(delta):
    # Update blend parameter for ground movement
    set("parameters/Ground/blend_position", speed)

    # Check state transitions
    var current_state = get("parameters/StateMachine/current_state")
    if current_state == "Ground" and is_jumping:
        travel("parameters/StateMachine/Air")
    elif current_state == "Air" and get_parent().is_on_floor():
        travel("parameters/StateMachine/Ground")

Usage example: Create an AnimationTree node in your character scene. Set the anim player to your AnimationPlayer. Create a StateMachine root with two states: Ground (a BlendSpace2D with idle and walk animations) and Air (an AnimationNodeAnimation for jump). In the character's movement script, set speed to velocity.x / max_speed and is_jumping to true when jump button pressed. The state machine will handle transitions automatically.

How to Use These Prompts Effectively

  1. Be specific: Include variables, thresholds, and component names. The more detail, the better the output.
  2. Specify the engine and language: Always mention "Unity C#", "Unreal Blueprint", or "Godot GDScript" at the start.
  3. Request comments: Adding "include comments" ensures the code is readable and educational.
  4. Ask for error handling: For robustness, ask for null checks or default values.
  5. Iterate: If the first result isn't perfect, refine your prompt: "Add a cooldown" or "Use a different collision shape."

Conclusion

These 12 prompts cover the most common tasks in Unity, Unreal Engine, and Godot development. By using them, you save hours of boilerplate coding and focus on what matters: making your game fun. Copy, paste, and adapt them to your project. And remember — the engine is just a tool; your creativity is the real superpower. Happy developing!

← All posts

Comments