module Interp_types:sig
..end
Interp
.Interp
.typeposition =
float * float
(x, y)
.type'a
table =('a Bulletml.Syntax.id * 'a) list
actionRef
, etc).type 'a
linear_map = {
|
frame_start : |
|
frame_end : |
|
val_start : |
|
val_end : |
frame_start
, its value is val_start
.frame_end
, its value is val_end
.type
opcode =
| |
OpRepeatE of |
(* | Repeat times the same Syntax.action | *) |
| |
OpWaitE of |
(* | Wait frames (unevaluated form) | *) |
| |
OpWaitN of |
(* | Wait frames (evaluated form) | *) |
| |
OpFire of |
(* | Fork execution by creating a new Interp_types.obj | *) |
| |
OpSpdE of |
(* | Change speed (unevaluated form) | *) |
| |
OpSpdN of |
(* | Change speed (evaluated form) | *) |
| |
OpDirE of |
(* | Change direction (unevaluated form) | *) |
| |
OpDirN of |
(* | Change direction (evaluated form) | *) |
| |
OpAccelE of |
(* | Accelerate (unevaluated form) | *) |
| |
OpAccelN of |
(* | Accelerate (unevaluated form): h, v, term | *) |
| |
OpVanish |
(* | Let the bullet disappear | *) |
| |
OpCall of |
(* | Call an indirect action with parameters | *) |
Interp_types.obj
.
Some cases have an both an unevaluated form and an evaluated form. This is because it is necessary to delay the evaluation as late as possible, and having a convenient form for computations in progress.
For example, OpWaitX
. Evaluating Wait (Param 1)
will create a OpWaitE
(Param 1)
(as is in the opcode list). When it is time to handle the opcode, it
will be replaced by OpWaitN 3
(if we are in a context where $1 = 3
). At the
next frame it will be OpWaitN 2
, etc.
Some cases have a "term", it is the number of frames in which the evolution
will be done in the corresponding Interp_types.linear_map
.
type
obj = {
|
prog : |
(* | Behaviour | *) |
|
speed : |
(* | In pixels/frame | *) |
|
dir : |
(* | In degrees. Top is 0, clockwise. Strange, I know | *) |
|
children : |
(* | Interp_types.obj s created by this one | *) |
|
pos : |
(* | Where to draw it | *) |
|
prev_dir : |
(* | Used for interpreting DirSeq e | *) |
|
prev_speed : |
(* | Used for interpreting SpdSeq e | *) |
|
vanished : |
(* | If true, don't draw this bullet | *) |
type
env = {
|
frame : |
(* | Frame number. Usually starts at 1, but only deltas are significant | *) |
|
ship_pos : |
(* | Where patterns can aim | *) |
|
screen_w : |
(* | Screen width in pixels | *) |
|
screen_h : |
(* | Screen height in pixels | *) |
|
actions : |
(* | Definitions of Syntax.action s | *) |
|
bullets : |
(* | Definitions of Syntax.bullet s | *) |
|
fires : |
(* | Definitions of Syntax.fire s | *) |
type
init_params = {
|
p_ship : |
(* | Where is the ship. The one that is aimed | *) |
|
p_enemy : |
(* | Where is the enemy. The one that shoots | *) |
|
p_screen_w : |
(* | Screen width in pixels | *) |
|
p_screen_h : |
(* | Screen height in pixels | *) |
type ('g, 'l, 'r)
interpreter = {
|
make_global_ctx : |
(* | (once) create the global, persistent context | *) |
|
make_local_ctx : |
(* | (each frame) create a local context | *) |
|
clear : |
(* | clear frame | *) |
|
draw : |
(* | draw the object and its descendants | *) |
|
run_cont : |
(* | run the next frame. When in doubt, fun _ k -> k () works | *) |
Interp.main_loop
.
It is polymorphic and quite parametric, to allow for different kind of interpreters.
'g
is the global context, something that lasts during all the game. For
example, a window object.'l
is the local context, something created at each frame.'r
is the return type. Typically unit
, but who knows, you might be
writing a monadic interpreter.