読者です 読者をやめる 読者になる 読者になる

`(kakko ,man)

Find a guide into tomorrow by taking lessons from the past

Lisp Game Programming 2 <Stage 12>

f:id:tomekame0126:20151018082143p:plain
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)
	    
     ・・・・・・・・・・・・・・・・・・・・