Distance and Direction
Before this: Vectors and Colors, Reacting to the Game
Next steps: Dot and Cross
Every position in the world is a vector: three numbers, x, y and z.
Subtract two positions and you get the arrow from one to the other, with a
length (how far) and a direction (which way). This lesson builds a light that
brightens as a player walks toward it.
Contents
zone "Zone Ref" -> chip room
zone Occupied -> chip occupied
chip brightness -> light Brightness
chip readout -> decal Text
zone Occupied -> light Enabled
Code
const RANGE = 500.0
@left in room: zone
@left in occupied: bool
var visitor: character
var glow: float = 0.0
var shown: string = ""
@right out brightness = glow.Value
@right out readout = shown.Value
on ZoneEntered(zone = room) -> (character) {
visitor = character
}
on Clock(interval = 0.1, enabled = occupied) {
let here = GetOwnTransform().Location
let there = visitor.GetLocation()
let d = Distance(here, there)
glow = clamp(1.0 - d / RANGE, 0.0, 1.0) * 4.0
shown = "${round(d) as int} units away"
}
var visitor: character remembers the player who last walked into the zone.
Ten times a second, while someone is inside, the Clock handler measures:
GetOwnTransform().Locationis where the chip’s own brick is.visitor.GetLocation()is where the player is.Distance(here, there)is how far apart the two points are, in the game’s units.
d / RANGE is 0 at the chip and 1 at 500 units away, so 1.0 - d / RANGE
runs the other way: 1 up close, 0 at the edge. clamp(..., 0.0, 1.0) keeps it
from going below 0 farther out, and * 4.0 turns it into a brightness from 0
to 4. round(d) rounds to the nearest whole number and as int makes it an
int, so the sign shows no decimals.
A player stands 125 units from the chip. How bright is the light? And at 600 units?
Run
- Compile the chip and paste it in-game. Give a brick an Attached Zone big enough to walk around in, and put the chip inside it. Place a Point Light and a brick with a Text Decal near the chip.
- Wire the Attached Zone’s Zone Ref to
room, and its Occupied tooccupiedand to the Point Light’s Enabled. - Wire
brightnessto the Point Light’s Brightness, andreadoutto the Text Decal’s Text. - Walk into the zone and toward the chip. If you were already inside when
you pasted the chip, step out and back in:
visitoris set when someone enters. The light grows brighter and the sign counts down. At 125 units the brightness is 3, at 250 it is 2, and from 500 units out it is 0. Leave the zone and the light goes off.
Under the Hood
Open the chip. The Clock starts a chain: Get Own Location and
Rotation for the chip’s position, a Get Variable for visitor, and
Get Location of Entity for the player. One Distance gate takes the two
positions. After it come a Divide, a Subtract, a Clamp and a
Multiply for the brightness, a Round, a Convert and a Format
String for the sign, and two Set Variable gates.
A distance is a number and a position is a vector, and the two cannot be compared. Asking whether the arrow between them is short fails to compile:
@left in here: vector
@left in there: vector
@right out near = there - here < 500.0
Error: [WS004] no overload for '<' on vector, float
Measure the arrow first, with Magnitude or Distance, and compare the
number.
Arrows between points
there - here subtracts part by part and gives the arrow from here to
there. With here at Vec(0.0, 0.0, 0.0) and there at
Vec(300.0, 400.0, 0.0), the arrow is Vec(300.0, 400.0, 0.0).
Magnitude(there - here)is the arrow’s length: 500.Distance(here, there)is the same number in one gate.Normalize(there - here)keeps the direction and makes the length 1:Vec(0.6, 0.8, 0.0). A length-1 vector is a pure direction.- A direction times a distance gives the arrow back:
Vec(0.6, 0.8, 0.0) * 500.0isVec(300.0, 400.0, 0.0). Sohere + Normalize(there - here) * 100.0is the point 100 units fromhereon the way tothere.
These also work as methods: (there - here).Magnitude(),
here.Distance(there). DistanceSq and MagnitudeSq give the same values
squared.
Modify
- Show which way the chip lies from the player. Add a second line to the sign:
shown = "${round(d) as int} units away<br>${Normalize(here - there)}".<br>starts a new line, and a vector shows asX=... Y=... Z=.... - Add a door that opens only within 200 units. Add
const CLOSE = 200.0,var near: bool = falseand@right out open = near.Value, and in the handlernear = Distance(here, there) < CLOSE. - Measure along the floor only, so a player on a balcony above the chip
reads as close as one standing beside it. Flatten both points first:
Distance(Vec(here.x, here.y, 0.0), Vec(there.x, there.y, 0.0)).
Make
Make a “warmer, colder” sign for a hidden prize. The chip is the prize. Each
sample, compare the distance with the one from the sample before (keep it in
a var) and show Warmer when the player got closer, Colder when they
moved away, and Found it! within 50 units.
zone "Zone Ref" -> chip room
zone Occupied -> chip occupied
chip readout -> decal Text
Good to Know
- Distances are in the game’s units (Unreal units). A 1x1 brick is 10 units wide, so 500 units is 50 studs.
- A player’s location is a single point on their body, so standing right on the chip still reads a small distance.
visitoris whoever walked in last. With two players in the zone, the light follows the newer one. Reading every player in the zone takes a loop: Looping Over a List.Normalizeof a zero-length vector has no direction to keep. Check the distance before you use a direction between two points that may meet.
See Vector in the reference.
Next: Dot and Cross.