Quick answer: “Move to Top” and “Move to Bottom” only reorder objects within the same layer. If the object you want to appear above is on a different (higher) layer, Z order changes within your object’s layer will have no visible effect. Move the object to the correct layer first, or restructure your layers so that objects that need dynamic reordering share the same layer. If using 3D features, Z elevation overrides Z order via the depth buffer.

You add a “Move to top” action to make your player sprite render above enemy sprites. You run the game. Nothing changes. The player is still behind the enemies. You try “Move to bottom,” you try “Move to layer,” you try setting Z order values directly — and the visual result does not match what you expect. This is one of the most confusing aspects of Construct 3’s rendering system, because there are actually multiple independent systems that all affect visual ordering.

The Symptom

You use one of Construct 3’s Z order actions — Move to top, Move to bottom, Move in front of, or Move behind — and the visual rendering order of your objects does not change. The actions execute without errors, and if you check the Z order index of the object, it has indeed changed. But on screen, the object still renders in the same position relative to other objects.

This can manifest in several ways:

A character sprite that should appear in front of a background element always renders behind it, regardless of Z order actions. Or a dynamically created object always appears on top of everything, even after you explicitly move it to the bottom. Or two objects on different layers appear to ignore Z order changes entirely — one always renders above the other no matter what you do.

In projects using Construct 3’s 3D features (Z elevation), the situation gets even more confusing. An object with Z elevation of 100 renders in front of an object with Z elevation of 50, regardless of which one has a higher Z order index. This makes it seem like Z order actions have stopped working entirely.

What Causes This

There are four common causes for Z order actions not producing the expected visual result:

1. The objects are on different layers. This is the cause in the majority of cases. Construct 3 renders layers in a strict top-to-bottom order as listed in the Layers panel. All objects on Layer 2 render above all objects on Layer 1, always, regardless of Z order. Z order only controls rendering order within a single layer. If your player is on “GameObjects” (Layer 1) and the UI element blocking it is on “UI” (Layer 2), no amount of “Move to top” on the player will make it render above the UI layer.

2. Z elevation overriding Z order. When using Construct 3’s 3D features, each object can have a Z elevation value that positions it in 3D space. The renderer uses a depth buffer for Z elevation, which operates independently from the 2D Z order system. An object at Z elevation 200 will render in front of an object at Z elevation 100, even if the Z elevation 100 object has a higher Z order. This is correct 3D behavior but is unexpected if you are thinking in 2D Z order terms.

3. Timing: Z order changes on the same tick as object creation. If you create an object and immediately try to change its Z order on the same tick, the visual result may not appear until the next frame. More importantly, if multiple objects are created on the same tick, their Z order relative to each other depends on creation order. The last object created has the highest Z order. If you then move one to top, it may already be on top, making the action appear to have no effect.

4. Hierarchy children inheriting parent Z order. Objects in a parent-child hierarchy have their Z order managed relative to their parent. A child object renders relative to its parent’s Z position, and calling “Move to top” on a child moves it to the top of its siblings within the parent, not to the top of the entire layer. If you want to reorder the entire group (parent plus children), you need to move the parent.

The Fix

Step 1: Verify both objects are on the same layer.

Before changing Z order, confirm that the objects you want to reorder are actually on the same layer:

// Debug: Log which layer each object is on
Event: Keyboard > On D pressed  // Debug key
  Action: System > Log
    "Player layer: " & Player.LayerName
    & " | Z order: " & Player.ZIndex
  Action: System > Log
    "Enemy layer: " & Enemy.LayerName
    & " | Z order: " & Enemy.ZIndex

// If they show different layers, Z order changes
// within one layer cannot affect the other.

If the objects are on different layers and you need to reorder them, either restructure your layers or move one object to the other’s layer:

// Move the player to the same layer as the enemy:
Event: Player overlaps Enemy
  Action: Player > Move to layer Enemy.LayerName
  Action: Player > Move to top

// OR: Restructure layers so both are on the same layer.
// Recommended layer structure for a platformer:
//
// Layer: "UI"          (top - HUD, menus, always on top)
// Layer: "GameObjects" (middle - player, enemies, items)
// Layer: "Background"  (bottom - tiles, sky, parallax)
//
// Player and Enemy are BOTH on "GameObjects"
// Now Move to Top/Bottom controls their relative order.

Step 2: Use Y-sorting for automatic depth ordering.

For top-down games where objects lower on the screen should render in front of objects higher up, implement Y-sorting by continuously updating Z order based on Y position:

// Y-sorting: objects lower on screen render in front
// Run this every tick for all game objects on the same layer

