Rotations
Before this: Angles, Looping Over a List
The last lesson built a rotator from angles by hand. The game has gates that
work with whole rotations instead: point along a direction, turn a vector,
undo a turn. Most of them use a second rotation type, the quat. This lesson
builds a spotlight that tracks the nearest player in a zone.
Contents
zone "Zone Ref" -> chip room
zone Occupied -> chip occupied
chip aim -> light Rotation
switch Enabled -> light Enabled
Code
@left in room: zone
@left in occupied: bool
var players: character[]
var facing: rotator = Rotation(0.0, 0.0, 0.0)
@right out aim = facing.Value
on Clock(interval = 0.1, enabled = occupied) {
players.fillFromZonePlayers(room)
let here = GetOwnTransform().Location
var nearest: float = -1.0
var target: vector = here
for p in players {
let spot = p.GetLocation()
let d = Distance(here, spot)
if nearest < 0.0 || d < nearest {
nearest = d
target = spot
}
}
if nearest >= 0.0 {
facing = (target - here).ToRotation()
}
}
Ten times a second while someone is in the zone,
players.fillFromZonePlayers(room) fills the list with everyone standing in
it. The loop keeps the closest one, comparing their distances. nearest
starts at -1, so if the list comes back empty it stays there and the light
keeps its last aim.
(target - here).ToRotation() is the whole of the last lesson’s compass math
in one gate: it turns the arrow toward the player into a rotation that points
along it. The answer is a quat, and storing it in the rotator variable
converts it.
Two players stand in the zone, one 300 units away and one 400. Which one does the light follow? What happens when the near one leaves?
Run
- Compile the chip and paste it in-game. Give a brick an Attached Zone covering the area to watch. Place a Spot Light without turning its brick, and put the chip right next to it: the chip measures from its own position, and the beam starts at the light.
- Wire the Attached Zone’s Zone Ref to
roomand its Occupied tooccupied. Wireaimto the Spot Light’s Rotation, and a Switch to its Enabled. - Walk into the zone. The beam follows you. Bring a friend: it switches to whoever is closer, and stays where it last pointed when the zone empties.
Under the Hood
Open the chip. The Clock’s chain runs Get Players In Zone, Get Own
Location and Rotation, and two Set Variable gates for the loop’s
starting values. The For Each Array Entry chip holds a Get Location of
Entity, a Distance, and the Less, OR and Branch
gates of the comparison. After the loop, a Greater/Equal and a
Branch check that someone was found, then a Subtract, one Direction
to Quaternion, and the Set Variable for facing. No gate sits between
the quaternion and the rotator variable: the wire carries either kind.
A quat holds no angles. Its parts are four numbers, .x .y .z .w,
that only mean something together, so asking it for a pitch fails:
@left in dir: vector
@right out tilt = dir.ToRotation().pitch
Error: [WS010] no field `pitch` on quat
dir.ToRotation().ToEuler().Pitch converts first and reads the angle.
Rotator or quat
Both types hold a rotation, and each converts to the other with no gate: pass a rotator to a quat method, or store a quat in a rotator.
Use a rotator for | Use a quat for |
|---|---|
| angles you read or write as numbers | pointing along a direction: dir.ToRotation() |
| pins that take a rotation, such as a Spot Light’s Rotation | turning a vector: v.Rotate(q) |
Rotation(pitch, yaw, roll) and .pitch .yaw .roll | undoing a turn: q.Invert() |
the turn between two directions: a.RotationTo(b) |
The quat gates work on rotators too, so facing.Value.ToDirection() is fine.
Turning vectors
v.Rotate(q) turns the vector v by the rotation q. q.ToDirection() is
the way q points, length 1. q.Invert() is the turn that undoes q.
@left in turret: rotator
@left in offset: vector
let local = offset.Rotate(turret.Invert())
@right out muzzle = Vec(100.0, 0.0, 0.0).Rotate(turret)
@right out inFront = local.x > 0.0
@right out onRight = local.y > 0.0
Vec(100.0, 0.0, 0.0)is 100 units along x, the way a rotation of zero points. Turned byturret, it is 100 units along the turret’s aim: the same asturret.ToDirection() * 100.0.offsetis an arrow in world directions, such as from the turret to a player. Turning it by the inverse undoes the turret’s turn and gives the arrow in the turret’s own directions:xahead,yto its right,zup. A positivelocal.xmeans the player is in front of the turret.
a.RotationTo(b) is the turn that carries direction a onto direction b,
so a.Rotate(a.RotationTo(b)) points along b.
q.ToAxisAngle().Angle is how far a turn goes, in degrees, and
a.AngleTo(b) is the angle between two rotations, also in degrees.
Modify
- Watch the turn. Add
var shown: string = ""and@right out readout = shown.Value. In theif, computelet wanted = (target - here).ToRotation(), setshown = "Turned ${round(facing.AngleTo(wanted)) as int} degrees", and thenfacing = wanted. Walk sideways across the beam and the number grows. - Mount the light on a wall, so it should never aim behind itself. Read the
chip’s own rotation with
let own = GetOwnTransform()(thenown.Locationandown.Rotation), and in the loop skip players behind the chip: computelet local = (spot - here).Rotate(own.Rotation.Invert())and addlocal.x > 0.0 &&to theif. Turn the chip and see which side it guards. - Show where the beam lands 300 units out: add
here + facing.Value.ToDirection() * 300.0to the sign. Stand still and compare it with your own position.
Make
Make a security camera. When the zone is empty, the Spot Light sweeps slowly
left and right, a few degrees of yaw per Clock tick. When a player comes
within 30 degrees of where it points (use Dot from
Dot and Cross), it locks on and follows them, and it goes
back to sweeping when they leave.
zone "Zone Ref" -> chip room
zone Occupied -> chip occupied
chip aim -> light Rotation
switch Enabled -> light Enabled
Good to Know
- The beam snaps to each new aim. For a light that swings smoothly, see
Blending Values and
Over Time:
BlendandTweentake rotations too. a * bon two rotations combines the two turns into one. See Arithmetic Operators.axis.RotationByAngle(angle)is a turn byanglearoundaxis, such asVec(0.0, 0.0, 1.0).RotationByAngle(90.0)for a quarter turn about the up axis. The game’s gate takes the angle in degrees.- A player’s location is a point on their body, so the beam aims at their middle, not their feet.
ToRotationon a zero-length arrow has no direction to point along. If a player can stand exactly on the chip, check the distance before aiming.
See Rotation / Quaternion and Zone array fills in the reference.
Next: pick a lesson from the tree on the Learn page.