Steve's Roc Apps roc-apps on GitHub

Safari Ride Chapters

Chapter 24

The ride instant

A moment carries four things: the rider, the truck, the clock, and the plan for when the cat or the bird ahead starts to move. A step makes the next moment from this one. This chapter explains that step, then groups the ride's moving parts by how they change.

One step §

Here's the step, whole:

RideInstant.roc
## The instant a step after `instant`. The world and the rider change each
## other within one step, in this order. First the rider reads the world as it
## stands at the old clock: the stage of the encounter on the rider's segment.
## Then the rider steps, and the clock ticks. Then the world answers the rider
## that has just moved. The truck aims at how far along the route this step's
## rider is, and the encounter plan is kept, forgotten at a new segment, or made
## from this step's rider at the new clock. The rider never reads the truck.
next : Route, RideInstant -> RideInstant
next = |route, instant| {
	stage_before = RideInstant.encounter_stage(route, instant)
	rider = instant.rider.rider_at_next_step({ route, encounter_stage: stage_before })
	clock = instant.clock.next()
	rider_place = rider.motorcycle.route_place
	truck = TruckJourney.truck_progress_at_next_step(
		instant.truck,
		{ rider_distance: rider_place.distance_along(route), route },
	)
	segment_change =
		if rider_place.segment_index == RideInstant.rider_segment_index(instant) {
			SameSegment
		} else {
			NewSegment
		}
	encounter_plan = instant.encounter_plan.plan_at_next_step({
		segment_change,
		approach: encounter_approach(rider_place.segment_on(route).encounter, rider.motorcycle),
		now: clock,
	})
	{ rider, truck, clock, encounter_plan }
}

next_or_restart, from the “Immutable values: a flip book” chapter, calls this step until the rider reaches the end of the road. The doc comment on next gives the order, and the order matters. The rider moves first, reading where the encounter ahead has got to. Then the clock ticks. Then the world answers the rider who has just moved: the truck aims at how far along the route the rider now is, and plan_at_next_step keeps the encounter plan, drops it at a new segment, or makes one from this step's rider. The last line puts the four together into the next moment, and the old moment stays as it was.

The rider reads the encounter as a stage, where its animation has got to:

Animation.roc
## Where an animation has got to: not begun, playing and this many steps in,
## which is the frame it shows, or over this many steps ago.
Stage : [Waiting, Playing(Steps), Past(Steps)]

Waiting comes before the animation starts, Playing counts the steps in, and Past counts the steps since it ended. The “The cat” chapter shows how the plan and the clock make one.

Carried and derived §

Those four fields are all the ride carries from one step to the next. The ride derives everything else in a frame from them and the road, afresh for each frame. So the ride's moving parts come in three kinds:

Kind Things How it changes
Clock-driven The sun's height, the sky, the beacons Derived from the clock, and for a beacon its tower
Stepped The rider, the truck Carried in the moment, and moved on once a step by its step function
Rider-driven The cat, the bird Derived from the clock and the carried plan, which the rider's approach sets

The trees and the cows stay put.

Clock.next, Rider.rider_at_next_step and TruckJourney.truck_progress_at_next_step all have the same shape: a value goes in, and the next value comes out. Call that a step function. Set beside the clock-driven kind, stepping has a cost:

So the stepped parts need the most care.

The clock-driven things come next, and the beacons are the simplest of them: they follow the clock and their towers.