Я работаю над программой Racket для класса, и я в полном недоумении относительно того, как реализовать одну из функций.
Программа использует Big-Bang и должна реализовывать простую игру Space Invaders..
У меня все работает, кроме одного куска, а именно - как справиться со случаем, когда ракета сталкивается с захватчиком.Причина, по которой я борюсь, состоит в том, что я не знаю, как написать функцию, в которой у меня есть два списка произвольного размера, и я должен проверить поля каждого объекта в одном списке с каждым объектом в другом списке и удалить объектв каждом списке, если они имеют одинаковые значения.
Мировое состояние - игра:
(define-struct game (invaders missiles tank))
, где захватчики и ракеты - оба списка.
Для создания следующегоВ игровом состоянии я реализую функцию под названием «tock».
Обычно я просто делаю:
(define (tock s)
(make-game (next-invaders (game-invaders s))
(next-missiles (game-missiles s))
(next-tank (game-tank s)))
Но так как содержимое списков захватчиков и ракет может влиять друг на другаиз-за столкновения я не могу просто обновить позиции независимо и двигаться дальше, я должен удалить любые столкновения и затем обновить позиции.
Итак, я попробовал:
(define (tock s)
(make-game (check-collision (game-invaders s)
(game-missiles s)
(game-tank s))
Но это заставляет чек-столкновение брать танк, который ему не нужен.
(define (tock s)
(make-game (next-invaders (game-invaders s) (game-missiles s))
(next-missiles (game-missiles s) (game-invaders s))
(next-tank (game-tank s))))
В этой версии у меня есть функция с именем next-invaders
, которая принимает список захватчиков и ракет, ифункция называется next-missiles
, который занимает список ракет и захватчиков.Первая функция проверяет каждого захватчика на каждой ракете, пытается удалить всех столкнувшихся захватчиков и возвращает оставшихся захватчиков.Вторая функция проверяет каждую ракету против каждого захватчика и пытается удалить любые столкнувшиеся ракеты и возвращает оставшиеся ракеты.Ответы должны быть одинаковыми, но это дублирующая работа, и я беспокоюсь о возможном состоянии гонки.Я не знаю, как еще построить одно выражение, в котором одной функции нужно только два поля, а другому - три, и я все еще получаю следующее состояние игры.
Вот пример next-invaders
.Если нет захватчиков, это ничего не делает.Если есть захватчики, но нет ракет, он просто перемещает каждого захватчика (move-invader)
и рекурсивно вызывает себя для перебора всех захватчиков.Если есть и ракеты, и захватчики, то я проверяю, нет ли столкновения между первым захватчиком в списке и каждой ракетой в списке;так что проверка столкновения является рекурсивной.
(define (next-invaders loi lom)
(cond [(empty? loi) empty]
[(empty? lom) (move-invader (first loi) (next-invaders (rest loi) lom))]
[(check_collision (first loi) lom)
(next-invaders (cons (rest loi) empty) lom)]
[else
(move-invader (first loi)
(next-invaders (rest loi) lom))]))
Является ли 'ответ' на check-collision
правильным способом "удаления" столкнувшегося захватчика из списка захватчиков?
(define (check_collision i lom)
(cond [(empty? lom) false]
[(and (<= (- (missile-x (first lom)) (invader-x i)) HIT-RANGE)
(<= (- (missile-y (first lom)) (invader-y i)) HIT-RANGE))
true]
[else (check_collision i (rest lom))]))
это правильный способ проверить каждый элемент каждого списка друг против друга?
Обновление: по-прежнему кругами по этой проблеме.check-collision работает и invader-function работает, но когда я возвращаюсь к функции missile, я не знаю, как указать, что ракета должна быть удалена в случае обнаружения столкновения в функции invader.
(define-struct invader (x y dx))
;; Invader is (make-invader Number Number Number)
;; interp. the invader is at (x, y) in screen coordinates
;; the invader along x by dx pixels per clock tick
(define-struct missile (x y))
;; Missile is (make-missile Number Number)
;; interp. the missile's location is x y in screen coordinates
(define-struct collision (invaders missiles))
(define (tock s)
(make-game (handle-invaders (collision-invaders (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
(handle-missiles (collision-missiles (next-invaders-and-missiles (make-collision (game-invaders s) (game-missiles s)))))
(handle-tank (game-tank s))))
(define (next-invaders-and-missiles c)
(cond [(and (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision empty empty)]
[(or (empty? (collision-invaders c)) (empty? (collision-missiles c))) (make-collision (collision-invaders c) (collision-missiles c))]
[else
(missile-function (make-collision (collision-invaders c) (collision-missiles c)))]))
;; Collision -> list Of Missiles
;; produce an updated listOf Missiles taking collisions into account
(define (missile-function c)
(cond [(empty? (collision-missiles c)) (make-collision (collision-invaders c) empty)]
[else
(if (< (length (invader-function (first (collision-missiles c)) (collision-invaders c))) (length (collision-invaders c)))
(make-collision (collision-invaders c) (remove (first (collision-missiles c)) (collision-missiles c)))
(missile-function (make-collision (collision-invaders c) (rest (collision-missiles c)))))]))
;; Missile, listOf Invaders -> listOf Invaders
;; produce an updated listOf Invaders taking collisions into account
(define (invader-function m loi)
(cond [(empty? loi) empty]
[else
(if (check-collision? (first loi) m)
(remove (first loi) loi)
(invader-function m (rest loi)))]))
;; Invader, Missile -> Boolean
;; produce true if the coordinates of a missile are within HIT-RANGE of the coordinates of an invader
(define (check-collision? i m)
(and (<= (- (missile-x m) (invader-x i)) HIT-RANGE) (<= (- (missile-y m) (invader-y i)) HIT-RANGE)))