Skip to content

GameObject Manipulation

David O'Donoghue edited this page Jan 28, 2026 · 4 revisions

GameObject Manipulation

Methods for controlling GameObjects during tests: disable/enable, freeze physics, teleport, and toggle collisions.

Overview

All manipulation methods are async and wait up to 10 seconds (configurable) for elements to appear, consistent with other action methods. They return restoration tokens that can restore the original state:

using static ODDGames.UIAutomation.ActionExecutor;

// Via Search (async - require await)
await new Search().Name("Player").Freeze();
await Search.Reflect("GameManager.Instance.player").NoClip();

// Via static helpers
await Freeze(Name("Player"));
await NoClip(Static("GameManager.Instance.player"));

Methods

Method Returns Description
.Disable(searchTime) UniTask<ActiveState> Deactivate a GameObject
.Enable(searchTime) UniTask<ActiveState> Activate a GameObject (can find inactive)
.Freeze(includeChildren, searchTime) UniTask<FreezeState> Zero velocity + set kinematic on Rigidbodies
.Teleport(Vector3, searchTime) UniTask<PositionState> Move transform to world position
.NoClip(includeChildren, searchTime) UniTask<ColliderState> Disable all colliders
.Clip(includeChildren, searchTime) UniTask<ColliderState> Enable all colliders

All methods have a searchTime parameter (default 10 seconds) that controls how long to wait for the element to appear.

Disable / Enable

Control GameObject active state:

// Disable a GameObject
await new Search().Name("TutorialPanel").Disable();

// Enable an inactive GameObject (Enable() can find inactive objects)
await new Search().Name("TutorialPanel").Enable();

// Via Static path
await Search.Reflect("GameManager.Instance.tutorialPanel").Disable();

// Custom timeout (default is 10 seconds)
await new Search().Name("TutorialPanel").Disable(searchTime: 5f);

Freeze

Stop physics simulation on Rigidbodies:

// Freeze a single object (includes children by default)
await new Search().Name("AITruck").Freeze();

// Freeze only the root object
await new Search().Name("Player").Freeze(includeChildren: false);

// Via Static path
await Search.Reflect("GameManager.Instance.player").Freeze();

Freeze sets:

  • isKinematic = true
  • linearVelocity = Vector3.zero
  • angularVelocity = Vector3.zero

Works with both Rigidbody (3D) and Rigidbody2D (2D).

Teleport

Move a transform instantly to a world position:

// Teleport to position
await new Search().Name("Player").Teleport(new Vector3(100, 0, 50));

// Via Static path
await Search.Reflect("GameManager.Instance.player").Teleport(Vector3.zero);

Children maintain their local positions relative to the parent.

NoClip / Clip

Toggle collider states for pass-through or collision:

// Disable all colliders (pass through objects)
await new Search().Name("Player").NoClip();

// Enable all colliders (restore collisions)
await new Search().Name("Player").Clip();

// Only affect root object, not children
await new Search().Name("Player").NoClip(includeChildren: false);

Works with both Collider (3D) and Collider2D (2D).

Restoration Tokens

All methods return state objects that capture the original state before modification.

Manual Restore

// Capture state
var state = await new Search().Name("Player").NoClip();

// ... test code with colliders disabled ...

// Restore original state
state.Restore();

Using Pattern (Auto-Restore)

State tokens implement IDisposable for automatic restoration:

using (await new Search().Name("Player").NoClip())
{
    // Colliders disabled here
    await Click(Name("Button"));
}
// Colliders automatically restored

Multiple States

Stack multiple using blocks for complex setups:

using (await new Search().Name("AITruck").Freeze())
using (await new Search().Name("Player").NoClip())
{
    // AI frozen, player has no collision
    await Teleport(Name("Player"), targetPosition);
}
// Both states restored

State Properties

Property Description
.Count Number of affected components
.Restore() Restore original state (idempotent)
var state = await new Search().Name("Vehicle").Freeze();
Debug.Log($"Froze {state.Count} rigidbodies");

Static Helper Methods

Static helper methods are available via ActionExecutor:

using NUnit.Framework;
using static ODDGames.UIAutomation.ActionExecutor;

[TestFixture]
public class GameObjectManipulationTests
{
    [Test]
    public async Task TestGameObjectManipulation()
    {
        // Helper methods (all async)
        await Disable(Name("TutorialPanel"));
        await Enable(Name("TutorialPanel"));
        await Freeze(Name("AITruck"));
        await Teleport(Name("Player"), new Vector3(100, 0, 50));
        await NoClip(Name("Player"));
        await Clip(Name("Player"));

        // They also return restoration tokens
        using (await Freeze(Name("AITruck")))
        {
            // AI frozen
        }
    }
}

Common Patterns

Skip Tutorial

// Disable tutorial UI without clicking through it
await Disable(Name("TutorialPanel"));
await Click(Name("StartGame"));

Freeze AI During Setup

using (await Freeze(Name("EnemySpawner")))
{
    // Position player without AI interference
    await Teleport(Name("Player"), spawnPoint);
    await WaitForSeconds(1);
}
// AI resumes

Pass Through Obstacles

using (await NoClip(Name("Player")))
{
    // Move through walls to reach test location
    await Teleport(Name("Player"), new Vector3(500, 0, 500));
}
// Collisions restored

Test Setup and Teardown

Use [Test] public async Task with try/finally for cleanup:

using NUnit.Framework;
using static ODDGames.UIAutomation.ActionExecutor;

[TestFixture]
public class AITests
{
    [Test]
    public async Task TestWithFrozenAI()
    {
        var frozenAI = await Freeze(Name("AIManager"));
        try
        {
            // ... test code ...
        }
        finally
        {
            frozenAI?.Restore();
        }
    }
}

Error Handling

Methods throw TimeoutException if the target is not found within the search time:

// Throws TimeoutException after 10s if "NonExistent" not found
await new Search().Name("NonExistent").Disable();

// Use shorter timeout for faster failure
await new Search().Name("NonExistent").Disable(searchTime: 1f);

Methods return zero-count states if no applicable components exist:

// Returns FreezeState with Count = 0 if no Rigidbodies
var state = await new Search().Name("StaticObject").Freeze();
Debug.Log(state.Count); // 0

Related Pages

Clone this wiki locally