Last updated on
hotpotato Example
This example demonstrates how to use the ClockDrivenStateMachine provided by the library. It enables you to simulate a continuous, time-based game instead of relying solely on discrete player actions.
In the hotpotato game, a player starts holding a potato. The longer they keep it, the more points they earn. However, after a random amount of time, the potato will explode, turning into rösti. The player holding the potato at that moment loses a significant number of points.
ClockDrivenStateMachine
To use the clock, your Logic class needs to extend ClockDrivenStateMachine
class Logic extends ClockDrivenStateMachine[Event, State, View]:
webapp-examples/apps/jvm/src/main/scala/apps/hotpotato/Logic.scala
This requires defining two fields:
override val clockPeriodMs: Int = 100 // How frequently we want to receive the clock tick events in ms
override val clockDrivenWire: AppWire[Event, View] = hotpotato.Wire // The wire of our app
webapp-examples/apps/jvm/src/main/scala/apps/hotpotato/Logic.scala
Your transition function will now take an event of type Either[Tick, Event], instead of Event. This will allow you to handle the Tick events as well as your regular events.
override def transition(state: State)(
userId: UserId,
event: Either[Tick, Event]
): Try[Seq[Action[State]]] =
webapp-examples/apps/jvm/src/main/scala/apps/hotpotato/Logic.scala
For example, in our transition function, we separately handle cases where a Tick or an Event is received.
event match
case Left(Tick(_)) =>
if timer - clockPeriodMs <= 0 then
goToNextRound(state, holder)
else
Seq(Render(state.copy(
scores = state.scores.updatedWith(holder)(prevScore => Some(prevScore.get + 1)),
phase = Phase.Playing(holder, timer - clockPeriodMs)
)))
case Right(Event.Pass) =>
if holder == userId then
val players = state.scores.keys.toList.sorted
Seq(Render(state.copy(
phase = Phase.Playing(holder = pickNextPlayer(players, holder), timer = timer)
)))
else Seq()
webapp-examples/apps/jvm/src/main/scala/apps/hotpotato/Logic.scala
Pictures
This example also includes a picture. If you want to use any kind of picture file, you can wrap it in a img element. You need to put all your images in the apps/jvm/src/main/resources/www/static directory, similar to thumbnails.
Then the src attribute of the img element needs to be /static/<my_image>
img(
src := "/static/rosti.png",
alt := "Rosti!",
cls := "rosti-image"
)
webapp-examples/apps/js/src/main/scala/apps/hotpotato/UI.scala