-
SurfaceEffect Resource (
scripts/surfaces/surface_effect.gd)- Data container for surface properties
- Three types: OIL, ICE, WATER
- Movement speed multipliers and friction modifiers
-
Surface Base Class (
scripts/surfaces/surface.gd)- Node3D with configurable radius
- Lifetime system (persistent or timed)
- Auto-registers with Room
- Stacking support via Y-position priority
-
Room Integration (updated
scripts/rooms/room.gd)active_surfacesarray trackingadd_surface()/remove_surface()methodsget_top_surface_at_position()- center point detection with variable radiusget_surfaces_in_radius()- for overlap queries
-
SurfaceDetector Component (
scripts/surfaces/surface_detector.gd)- Attaches to entities (Player/Enemy)
- Timer-based detection (0.1s intervals)
get_speed_multiplier()helper method- Emits
surface_changedsignal
-
OilSurface (
scripts/surfaces/oil_surface.gd)- 0.5x speed multiplier (sticky/slow)
- Radius: 2.0m
- Persistent lifetime
-
IceSurface (
scripts/surfaces/ice_surface.gd)- 1.2x speed multiplier (fast/slippery)
- Radius: 2.5m
- Lifetime: 30 seconds
- TODO: Add sliding momentum
-
WaterSurface (
scripts/surfaces/water_surface.gd)- 1.0x speed multiplier (neutral)
- Radius: 2.0m
- Lifetime: 20 seconds
- Instantly cleans overlapping oil/ice surfaces
-
Player Movement (updated
scripts/player/player.gd)- Caches SurfaceDetector component
- Applies speed multiplier to movement
-
Enemy Movement (updated
scripts/enemies/chase_movement_behaviour.gdandranged_movement_behaviour.gd)- Queries SurfaceDetector from enemy parent
- Applies speed multiplier to navigation movement
- SpawnSurfaceEffect (
scripts/items/effects/spawn_surface_effect.gd)- OnDestroyEffect component
- Spawns configurable surface scene when weapon breaks
- Ready for OilFlask integration
You need to create three surface scene files:
scenes/surfaces/OilSurface.tscn:
OilSurface (Node3D) - Script: res://scripts/surfaces/oil_surface.gd
└── MeshInstance3D (puddle mesh, dark brown material)
scenes/surfaces/IceSurface.tscn:
IceSurface (Node3D) - Script: res://scripts/surfaces/ice_surface.gd
└── MeshInstance3D (puddle mesh, light blue material)
scenes/surfaces/WaterSurface.tscn:
WaterSurface (Node3D) - Script: res://scripts/surfaces/water_surface.gd
└── MeshInstance3D (puddle mesh, blue transparent material)
Steps:
- Create new scene (Node3D)
- Attach appropriate script (oil_surface.gd, ice_surface.gd, or water_surface.gd)
- Add MeshInstance3D child
- In MeshInstance3D Inspector:
- Mesh: Load
res://resources/models/Puddles/puddles.fbx(or .blend) - Create new StandardMaterial3D
- Set albedo color (brown for oil, light blue for ice, blue for water)
- Enable transparency if needed (water)
- Mesh: Load
- Export variables will use defaults from script
- Save to
scenes/surfaces/
- Open
scenes/Player.tscn - Add child node (type: Node)
- Attach script:
res://scripts/surfaces/surface_detector.gd - Name it:
SurfaceDetector - Optional: Enable
debug_printin Inspector to see surface changes in console - Save
For each enemy scene:
- Open
scenes/enemies/Enemy.tscn(and any variants) - Add child node (type: Node)
- Attach script:
res://scripts/surfaces/surface_detector.gd - Name it:
SurfaceDetector - Save
Repeat for:
scenes/enemies/RangedEnemy.tscn(if exists)- Any other enemy variants
- Open
scenes/items/OilFlask.tscn - Add child node (type: Node)
- Attach script:
res://scripts/items/effects/spawn_surface_effect.gd - Name it:
SpawnSurfaceEffect - In Inspector, set properties:
surface_scene: Loadres://scenes/surfaces/OilSurface.tscnspawn_offset: Vector3(0, 0.05, 0)
- Ensure OilFlask has
WeaponBehaviourwithmax_durability: 1 - Save
- Open
scenes/RoomTest.tscn - Add OilSurface instance to room (position Y: 0.05)
- Run scene
- Walk player over oil surface
- Check console: Should see "Room: Added surface" message
- Verify player moves slower (speed reduced by ~50%)
- Open
scenes/RoomTest.tscn - Add OilFlask instance to room
- Run scene
- Pick up flask (E key)
- Throw flask (right-click)
- Flask should break on impact
- Oil surface should spawn at break location
- Walk over surface - should slow movement
- Manually add OilSurface (Y: 0.05) to room
- Manually add IceSurface (Y: 0.10) at same XZ position
- Run scene
- Walk over stacked surfaces
- Should feel ICE effect (faster), not oil
- Check console: Should report Ice surface (higher Y wins)
- Add OilSurface to room (position: 0, 0.05, 0)
- Add WaterSurface overlapping it (position: 0, 0.06, 0)
- Run scene
- Water should instantly delete the oil surface
- Check console: "Water surface cleaning OilSurface"
- Add OilSurface to room
- Add Enemy to room
- Run scene
- Lure enemy onto oil surface
- Enemy should move slower on oil
- Add IceSurface to room
- Run scene
- Wait 30 seconds
- Ice surface should disappear (queue_free)
- Check console: "Room: Removed surface"
- Entities move at 50% speed
- Dark brown puddle visual
- Persists until cleaned by water
- Spawned by OilFlask destruction
- Entities move at 120% speed
- Light blue puddle visual
- Lasts 30 seconds then disappears
- TODO: Add sliding/reduced control
- Entities move at normal speed (100%)
- Blue transparent puddle visual
- Lasts 20 seconds then disappears
- Instantly removes overlapping oil/ice
- No scene files yet - Surfaces need to be created in editor with puddle meshes
- No visual effects - No particles on surface entry/exit (future enhancement)
- Ice sliding not implemented - Currently just speed boost (marked as TODO)
- Center point only - Detection checks entity center, not full footprint
- No sound effects - Silent surface interactions (future enhancement)
- Create ice/water flask items with spawn surface effects
- Add particle effects on surface entry
- Implement ice sliding momentum mechanics
- Add surface interactions (fire + oil = burning oil)
- Visual feedback (ripples, footprints, splashes)
- Sound effects (splash, freeze, sizzle)
- Surface spreading mechanics (oil flows, water spreads)
scripts/surfaces/surface_effect.gd✓scripts/surfaces/surface.gd✓scripts/surfaces/surface_detector.gd✓scripts/surfaces/oil_surface.gd✓scripts/surfaces/ice_surface.gd✓scripts/surfaces/water_surface.gd✓scripts/items/effects/spawn_surface_effect.gd✓
scripts/rooms/room.gd✓ (added surface management)scripts/player/player.gd✓ (added surface detection)scripts/enemies/chase_movement_behaviour.gd✓ (added surface effects)scripts/enemies/ranged_movement_behaviour.gd✓ (added surface effects)
scenes/surfaces/OilSurface.tscn⚠️ scenes/surfaces/IceSurface.tscn⚠️ scenes/surfaces/WaterSurface.tscn⚠️
scenes/Player.tscn⚠️ (add SurfaceDetector)scenes/enemies/Enemy.tscn⚠️ (add SurfaceDetector)scenes/items/OilFlask.tscn⚠️ (add SpawnSurfaceEffect)
The system fully supports variable surface radii:
- Each surface has
@export var radius: float = 2.0 - Can be overridden per-instance in Godot editor
- Room query checks:
distance <= surface.radius - Works for all surface types (oil, ice, water)
- Example: Create small oil puddle (radius: 1.0) or large one (radius: 5.0)
- No collision layers needed - Uses pure distance math (Vector2 XZ check)
- Timer-based detection - Entities check every 0.1s, not every frame
- Room ownership - Surfaces are children of Room for persistence
- Effect composition - SpawnSurfaceEffect is reusable for any flask/grenade
- Simple stacking - Highest Y position wins, predictable behavior