Lisp Game Programming 2 <Stage 13-2 Barrage>
Stage1のボスキャラの弾幕(ショットパターン:6、7)
Stage2のボスキャラの弾幕(ショットパターン:8、9、10)
※8と9は32方向に円形の弾幕を張り、10はshipに向かって10連発
ミドルクラスの敵の弾幕(ショットパターン:3、4)
※3は回転しながら4方向に5連発、4はshipに向かって5連発
Stage3のボスキャラの弾幕(ショットパターン:11、12、13)
さて今回作成したものは以下。
先に作成したショットパターンを読み込むためのプログラムを追加。
;; step13 <Enemy Shot Data> ;; ----------------------------------------------------------------------------------------------- (load "C:\\work\\shot-data.lisp")
ショットパターンのためのクラスは、データ保存のために作成。
;;step13 <Enemy Shot Pattern> ;; ----------------------------------------------------------------------------------------------- (define-class shotpattern () (timing angle-store shot-counter beforetime pattern-number pattern-number-store pattern-cnt pattern-cnt-store repeat-flag count-flag first-x first-y first-angle) 0) ; timing shottiming ; angle-store angle-store ; shot-counter number of shot per battery ; beforetime interval before shot ; pattern-number shotpattern0-13 ; pattern-number-store store pattern number ; pattern-cnt number of shotpattern ; pattern-cnt-store store pattern counter ; repeat-flag 0:once 1:repeat ; count-flag repeat count ; first-x x position of first shot ; first-y y position of first shot ; first-angle angle of first shot
敵クラスfoeは、ショットパターンも継承するように変更
(define-class foe (entity shotpattern) (move-cnt damage-cnt life-cnt kind) 0) ; move-cnt moving counter (distance) ; damage-cnt enemy damage counter(wait) ; life-cnt enemy life counter (life time) ; kind kind of enemy
Step9で作成した敵弾の扱いは以下のように大幅に変更。
;; Step13 <Charge Enemy Shot> ;; --------------------------------------------------------------------------------------------- (defun Charge-enemy-shot (enemy enemy-manager) (dotimes (i (shotdata-number-battery (aref *shot-pattern-data* (pattern-number enemy)))) (let ((enemy-shot (make-instance 'entity :id 4 :width 8 :height 8 :dx 0 :dy 0 :state 0))) (push enemy-shot (enemy-shot-list enemy-manager))))) ;; Step13 <Set Enemy center> ;; --------------------------------------------------------------------------------------------- (defun Set-enemy-center (enemy enemy-shot) (case (kind enemy) ((1) ; small class enemy (setf (y enemy-shot) (+ (y enemy) 12)) ; center of small class enemy x (setf (x enemy-shot) (+ (x enemy) 12))) ; center of small class enemy y ((2) ; middle class enemy (setf (y enemy-shot) (+ (y enemy) 28)) ; center of middle class enemy x (setf (x enemy-shot) (+ (x enemy) 28))) ; center of middle class enemy y ((3) ; large class enemy (setf (y enemy-shot) (+ (y enemy) 44)) ; center of large class enemy x (setf (x enemy-shot) (+ (x enemy) 44))))) ; center of large class enemy y ;; Step13 <Set Repeat Flag OFF> ;; --------------------------------------------------------------------------------------------- (defun Set-repeat-flag-OFF (enemy) (case (id enemy) ; if enemy is blue or purple, repeat-flag OFF ((80 81 82 83 84 85) (setf (repeat-flag enemy) 0)) ((50 51 52 53) (setf (repeat-flag enemy) 0)))) ;; Step13 <Set Enemy Variables> ;; --------------------------------------------------------------------------------------------- (defun Set-enemy-variables (enemy) (when (= (count-flag enemy) 0) ; --- if flag ON, set variables (setf (shot-counter enemy) ; set shotcounter (number of shot per 1 pattern) (shotdata-number-battery-shot (aref *shot-pattern-data* (pattern-number enemy)))) (setf (timing enemy) (beforetime enemy)) ; set shot beforetime (setf (pattern-cnt-store enemy) (pattern-cnt enemy)) ; each enemy has 0-2 patterns (setf (pattern-number-store enemy) (pattern-number enemy)) ; store patternnumber (setf (count-flag enemy) 1))) ; --- flag OFF, no more set ;; Step13 <Set Enemy Shot angle> ;; --------------------------------------------------------------------------------------------- (defvar *range-x*) (defvar *range-y*) (defvar *distance*) (defun Set-enemy-shot-angle (shotangle ship enemy enemy-shot) (let ((angle (nth shotangle (shotdata-battery-angle (aref *shot-pattern-data* (pattern-number enemy))))) (rotation-angle (shotdata-direction-battery-angle (aref *shot-pattern-data* (pattern-number enemy)))) (speed (shotdata-shotspeed (aref *shot-pattern-data* (pattern-number enemy)))) (ship-x (+ (x ship) (/ (width ship) 2))) ; ship x position (ship-y (+ (y ship) (/ (height ship) 2))) ; ship y position (ene-shot-x (+ (x enemy-shot) (/ (width enemy-shot) 2))) ; enemy-shot x position (ene-shot-y (+ (y enemy-shot) (/ (height enemy-shot) 2)))) ; enemy-shot y position (case (shotdata-battery-direction (aref *shot-pattern-data* (pattern-number enemy))) ((0) ; beneath (when (= rotation-angle 0) ; not rotation (setf (dx enemy-shot) (* (cos (degree-radian angle)) speed)) ; dx from angle list (setf (dy enemy-shot) (* (sin (degree-radian angle)) speed))); dy from angle list (when (/= rotation-angle 0) ; rotation (if (= shotangle 0) (setf (angle-store enemy) (+ (angle-store enemy) rotation-angle))) (setf (dx enemy-shot) (* (cos (degree-radian (+ angle (angle-store enemy)))) speed)) ; dx from angle list (setf (dy enemy-shot) (* (sin (degree-radian (+ angle (angle-store enemy)))) speed)))); dy from angle list ((1) ; direction of ship (setf *range-x* (- ship-x ene-shot-x)) (setf *range-y* (- ship-y ene-shot-y)) (setf *distance* (sqrt (+ (* *range-x* *range-x*) (* *range-y* *range-y*)))) (setf (first-x enemy) (* (/ *range-x* *distance*) speed)) ; x distance from enemy to ship (setf (first-y enemy) (* (/ *range-y* *distance*) speed)) ; y distance form enemy to ship (if (< (atan (/ (first-y enemy) (first-x enemy))) 0) ; find angle in Arc tangent (setf (first-angle enemy) (radian-degree (+ (atan (/ (first-y enemy) (first-x enemy))) (/ pi 2)))) (setf (first-angle enemy) (radian-degree (- (atan (/ (first-y enemy) (first-x enemy))) (/ pi 2))))) (when (= rotation-angle 0) ; not rotation (setf (dx enemy-shot) (* (cos (degree-radian (+ angle (first-angle enemy)))) speed)) (setf (dy enemy-shot) (* (sin (degree-radian (+ angle (first-angle enemy)))) speed))) (when (/= rotation-angle 0) ; rotation (if (= shotangle 0) (setf (angle-store enemy) (+ (angle-store enemy) rotation-angle))) (setf (dx enemy-shot) (* (cos (degree-radian (+ angle (first-angle enemy) (angle-store enemy)))) speed)) ; dx from angle list (setf (dy enemy-shot) (* (sin (degree-radian (+ angle (first-angle enemy) (angle-store enemy)))) speed))))))); dy from angle list ;; Step13 <Set Enemy Shot Timing> ;; --------------------------------------------------------------------------------------------- (defun Set-enemy-shot-timing (ship enemy enemy-manager) (when(and (= (move-cnt enemy) (timing enemy)) ; equal move-cnt and timing (= (repeat-flag enemy) 1)) ; and shot repeat (let ((shotangle 0)) ; set enemy shot direction (start <- 0) (dolist (enemy-shot (enemy-shot-list enemy-manager)) (when (= (state enemy-shot) 0) (Set-enemy-center enemy enemy-shot) ; set enemy center position (Set-enemy-shot-angle shotangle ship enemy enemy-shot) ; set enemy shot angle (incf shotangle) ; judge length of battery-angle-list (if (= shotangle (length (shotdata-battery-angle (aref *shot-pattern-data* (pattern-number enemy))))) (setf shotangle 0)) ; reset shotangle (setf (state enemy-shot) 1)))) ; shot state ON into battery-angle list (setf (shot-counter enemy) (decf (shot-counter enemy))) ; go to next shot timing (cond ((/= (shot-counter enemy) 0) ; when shot counter not 0 (setf (timing enemy) ; set betweentime (+ (timing enemy) (shotdata-betweentime (aref *shot-pattern-data* (pattern-number enemy)))))) ((= (shot-counter enemy) 0) ; when shot counter 0 (setf (timing enemy) ; set aftertime (+ (timing enemy) (shotdata-aftertime (aref *shot-pattern-data* (pattern-number enemy))))) (setf (angle-store enemy) 0) ; angle-store reset 0 (setf (pattern-cnt enemy) (decf (pattern-cnt enemy))) ; go to next pattern (ex: 1 -> 0) (Set-repeat-flag-OFF enemy))))) ; blue and purple enemy repeat OFF ;; Step13 <Set Enemy Shot Pattern> ;; --------------------------------------------------------------------------------------------- (defun Set-enemy-shot-pattern (enemy) (when (= (shot-counter enemy) 0) (if (= (pattern-cnt enemy) 0) ; reset shot pattern (progn (setf (pattern-cnt enemy) (pattern-cnt-store enemy)) ; back to first pattern count (setf (pattern-number enemy) (pattern-number-store enemy)) ; back to first pattern number (setf (shot-counter enemy) ; back to first shotcounter (shotdata-number-battery-shot (aref *shot-pattern-data* (pattern-number enemy))))) (progn (setf (pattern-number enemy) (incf (pattern-number enemy))) ; pattern number + 1 (ex: 3 -> 4 etc) (setf (shot-counter enemy) ; set shotcounter (number of shot per 1 pattern) (shotdata-number-battery-shot (aref *shot-pattern-data* (pattern-number enemy))))))))
なお、弾幕を設定するにあたり、Step7も以下のように各敵ごとのショットパターンの設定を行った。
茶色の敵:連射 :初弾までのタイミング 8 :ショットパターン 0
紫色の敵:単射 :初弾までのタイミング 8 :ショットパターン 1
青色の敵:単射 :初弾までのタイミング 16 :ショットパターン 2
灰色の敵:連射 :初弾までのタイミング 32 :ショットパターン 3 4
緑色の敵:連射 :初弾までのタイミング 32 :ショットパターン 5
ボス1 :連射 :初弾までのタイミング 64 :ショットパターン 6 7
ボス2 :連射 :初弾までのタイミング 64 :ショットパターン 8 9 10
ボス3 :連射 :初弾までのタイミング 64 :ショットパターン 11 12 13
;; step7 <Generate Enemy> + Enemy Shot ;; ----------------------------------------------------------------------------------------------- (defgeneric Generate-enemy-item (map enemy-manager item-manager)) (defmethod Generate-enemy-item (map enemy-manager item-manager) (when (and (eql *enemy-generate-flag* t) (= (mod *scroll-cnt* 64) 0) (<= (length (enemy-list enemy-manager)) 10)); max 10 enemy (dotimes (j 10) (when (/= (aref map *enemy-map-pointer* j) -1) (case (aref map *enemy-map-pointer* j) ((7) ; when id is 7 (let ((enemy (make-instance 'foe ; small class yellow enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 32 :height 32 :life-cnt 3 :kind 1 :state 1 :beforetime 8 :pattern-number 0 :pattern-cnt 1 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((80) ; when id is 80 (let ((enemy (make-instance 'foe ; small class purple enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 32 :height 32 :life-cnt 3 :kind 1 :state 1 :beforetime 8 :pattern-number 1 :pattern-cnt 1 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((50) ; when id is 50 (let ((enemy (make-instance 'foe ; small class blue enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 32 :height 32 :life-cnt 3 :kind 1 :state 1 :beforetime 16 :pattern-number 2 :pattern-cnt 1 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((76) ; when id is 76 (let ((enemy (make-instance 'foe ; middle class gray enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 64 :height 64 :life-cnt 20 :kind 2 :state 1 :beforetime 32 :pattern-number 3 :pattern-cnt 2 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((78) ; when id is 78 (let ((enemy (make-instance 'foe ; middle class green enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 64 :height 64 :life-cnt 20 :kind 2 :state 1 :beforetime 32 :pattern-number 5 :pattern-cnt 1 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((70) ; when id is 70 (let ((enemy (make-instance 'foe ; large class boss1 enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 96 :height 96 :life-cnt 300 :kind 3 :state 1 :beforetime 64 :pattern-number 6 :pattern-cnt 2 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((71) ; when id is 71 (let ((enemy (make-instance 'foe ; large class boss2 enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 96 :height 96 :life-cnt 300 :kind 3 :state 1 :beforetime 64 :pattern-number 8 :pattern-cnt 3 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((72) ; when id is 72 (let ((enemy (make-instance 'foe ; large class boss3 enemy generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 96 :height 96 :life-cnt 300 :kind 3 :state 1 :beforetime 64 :pattern-number 11 :pattern-cnt 3 :repeat-flag 1))) (push enemy (enemy-list enemy-manager)))) ((17 18) ; when id is 17 or 18 (let ((item (make-instance 'foe ; item generate :id (aref map *enemy-map-pointer* j) :x (+ 160 (* j 32)) :y 0 :width 32 :height 32 :dx 0 :dy 2 :kind 4 :state 1))) (push item (item-list item-manager))))))) ; store items into item-list (if (/= *enemy-map-pointer* 0) (decf *enemy-map-pointer*) ; attention ! *enemy-map-pointer* 0 keep! (setf *enemy-generate-flag* nil)))) ; *enemy-map-pointer* 64 -> 0 (end position)
H27.10.28追記
stage3の渦巻き型の弾幕がなかなか見事なので掲載。