►
Description
Steve has been building side projects in rust since 2016, with a focus on computer graphics and game development.
He has entered the 7-Day Roguelike game jam with rust each year since then and he maintains a collection of crates for building traditional roguelikes.
A
A
A
They
run
in
graphical
Windows
because
I'd
like
people
who
don't
use
Unix
terminals
to
be
able
to
play
them,
but
the
graphics
are
made
entirely
of
characters
and
so
I've
got
I've
built.
This
Library
called
chargrid,
which
abstracts
away
the
specific
run
time
that
the
game's
running
on
and
just
gives
the
the
game,
an
interface
to
rendering
grids
of
characters
and
also
getting
IO
from
the
different
places
you
can
play
these
games
on
Windows,
Max
and
Linux
and
in
a
web
browser
and
in
a
terminal.
A
But
in
order
to
make
your
game
Run
in
all
of
these
different
environments,
one
of
the
constraints
is
that
the
flow
control
that
the
engine
uses
has
to
be
entirely
tick.
Based,
there's
no
way
to
spawn
a
new
thread
and
weigh
it
because
in
webassembly,
which
is
what's
used
to
make
the
game
Run
in
a
browser.
There's
no
mechanism,
or
at
least
the
mechanism,
is
different
enough
from
native
threads.
That
there's
not
really
a
nice
way
to
provide
like
a
Threading
API
to
chagrid.
A
So
this
means
that
all
the
games
have
a
giant
loop
around
the
outside
handled
by
the
runtime
that
just
progresses
and
iteratively
takes
the
state
machine
to
update
the
game
state
to
do
all
the
rendering
and
so
on,
and
it
turns
out
that
programming
in
an
entirely
tick-based
environment
is
a
little
unpleasant.
A
It's
often
the
case
that
you'll
want
to
sequence.
Events
like
pop-up
a
menu
have
the
player
choose,
say
an
upgrade
over
the
character
or
something
from
that
menu.
Prompt.
That
says
like,
are
you
sure,
and
then
they
press
Y,
and
then
the
game
continues
or
something
like
that
some
sort
of
sequential
operation,
but
in
a
tick-based
environment,
all
you
can
really
do
is
add
additional
states
to
a
state
machine,
and
this
quickly
gets
out
of
hand.
A
So
I'm
going
to
describe
a
solution
that
I
came
up
with
with
this
problem,
which
takes
the
form
of
a
pseudosynchronous
domain,
specific
language
embedded
in
Rust.
That
allows
you
to
write
code
that
looks
like
synchronous
blocking
code,
but
actually
generate
State
machines
that
can
be
executed
in
affiliate
fully
tick-based
environment.
A
So
this
is
the
common
interface
that
all
of
the
components
of
one
of
my
like
games,
Implement,
I,
say
game.
It's
more
like
the
game.
Ui
right,
like
the
menus,
like
buttons
there'll,
be
one
of
these
for
the
game
itself,
but
it'll
be
kind
of
this
opaque
blob
surrounding
some
custom
code
made
for
the
game.
So
every
component,
maybe
a
good
example-
would
be
a
menu.
Every
component
has
some
kind
of
output.
It
can
compute
a
result.
A
So,
in
the
case
of
the
menu
That's
The
Selection
that
the
user
made
from
the
menu,
the
component
can
be
rendered,
which
just
populates
a
frame
buffer
and
the
component
can
be
ticked
or
updated,
which
feeds
some
input
event
to
the
component
and
allows
it
to
update
its
internal
State
and
to
produce
some
output
as
its
output,
so
I,
and
this
this
happens
on
every
frame,
so
I
suppose
I
should
clarify
that
for
a
menu.
The
output
is
not
just
the
choice.
The
choice
that
the
user
selected.
A
It's
also
it's
an
optional
choice
because
on
all
the
frames
where
they
don't
make
a
selection,
you
start
to
produce
some
value.
So
it'll
just
be
done
in
those
cases,
so
let's
have
a
motivating
example.
This
is
a
little
game.
This
game
exists,
it's
not
it's
not
very
fun,
but
it
does
procedurally
generate
levels
and
you
can
go
down
the
stairs
and
see
new
levels.
A
It's
endless,
you
can't
win,
you
can't
lose,
but
you
can
open
a
menu
and
that's
an
interesting
academic
exercise,
because
now
we
have
to
maintain
the
state
of
the
menu
and
the
state
of
the
game
at
the
same
time
and
you
can
choose
an
item
from
the
menu
and
if
you
choose
quick,
the
game
ends.
If
you
choose
re
new
game,
the
game
restarts.
A
So
let's
look
at
how
one
might
Implement
something
like
this
using
chagrid.
So
here's
the
component
that
represents
the
game
I
mean
the
only
really
interesting
thing
here.
Is
the
game
output
so
we're
going
to
say
that
on
every
frame
the
game
either
produces
no
output
like
none
or
the
game's
over,
which
is
impossible,
but
you
know
pretend
or
Escape
was
pressed,
so
we
want
if
the
game's
running
and
the
user
presses
Escape,
we
want
to
be
able
to
say:
oh,
like
stop.
A
The
game
they
press
Escape,
like
let's,
show
a
menu.
Instead,
when
that
happens,
we
show
a
menu.
This
is
a
venue,
it's
got
three
choices,
resume
new
game
and
quit,
and
similarly
on
every
frame
it's
got
to
produce
an
output,
so
it'll
be
done.
A
If
no,
if
the
entity
was
impressed,
if
the
user
presses
like
up
or
down,
we
want
to
change
which
one
the
current
selection
is
so
internal
to
this
menu
type
like
its
implementation,
might
just
have
like
an
integer
value
that
tracks
the
current
selection
say
and
like
the
names
of
all
of
the
options
and
then
update's
gonna
pick
which
I
update
internal
State
and
return
none
if
they
press
down
or
up,
say
and
return
some
value,
if
they
pressed
I,
don't
know,
maybe
enter
or
click
them
one
all
right.
A
So
that
was
pretty
straightforward
and
that
seemed
completely
fine.
The
problem
starts
to
arise
when
we
have
multiple
sort
of
high
level
components
that
we're
trying
to
Multiplex
between.
So
one
way
of
doing
that
would
be
just
by
explicitly
implementing
a
state
machine
like
I've
done
here,
so
the
app
has
two
states
game
and
menu,
and
when
the
game
is
running,
we
are
in
the
game
State,
and
we
forward
all
the
input
events
to
the
game.
We
render
the
game
likewise
from
menu.
A
This
isn't
completely
accurate,
because
if
in
in
this
implementation,
if
then
you
were
selected,
the
game
object
gets
trashed
unless
we
save
it
somewhere,
but
we
want
to
be
able
to
stash
it
somewhere
for
a
few
juice.
That's
handled,
there's
how
that's
good
for
this
talk,
so
some
problems
with
this
approach.
A
The
big
problem
is
that
this
logic,
this
Logic
for
traversing,
the
state
machine,
is
duplicated,
and
this
is
maybe
fine
for
a
simple
thing
like
this,
but
if
we
start
adding
more
menus
or
having
like
sequences
of
menus
that
are
displayed
one
after
the
other,
this
quickly
gets
out
of
hand
and
they'll
get
out
of
sync
and
it'll
become
a
nightmare
to
keep
them
in
sync
as
you're
adding
features,
one
of
the
main
things
I
use
this
engine
for
is
game
jams,
and
you
don't
want
to
have
to
spend
ages
around
with
messing
around
with
with
State
machines
in
the
middle
of
your
game,
Jam
when
you're
running
out
of
time.
A
The
other
problem
with
this
is
that
it's
just
a
little
bit
tedious
when
you
want
to
describe
a
sequential
sequence
of
events
in
state
machines
like
if
I
want
to
add,
like
an
are
you
sure,
dialogue
after
the
new
game
button
is
chosen
here,
I
need
to
add
a
whole
another
state
wire
it
into
all
the
different
functions
that
Traverse
the
state.
There's
no
static
checks
that
I've
done
it
correctly
and
like
it's,
it's
just
a
bit
of
a
mess
like
no.
No
one
enjoys
that
kind
of
programming
right.
A
So
ideally
that'd
be
a
game
loops
the
rates
forever
and
runs
the
game
until
either
the
game's
over
or
Escape
is
pressed
and
then,
if
Escape
was
pressed,
it
shows
the
menu
and
then
that
effectively
blocks
until
the
choice
is
made
and
then
we
handle
the
choice
and
then,
if
the
choice
keeps
the
program
running,
we
repeat
right,
that's
nice,
but
as
I
said
at
the
beginning
of
the
talk,
this
would
require
some
sort
of
blocking
flow
control,
which
is
not
really
an
option
for
us
if
we're
trying
to
be
across
the
platform
so
instead
Char
grid
now
has
an
API
called
Echo
control
flow
which
allows
you
to
write
code
kind
of
like
this.
A
So
structurally,
it's
quite
similar
to
the
synchronous
version
on
the
previous
slide.
There's
an
outer
loop.
It
runs
the
game
until
the
game
yields
control
back
to
the
outer
loop,
at
which
point
we
check
what
the
reason
was
for
exiting
the
game
and
if
it
was
Escape
being
pressed,
we
do
a
similar
thing
with
the
menu
and
then
we
handle
the
selection
from
the
menu
and
then
you'll
note
these
break
and
continue
statements,
and
now
just
values
like
in
the
domain.
A
Specific
language
and
loop
is
just
a
function
instead
of
a
control
structure
and
the
the
important
I
guess
takeaways
from
this
slide,
that
sort
of
make
the
whole
thing
work
the
combinators
and
then
and
map
there.
It
is
so
if
you're
familiar
I
mean
this
is.
This
is
a
very
similar
idea
to
your
futures
say
we
have
these.
These
values
that
represent
computations
that
that
we
can
sequence
additional
computations
onto
this
is
also
if,
if
you're
from
a
functional
background,
this
is
a
monad
I
promise.
A
I
won't
say
that
word
again
or
try
to
explain
what
it
means.
So,
let's
take
a
look
under
the
hood.
This
is
a
very
tiny
snippet
of
the
implementation
of
the
control
flow
API.
So
it
adds
this
wrapper
CF,
which
stands
for
control
flow
which
just
wraps
the
component
and
adds
a
bunch
of
additional
methods,
these
combinators
for
sequencing
and
doing
computations
on
the
results
of
of
components,
and,
let's
see
what's
worth
talking
about
here,
I
mean
really
the
this
is
this.
This
is
just
an
implementation.
A
All
the
combinators
really
just
return
return
values
of
these
structs
like
and
then,
and
then
on
that
influence
components
and
then
is
a
component
that
composes
additional
components
that
to
compute
perform
computations
on
the
results
of
other
components
and
that
that
concludes
the
talk,
so
that
was
a
very,
very
high
level
overview
of
the
control
flow
API
in
charge
which
solves
the
problem
of
managing
State
machines
for
you
in
a
pseudosynchronous,
looking
embedded
domain
specific
language.
A
If
you
want
to
check
out
some
of
the
games
that
I've
made
that
use
chagrid,
you
can
go
to
my
hio
just
here
or
you
can
follow
me
on
Twitch,
which
I,
occasionally
program
stream,
myself,
programming
gains
in
Rust,
usually
in
checkered,
or
you
can
check
out
the
chagrid
source
code
on
my
GitHub
all
right.
Thank
you.
A
Let
the
rice
interesting
yeah,
the
the
question
was:
if
I
had
considered
writing
a
custom
derive
for
the
type
that
would
give
some
sort
of
like
traversal
code
generated
automatically.
The
answer
is
no
I
hadn't
thought
I've
had
that
at
all.
It's
a
great
idea,
I'll
think
more
about
that.
Yeah.
A
So
the
question
was,
if
I
considered
using
Futures
instead
of
implementing
my
own
or
re-implementing
the
same
basic
idea
and
just
pulling
the
future
instead
of
calling
update
and
you're
right.
This
is
something
that
I
had
considered.
I
I
came
up
with
this
idea
when
I
was
doing
a
lot
of
functional
programming
that
like
with
with
with
features
basically
and
thought,
hey
like
this
sounds
like
a
good
fish
with
this
problem.
A
I
thought
about
implementing
my
own
custom
Futures
runtime
for
chargrid,
but
it
seemed
like
I
would
have
to
write
a
lot
of
unsafe
code
and
I
was
just
a
little
bit.
Scared
of
that
definitely,
and
also
it
would
be
I
elected
not
to
explore
that,
because
currently
I
like
how
explicit
everything
is
and
there's
sort
of
no
Global
magic.
That
makes
the
thing
run
and
I
thought
this
was
a
few
years
ago.
A
I
haven't
really
Revisited
it
since,
but
I
thought
that
I
would
have
to
do
some
sort
of
global
magic
in
order
to
make
it
like
ergonomic
to
program
like
this
with
Futures
but
yeah
like
it's
a
very
valid
idea
like
it's
definitely
something
worth
considering.