Возможно иметь два поведения, основанных на времени, работающих на разных скоростях, причем оба управляются одной и той же функцией on-tick
.
Например, две функции:
walk
, который тикает каждые 5/10 секунд run
, который тикает каждые 2/10 секунды
Где run
тикает с удвоенной скоростью walk
.
Для этого вы устанавливаете свою «фактическую» скорость тика равной «наибольшему общему знаменателю» из двух, что в данном случае составляет каждую 1/10 секунды.Затем вы должны убедиться, что run
вызывается на каждом "фактическом" тике, а walk
вызывается на каждом "реальном" тике.
(define (actual-tick w)
???)
(big-bang ???
[on-tick actual-tick 1/10]
...)
Как определить, является ли actual-tick
должен звонить walk
или нет?Он должен вызываться ровно в 1/5 времени, вращаясь между «вкл.», «Выкл.», «Выкл.», «Выкл.», «Выкл.» Регулярно.
Как определить, должен ли actual-tick
вызывать run
или нет?Его следует вызывать в 1/2 раза, чередуя «вкл.» И «выкл.».
. Для этого необходимо отслеживать два числа:
- Количествочисло тактов с момента последнего "шага"
- количество тактов с момента последнего "шага"
Они становятся двумя полями в структуре вашего состояния мира.
(struct ticks-since [run walk])
Когда звонить "гулять"?Когда ticks-since-walk
равен 5.
(define (tick-walk? s)
(<= 5 (ticks-since-walk s)))
Когда вызывать «запустить»?Когда ticks-since-run
равно 2.
(define (tick-run? s)
(<= 2 (ticks-since-run s)))
И, наконец, функция actual-tick
должна вызывать их.
(define (actual-tick s)
(cond
[(and (tick-walk? s) (tick-run? s))
;; call and reset both
(... walk ...
run ...
(ticks-since 0 0) ...)]
[(tick-walk? s)
;; call and reset walk, increment run
(... walk ...
(ticks-since 0 (add1 (ticks-since-run s))) ...)]
[(tick-run? s)
;; call and reset run, increment walk
(... run ...
(ticks-since (add1 (ticks-since-walk s)) 0) ...)]
[else
;; don't call walk or run, but increment both ticks-since counters
(... (ticks-since (add1 (ticks-since-walk s))
(add1 (ticks-since-run s))) ...)]))