Event: System > Every tick
  // For each game object, compare Y positions
  Action: Player > Move to top

  // Then sort by comparing Y values:
  Sub-event: For each Enemy ordered by Enemy.Y ascending
    Action: Enemy > Move to top

// More efficient approach using "Move in front/behind":
Event: System > Every tick
  Sub-event: Player > Is overlapping Enemy
    Sub-event: Player.Y > Enemy.Y
      Action: Player > Move in front of Enemy
    Sub-event: System > Else
      Action: Player > Move behind Enemy

Step 3: Handle Z elevation separately from Z order.

If you are using Construct 3’s 3D features, understand that Z elevation and Z order are independent systems:

// Z elevation (3D) overrides Z order (2D) via depth buffer.
// If two objects overlap on screen:

// Object A: Z order = 100, Z elevation = 50
// Object B: Z order = 1,   Z elevation = 200
// Result: B renders in front of A (Z elevation wins)

// To fix: set Z elevation to match your intended order
Event: System > Every tick
  Action: Player > Set Z elevation to Player.Y
  Action: Enemy > Set Z elevation to Enemy.Y

// If you don't need 3D, set all Z elevations to 0:
Event: System > On start of layout
  Action: Player > Set Z elevation to 0
  Action: Enemy > Set Z elevation to 0

// This ensures Z order (2D) controls rendering.

Step 4: Manage Z order in hierarchies correctly.

// For objects in a parent-child hierarchy:
// A weapon sprite is a child of the player sprite.

// WRONG: This moves the weapon to top of its siblings,
// not to the top of the entire layer:
Event: On attack
  Action: Weapon > Move to top  // Only moves within siblings!

// RIGHT: To move the entire player+weapon group to top,
// move the PARENT:
Event: On attack
  Action: Player > Move to top  // Moves player + all children

// To reorder children within the hierarchy:
Event: Player facing right
  // Weapon should render in front of player
  Action: Weapon > Move in front of Player

Event: Player facing left
  // Weapon should render behind player
  Action: Weapon > Move behind Player

Step 5: Use the scripting API for precise Z order control.

// JavaScript scripting API for Z order:
const player = runtime.objects.Player.getFirstInstance();
const enemy = runtime.objects.Enemy.getFirstInstance();

// Get current Z order index:
console.log("Player Z:", player.zIndex);
console.log("Enemy Z:", enemy.zIndex);

// Check which layer each is on:
console.log("Player layer:", player.layer.name);
console.log("Enemy layer:", enemy.layer.name);

// Move to top of current layer:
player.moveToTop();

// Move to a specific layer:
const targetLayer = runtime.layout.getLayer("GameObjects");
player.moveToLayer(targetLayer);

// Move in front of another instance:
player.moveInFrontOf(enemy);

// Set Z elevation (3D):
player.zElevation = 100;

Why This Works

Construct 3’s rendering pipeline processes layers in a strict order. Each layer is rendered as a complete unit before the next layer begins. Within a layer, objects are rendered in their Z order, from lowest (drawn first, appears behind) to highest (drawn last, appears in front). This two-level system — layers first, then Z order within layers — means Z order is always scoped to a single layer.

When you call “Move to top,” the engine sets the object’s Z index to be the highest on its current layer. This is a fast operation (it just moves the object to the end of the layer’s render list), but it cannot cross layer boundaries. Moving an object from Layer 1 to the top of Layer 1 has no effect on its relationship to objects on Layer 2.

Z elevation adds a third dimension to this system. When 3D rendering is involved, the GPU uses a depth buffer to determine which pixels are in front. The depth buffer does not care about layers or Z order — it only compares the actual Z elevation values of overlapping pixels. This is why Z elevation can override both Z order and layer order, which is correct for 3D rendering but confusing if you are thinking in 2D terms.

Hierarchies add yet another level of scoping. A child object’s Z position is relative to its parent in the render list. The parent and all its children form a contiguous group in the Z order. “Move to top” on a child reorders it within that group, not within the entire layer. This ensures that hierarchy groups stay together visually, which is usually the desired behavior for composite objects like a character with equipment.

“If Move to Top is not working, the first question is always: are both objects on the same layer? If they are not, Z order is not the tool you need.”

Related Issues

If your objects are rendering in the right order but their state resets when you change layouts, see global variable resets on layout restart for preserving game state. If the rendering itself crashes with a black screen, WebGL context lost errors covers GPU memory exhaustion that can disrupt the entire render pipeline. If your Z order issues only appear after the game loads, check loader layout stuck not progressing for asset loading problems that can affect object creation order. And for multiplayer games where different players see different Z orders, multiplayer signaling connection failures covers synchronization issues between peers.

Same layer? Then Z order works. Different layers? Move to layer first.