Lisp Game Programming 2 <Stage 12>
Stage12では、shipが敵や敵弾と衝突したときのプログラムを組みこんでみる。
また、STAGEが切り替わるためには、デカキャラを倒す必要があり、普通の敵より激しい爆発として作成したのが以下のプログラム。
これで「ほぼ」完成!(弾幕を除き)
;; Step12 <Ship Hit P> ;; ----------------------------------------------------------------------------------------------- (defgeneric Ship-hit-p (ship enemy-manager balloon-manager score shot-manager)) (defmethod Ship-hit-p (ship enemy-manager balloon-manager score shot-manager) (when (= (state ship) 1) (let ((hit 0)) (dolist (enemy (enemy-list enemy-manager)) (when (and (or (= (state enemy) 1) ; if enemy is alive (= (state enemy) 2)) ; or enemy is damaged (> (+ (x ship) 16) (x enemy)) ; 16 is center of ship (< (+ (x ship) 16) (+ (x enemy) (width enemy))) ; width enemy (> (+ (y ship) 16) (y enemy)) (< (+ (y ship) 16) (+ (y enemy) (height enemy)))) ; height enemy (if (/= (kind enemy) 3) ; when not large enemy (setf (state enemy) 0 ; small or middle enemy explosion hit 1) (setf (state enemy) 3 ; large enemy is dameged hit 1)))) (dolist (enemy-shot (enemy-shot-list enemy-manager)) (when (and (= (state enemy-shot) 1) ; enemies shot and ship hit (> (+ (x ship) 16) (x enemy-shot)) (< (+ (x ship) 16) (+ (x enemy-shot) (width enemy-shot))) (> (+ (y ship) 16) (y enemy-shot)) (< (+ (y ship) 16) (+ (y enemy-shot) (height enemy-shot)))) (setf (state enemy-shot) 0 hit 1))) (when (= hit 1) ; hit on ship (Play-sample *crushed*) ; ship crushed sound (setf (state ship) 2 ; ship is explode (shot-list shot-manager) nil (balloon-cnt balloon-manager) 0 (balloon-list balloon-manager) nil (n-bomb score) 3 (explode-cnt ship) 0))))) ; ship explode count 0 ;; Step12 <Explode Counter> ;; ----------------------------------------------------------------------------------------------- (defgeneric Explode-counter (ship score game-field stage)) (defmethod Explode-counter (ship score game-field stage) (when (= (state ship) 2) ; ship is explode (incf (explode-cnt ship) 1) (when (= (explode-cnt ship) 100) (decf (n-ship score) 1) (when (> (n-ship score) 0) (setf (state ship) 3 ; set ship revival (revival-cnt ship) 0 (x ship) (- (* (field-x game-field) 2) (/ (width ship) 2)) (y ship) (- (height game-field) (* (height ship) 2))))))) ;; Step12 <Revive Counter> ;; ----------------------------------------------------------------------------------------------- (defgeneric Revive-counter (ship enemy-manager)) (defmethod Revive-counter (ship enemy-manager) (when (= (state ship) 3) ; ship is revival (incf (revival-cnt ship) 1) (when (>= (revival-cnt ship) 200) ; revival counter is over 200 (dolist (enemy (enemy-list enemy-manager)) (unless (and (or (= (state enemy) 1) ; if enemy is alive (= (state enemy) 2)) ; or enemy is damaged (> (+ (x ship) 16) (x enemy)) ; 16 is center of ship (< (+ (x ship) 16) (+ (x enemy) (width enemy))) ; width enemy (> (+ (y ship) 16) (y enemy)) (< (+ (y ship) 16) (+ (y enemy) (height enemy)))))) ; height enemy (setf (state ship) 1)))) ;; Step12 <Draw Ship Explosion> ;; ----------------------------------------------------------------------------------------------- (defgeneric Draw-ship-explosion (ship explosion)) (defmethod Draw-ship-explosion (ship explosion) (when (and (= (state ship) 2) (< (explode-cnt ship) 30)) (setf (x explosion) (- (x ship) 16) ; x : center of explosion (y explosion) (y ship)) ; y : center of explosion (cond ((<= (explode-cnt ship) 10) (setf (id explosion) 47)) ((and (> (explode-cnt ship) 10) (<= (explode-cnt ship) 20)) (setf (id explosion) 48)) ((> (explode-cnt ship) 20) (setf (id explosion) 49))) (Draw explosion))) ; draw ship explosion ;; Step12 <Draw Ship> ;; ----------------------------------------------------------------------------------------------- (defgeneric Draw-ship (ship)) (defmethod Draw-ship (ship) (when (or (= (state ship) 1) (and (= (state ship) 3) (> 5 (mod (revival-cnt ship) 10)))) ; ship flushes on and off (Draw ship))) ; draw ship revival
敵がデカキャラの場合の爆発に関係するプログラムは以下。
;; step12 <Set Explosion> ;; ----------------------------------------------------------------------------------------------- (defvar *rnd1*) (defvar *rnd2*) (defgeneric Set-explosion (explosion-manager enemy-manager)) (defmethod Set-explosion (explosion-manager enemy-manager) "set explosion" (dolist (enemy (enemy-list enemy-manager)) (when (and (= (state enemy) 3) (= (kind enemy) 3)) (when (and (= (mod (bomb-cnt explosion-manager) 15) 0) ; bomb-cnt is 150 -> 10 times (/= (bomb-cnt explosion-manager) 0)) (dotimes (i (bomb-number explosion-manager)) ; 5 bomb (let ((bomb (make-instance 'entity :id 64 :width 64 :height 64 :state 1))) (setf *rnd1* (random 96) ; x: from -32 to 96 *rnd2* (random 96)) ; y: from -32 to 96 (setf (x bomb) (- (+ (x enemy) *rnd1*) 32) (y bomb) (- (+ (y enemy) *rnd2*) 32)) (push bomb (bomb-list explosion-manager))))) (decf (bomb-cnt explosion-manager)) ; decrement bomb-cnt 150 -> 0 (when (= (bomb-cnt explosion-manager) 0) ; if bomb counter is 0 , reset 150 (setf (bomb-cnt explosion-manager) 150 (state enemy) 0 *stage-end-flag* t) ; stage end! (Stop-sound))))) ; BGM stop! ;; step12 <Explode Large Enemy> ;; ----------------------------------------------------------------------------------------------- (defvar *large-enemy-explodes-flag* nil) (defgeneric Explode-large-enemy (explosion-manager)) (defmethod Explode-large-enemy (explosion-manager) "large enemy explosion while 15 times loop" (dolist (bomb (bomb-list explosion-manager)) (incf (explode-cnt bomb) 1) (when (eql *large-enemy-explodes-flag* nil) (setf *large-enemy-explodes-flag* t) ; bomb explode sound on (Play-sample *bomb*)) ; bomb explode sound (when (= (explode-cnt bomb) 15) ; when bomb explode count is 15 (setf (state bomb) 0 ; set state of bomb 0 *large-enemy-explodes-flag* nil)))) ;; step12 <Remove Explode large enemy> ;; ----------------------------------------------------------------------------------------------- (defgeneric Remove-explode-large-enemy (explosion-manager)) (defmethod Remove-explode-large-enemy (explosion-manager) "explode bomb remove from list" (setf (bomb-list explosion-manager) (delete-if #'(lambda (bomb) (= (state bomb) 0)) (bomb-list explosion-manager)))) ;; step12 <Draw Explosion Large Enemy> ;; ----------------------------------------------------------------------------------------------- (defgeneric Draw-explosion-large-enemy (explosion-manager)) (defmethod Draw-explosion-large-enemy (explosion-manager) (dolist (bomb (bomb-list explosion-manager)) (when (= (state bomb) 1) (cond ((and (>= (explode-cnt bomb) 0) (< (explode-cnt bomb) 5)) (setf (id bomb) 64)) ((and (>= (explode-cnt bomb) 5) (< (explode-cnt bomb) 10)) (setf (id bomb) 65)) ((and (>= (explode-cnt bomb) 10) (< (explode-cnt bomb) 15)) (setf (id bomb) 66))) (Draw bomb)))) ; draw bomb
メインルーチンにも当然追加が必要。
・・・・・・・・・・・・・・・・・・・・ ; <Enemy-hit-p :Damage Draw Explode> (Enemy-hit-p shot-manager enemy-manager) (Damage-counter enemy-manager score) (Explode-enemy enemy-manager) (Draw-enemy-explosion enemy-explosion enemy-manager) (Score-up score) ; <Large Enemy Explosion> (Set-explosion explosion-manager enemy-manager) (Explode-large-enemy explosion-manager) (Remove-explode-large-enemy explosion-manager) (Draw-explosion-large-enemy explosion-manager) ・・・・・・・・・・・・・・・・・・・・