Wall - BenBerke/Tilky-Engine GitHub Wiki
Wall
A wall is one straight edge of a sector's outline, from a start point to an end point on the map. Walls aren't drawn separately: they appear automatically when you draw sectors, one for every edge.
What a wall looks like in the game depends on the sectors on its two sides:
| Sides | Result |
|---|---|
| Sector on one side only | A solid wall from that sector's floor to its ceiling. |
| Sectors on both sides | An opening (a portal) between the two rooms. Solid pieces are drawn only where the two rooms don't overlap in height: a step up, a lintel over a doorway, the face of a raised platform. |
So you never make a "doorway wall". You make two sectors with different floor or ceiling heights next to each other, and the wall between them fills in the difference.
Front and back
Every wall has a direction, from start to end. Looking down on the map:
- the front sector is on the left side of that direction;
- the back sector is on the right side;
normalpoints toward the front (left) side.
A one-sided wall has only one of them set; the other is invalid (4294967295).
Top, bottom and middle textures
A wall has three textures, Top, Bottom and Middle, each with its own offset, scale, flip and anchor.
- A solid wall (a sector on one side only) shows only Top. The inspector calls it Texture.
- A portal shows Bottom on the step under the neighbouring room's floor, and Top on everything else: the wall above the neighbour's ceiling, and any slab between two of its floors.
- Middle fills a portal's openings, where both rooms are open space: fences, bars, grates, windows. It always fills the whole opening (each one, when stacked floors leave several), follows sloped floors and ceilings, and is one surface seen from both sides. Transparent pixels show through. With no Middle texture there is nothing in the opening at all. Solid walls have no openings, so their Middle fields are greyed out.
A Middle has two switches of its own:
| Switch | Default | Effect |
|---|---|---|
| Has Collision | on | Blocks entity colliders like a solid wall. |
| Ignored by Raycast | off | Raycasts pass through it: script raycasts, LineOfSight, and clicking it in the runtime editor. |
Anchor
The anchor is the height a texture is pinned to. When a floor or ceiling moves, a texture pinned to the moving edge moves with it; otherwise the edge slides over a texture that stays put.
| Anchor | Lua | Pinned to |
|---|---|---|
| Auto | WallAnchor.Auto |
The top edge, except the wall above a neighbour's ceiling, which uses its bottom edge. Doors and lifts carry their textures with them. |
| Top Edge | WallAnchor.TopEdge |
The piece's top edge. |
| Bottom Edge | WallAnchor.BottomEdge |
The piece's bottom edge. |
| World | WallAnchor.World |
World height 0. The texture never moves; use it for door tracks or to line up neighbouring walls. |
The offset is added on top of the anchor. Textures read upright from both sides of a wall.
Collision
Physics tests entity colliders against the solid parts of each wall. An opening is passable as long as the entity fits through the gap, unless it has a Middle texture with Has Collision on. If the solid part in the way is a low step at the entity's feet, and it is no taller than its collider's Step Size, the entity steps up onto it instead of being blocked. See Collider.
In the editor
| Field | Lua | Notes |
|---|---|---|
| Name | Editor only. Scripts can't read it. | |
| Front Sector / Back Sector | frontSector / backSector |
Set by the map topology. Read-only. |
| Texture (solid) / Top, Bottom (portal) | topTexture, bottomTexture |
Texture drawn on the solid parts. Empty means colour only. |
| Middle (portal) | middleTexture |
Texture in the openings. Empty means nothing is there. |
| Wall Color | color |
Tint, Vector4, 0..1 per channel. |
| UV Offset | topTextureOffset, bottomTextureOffset, middleTextureOffset |
Shifts the texture, in map units: 32 moves it by one repeat at scale 1. |
| UV Scale | topTextureScale, bottomTextureScale, middleTextureScale |
How many times the texture repeats. 2.0 means twice as many repeats. |
| Flip U / Flip V | Mirror the texture horizontally or vertically. Editor only. | |
| Anchor | topAnchor, bottomAnchor, middleAnchor |
See Anchor. Auto is the top edge for Middle. |
| Has Collision / Ignored by Raycast | middleHasCollision, middleIgnoredByRaycast |
Middle only. See above. |
| Tags | HasTag, GetTag, tagCount |
Read-only from scripts. |
The sector's light also darkens the wall (see Sector).
Scripting
Getting a wall
| Where from | How |
|---|---|
| A public field | public Wall switchWall |
| A sector | sector:GetWall(i), i from 1 to sector.wallCount |
| A raycast hit | hit.wall, when hit.type == "Wall" |
A Wall value is a safe handle. If the wall stops existing (the map was edited), isValid becomes
false and any other use raises an error. sector:GetWall(i) can also return an invalid wall, so
check isValid.
Properties
| Property | Type | Description | |
|---|---|---|---|
id |
integer | read-only | Stable wall ID. |
isValid |
boolean | read-only | false if the wall no longer exists. |
start |
Vector2 | read-only | Start point (x, z). |
end |
Vector2 | read-only | End point (x, z). end is a Lua keyword, so write wall["end"]. |
dir |
Vector2 | read-only | Unit vector from start to end. |
normal |
Vector2 | read-only | Unit vector perpendicular to the wall, pointing to the front side. |
length |
number | read-only | Length in map units. |
frontSector |
integer | read-only | ID of the front sector. |
backSector |
integer | read-only | ID of the back sector. |
isPortal |
boolean | read-only | true if there is a sector on both sides, so bottomTexture can show. |
color |
Vector4 | read/write | Tint, 0..1. |
topTexture |
string | read/write | Top texture path relative to Assets, e.g. "Textures/brick.png". |
bottomTexture |
string | read/write | Bottom texture path. Only shows on a portal. |
topTextureOffset |
Vector2 | read/write | Top texture shift in map units. Change it over time to scroll. |
bottomTextureOffset |
Vector2 | read/write | Bottom texture shift in map units. |
topTextureScale |
Vector2 | read/write | Top texture repeats per 32 map units. |
bottomTextureScale |
Vector2 | read/write | Bottom texture repeats per 32 map units. |
topAnchor |
WallAnchor | read/write | Where the top texture is pinned, e.g. WallAnchor.World. |
bottomAnchor |
WallAnchor | read/write | Where the bottom texture is pinned. |
middleTexture |
string | read/write | Middle texture path, filling the openings. "" means no middle. |
middleTextureOffset |
Vector2 | read/write | Middle texture shift in map units. |
middleTextureScale |
Vector2 | read/write | Middle texture repeats per 32 map units. |
middleAnchor |
WallAnchor | read/write | Where the middle texture is pinned. |
middleHasCollision |
boolean | read/write | The middle blocks entity colliders. |
middleIgnoredByRaycast |
boolean | read/write | Raycasts and LineOfSight pass through the middle. |
tagCount |
integer | read-only |
Methods
| Method | Returns | Description |
|---|---|---|
ClearTopTexture() |
Removes the top texture. | |
ClearBottomTexture() |
Removes the bottom texture. | |
ClearMiddleTexture() |
Removes the middle texture, and with it the middle. | |
HasTag(tag) |
boolean | true if the wall has tag. |
GetTag(index) |
string | The index-th tag, 1-based. |
Any image in
Assetscan be switched to. When the level loads, the engine packs every.png,.jpgand.jpegfile underAssetsinto the texture atlas, so a script can switch to an image the level doesn't use yet. An image added toAssetswhile the game is running is only picked up the next time the level loads.
Getting the sector on each side
frontSector and backSector are IDs, not Sector values. To get the sector itself, look up a
point just off the wall's middle:
local function SideSector(wall, side) -- side = 1 for front, -1 for back
local s, e = wall.start, wall["end"]
local mid = Vector2((s.x + e.x) * 0.5, (s.y + e.y) * 0.5)
return Game.GetSectorAt(mid + wall.normal * (0.5 * side))
end
In a sector script, the neighbour behind a wall is also in sector:GetNeighbor(i).
Walls have no callbacks
Walls can't hold scripts. To react to a wall, use a sector script on one of its sectors, or a raycast from an entity script.
Examples
Scrolling texture
-- Scripts/Walls/Scroll.lua (sector script)
-- Scrolls every wall of this sector that has the "conveyor" tag.
public Vector2 speed = Vector2(0.5, 0)
local walls = {}
function Start()
for i = 1, sector.wallCount do
local wall = sector:GetWall(i)
if wall.isValid and wall:HasTag("conveyor") then walls[#walls + 1] = wall end
end
end
function Update()
local step = speed * GameTime.deltaTime
for _, wall in ipairs(walls) do
wall.topTextureOffset = wall.topTextureOffset + step
end
end
Switch that changes texture when used
-- Scripts/Walls/WallSwitch.lua (on the player)
-- Look at a wall tagged "switch" and press E to flip it.
public number reach = 48
public Texture onTexture = nil
public Sector door = nil
function Update()
if not Input.GetKeyDown(Key.E) then return end
local camera = entity.camera
if camera == nil then return end
local hit = camera:Raycast(reach, false)
if hit == nil or hit.wall == nil or not hit.wall:HasTag("switch") then return end
-- An unassigned Texture field is an empty string, not nil.
if onTexture ~= nil and onTexture ~= "" then hit.wall.topTexture = onTexture end
if door ~= nil then door:MoveCeilingTo(1, door.floorHeight + 40, 60) end
end
Flash every wall in a room
-- Scripts/Walls/Alarm.lua (sector script)
public Vector4 flashColor = Vector4(1, 0.2, 0.2, 1)
local walls = {}
local original = {}
local t = 0
function Start()
for i = 1, sector.wallCount do
local wall = sector:GetWall(i)
if wall.isValid then
walls[#walls + 1] = wall
original[#original + 1] = wall.color
end
end
end
function Update()
t = t + GameTime.deltaTime
local k = (mathT.Sin(t * 6) + 1) * 0.5
for i, wall in ipairs(walls) do
wall.color = mathT.Vector4Lerp(original[i], flashColor, k)
end
end