アクションつくってみる3

投稿者:Nyan mini rurun9 投稿日:2012/04/17 00:10

ハイ、こんにちわー。

結局、ブロックとの当たり判定は一画面毎に細かく指定していく、最も面倒だけど確実な方法を採用してみますた…
例によって直前回とは根本的な設計を変えているので再び激変しております

今回は作り方の枠組みが決まったので、俺ルールをできるだけ解説してみるけど、たぶん自分で後から見直す用にしかならない気ガス
#chapter0
setVariable("e",118038) #スプライト用の素画像番号

def sv(a,b)
 setVariable(a,b)
end

def gv(a)
 return getVariable(a)
end

sv("x",createArray()); sv("y",createArray()) #スプライトの位置(x,y)
sv("j",createArray()) #スプライトの状態、向きや種類の番号、敵なら耐久力を入れる
sv("dx",createArray()); sv("dy",createArray()) #スプライトの移動量(dx,dy)
sv("zone",0) #何画面目か

#◆スプライトの作成
deleteAllSprite(); drawCanvas() #最初に使う前にキャンバスをキレイにしておく
sv("h",createArray()) #スプライト表示番号 0=宇宙人, 1~4=弾, 5~19=敵や床など
n=0
while n<20
 gv("h")[n]=createSprite(gv("e"))
n=n+1
end
setSpriteRect(gv("h")[0], 0,0,32,32, -32,-32,64,64) #宇宙人
setSpriteZOrder(gv("h")[0], 2)
n=1
while n<=4
 setSpriteRect(gv("h")[n], 0,96,32,32, -16,-16,32,32) #弾
 setSpriteZOrder(gv("h")[n], 1)
n=n+1
end
使う変数が減ってスッキリ
固定1画面を順にクリアしていくスクロール無しの単純なゲームに落ち着く
#chapter_setzone
def sp(i, x,y, w,h, dx, dy, what) #◆◆◆スプライトを作成する処理

case what
when 0 #固定の緑色
 setSpriteRect(gv("h")[i], 96,96,1,1, 0,0,w,h)
when 1 #移動の土色
 setSpriteRect(gv("h")[i], 70,20,1,1, 0,0,w,h)
when 2 #左側の坂
 setSpriteRect(gv("h")[i], 64,96,32,32, 0,0,w,h)
when 3 #右側の坂
 setSpriteRect(gv("h")[i], 96,96,32,32, 0,0,w,h)
when 4 #敵
 setSpriteRect(gv("h")[i], 64,0,32,32, -32,-32,64,64)
when 5 #敵の弾
 setSpriteRect(gv("h")[i], 32,96,32,32, -16,-16,32,32)
end

gv("x")[i]=x; gv("y")[i]=y; gv("dx")[i]=dx; gv("dy")[i]=dy
if what!=4
 gv("j")[i]=0 #敵なら耐久力になる
end

end #sp()終


def setzone() #◆◆◆画面切り替え時にステージ床&壁&敵を配置する処理

setCanvasVisible(false) #一度、全スプライトを見えなくする

n=0
while n<=4
 gv("x")[n]=0; gv("y")[n]=640 #弾は最初、見えない位置に置く
 gv("j")[n]=0 #弾は出てない状態にする
 gv("dx")[n]=0; gv("dy")[n]=0 #宇宙人と弾の初期移動量は(0,0)
n=n+1
end
gv("j")[0]=2 #宇宙人は右向きでスタート

case gv("zone")
when 0
 showImage(2495)
 sv("max",12); gv("x")[0]=100; gv("y")[0]=100
 sp(5, 240,300, 160,40, 0,-4, 1) #浮床
 sp(6, 0,0, 100,500, 0,0, 0) #左の壁
 sp(7, 700,164, 100,336, 0,0, 0) #右の壁
 sp(8, 0,500, 800,100, 0,0, 0) #床
 sp(9, 500,400, 200,100, 0,0, 2) #左坂
 sp(10, 636,164, 64,40, 0,0, 0) #敵の足場
 sp(11, 636+32,100+32, 64,64, 0,0, 4); gv("j")[11]=5 #敵
 sp(12, 0,600, 100,40, 0,0, 0) #ゴールへ行ける足場

when 1
 sv("max",7); gv("x")[0]=100; gv("y")[0]=500-32
 sp(5, 0,0, 100,500, 0,0, 0) #左壁
 sp(6, 700,0, 100,500, 0,0, 0) #右壁
 sp(7, 0,500, 800,100, 0,0, 0) #床

end #case zone終

n=gv("max")+1 #使わないスプライトをとりあえず無効化
while n<20
 gv("x")[n]=0; gv("y")[n]=640; gv("dx")[n]=0; gv("dy")[n]=0; gv("j")[n]=0
n=n+1
end

n=0
while n<20
 setSpritePosition(gv("h")[n], gv("x")[n],gv("y")[n] ) #スプライト全てを位置(x,y)に配置
n=n+1
end

drawCanvas() #スプライトを載せたキャンバスを更新
setCanvasVisible(true) #【重要】キャンバスを見えるようにしている
sv("goal",false) #このステージのゴールが開いてるかどうか

end #setzone()終
画面毎のステージを『ゾーン』と呼ぶ事にした
壁や床のスプライトを作成するdefを置き、各ゾーン毎にパーツ1個ずつ位置や大きさを指定してゆく
・宇宙人:スプライト番号0
・弾:1~4
・壁、床、敵、敵弾など:5~19までの最大15個

全てのスプライトについて、
・位置(x,y)
・幅w、高さh
・移動量(dx,dy)
・状態番号j
のデータで管理する
jに入る数値は種類によって全く意味が異なる俺ルールなので注意
#chapter_wallcheck
def wallcheck() #◆◆◆宇宙人と床や壁との衝突判定

x=gv("x")[0]+gv("dx")[0]; y=gv("y")[0]+gv("dy")[0]
walk=false

case gv("zone")
when 0 #◆◆
gv("y")[5]=gv("y")[5]+gv("dy")[5] #上下移動床を動かして再表示
if gv("y")[5]<200
 gv("dy")[5]=4
elsif 420<gv("y")[5]
 gv("dy")[5]=-4
end
setSpritePosition(gv("h")[5], gv("x")[5],gv("y")[5])

if 500-32<y #全体の床
 y=500-32; gv("dy")[0]=0; walk=true
end
if x<100 #左壁
 x=100; gv("dx")[0]=0
elsif 240<=x && x<400 #上下移動床
 if gv("y")[5]-32<=y && y<gv("y")[5]+40
  if gv("dy")[0]<0
   y=gv("y")[5]+40; gv("dy")[0]=0
  else
   y=gv("y")[5]-32; gv("dy")[0]=0; walk=true
  end
 end
elsif 500<=x && x<700 #坂
 if 750-32-(x/2)<y
  y=750-32-floor(x/2); gv("dy")[0]=0; walk=true
 elsif gv("dx")[0]<0 && gv("walk")
  y=750-32-floor(x/2); gv("dy")[0]=0; walk=true
 end
elsif 700<=x #右壁
 if y<=164-16
  changeChapter("chapter2")
 end
 x=700; gv("dx")[0]=0
 if 400-32<y
  y=400-32; gv("dy")[0]=0; walk=true
 end
end
if gv("goal") #敵を倒したら右上の足場に行ける
 if 0<=gv("dy")[0]
  if 468<=x && x<568 && 164-32<=y && y<204
   y=164-32; gv("dy")[0]=0; walk=true
  elsif 636<=x && 164-32<=y && y<204
   y=164-32; gv("dy")[0]=0; walk=true
  end
 end
end

when 1 #◆◆
if 500-32<y #全体の床
 y=500-32; gv("dy")[0]=0; walk=true
end
if x<100
 x=100; gv("dx")[0]=0
elsif 700<=x
 x=700; gv("dx")[0]=0
end

end #case zone終

gv("x")[0]=x; gv("y")[0]=y #座標の更新
if walk
 sv("walk",true)
else
 sv("walk",false)
end

end #wallcheck()終
ゾーン毎に地形が異なるのを、宇宙人がめり込まないように細かく座標を管理&制御してゆく
setzoneにて配置した位置&大きさに沿って、移動可能範囲を座標で計算(ゾーン毎に疲れる作業量…)

移動する床もwallcheck内で位置を変更してる
尚、上下移動する土色の浮き床の移動量dyは自由落下速度の初速と全く同じにしてあるので、下に動いている場合でも常に「乗っている」=ジャンプ可能となる
宇宙人が上に動いてるかdy[0]<=0、下に動いてるか0<dy[0]で、浮き床にめり込んだ際に上下どちらに押し出すかを決めている

ナナメの坂は、登っている場合は常に接地しているのでジャンプが可能なのに対して
坂を下っている場合にx方向のみ前に移動させると一瞬空中にいる状態になってしまい、空中ではジャンプができない。そこで「直前まで歩いていたなら」坂に沿って高さも同時にズラさないといけない

また「敵を倒すと地形が変化する」ギミックを入れたので、地形変化後の判定もココに書いてある
ゾーンが増えるほど、when i が増えてどんどん長くなっていく形
#chapter_hitcheck
def setgoal() #◆◆◆敵を倒したらゴールを出す処理

case gv("zone")
when 0
 setSpritePosition(gv("h")[12], 468,164)
#when 1
end #case zone終

sv("goal",true)

end #setgoal()終


def hitcheck(i) #◆◆◆弾の当たり判定処理

m=5
while m<=gv("max")
if 0<gv("j")[m] #残り耐久値があるヤツだけ判定する
 if gv("x")[m]-32<gv("x")[i] && gv("x")[i]<gv("x")[m]+32 && gv("y")[m]-32<gv("y")[i] && gv("y")[i]<gv("y")[m]+32
  gv("j")[m]=gv("j")[m]-1 #敵の耐久値を1減らす
  gv("x")[i]=0; gv("y")[i]=640; gv("j")[i]=0 #当たった弾も出てない状態にする
  if gv("j")[m]<1 #敵の耐久値が0になったら画面外へ
   gv("j")[m]=0; gv("x")[m]=0; gv("y")[m]=800; gv("dx")[m]=0; gv("dy")[m]=0
   setSpritePosition(gv("h")[m], gv("x")[m],gv("y")[m])
   setgoal(); playSound(63622)
  else
   playSound(44339)
  end
 end
end
m=m+1
end

end #hitcheck()終
地形が変化する処理と、弾が敵に当たってたら耐久値を減らす処理
まだ敵は弾を出してないので、敵弾の当たり判定も追加予定
#chapter1
z=createText(0,0,800,600) #臨時テキスト
setzone() #ステージを作成&設置
speak("ZONE ",gv("zone"))

p=createArray(); p[0]=400; p[1]=300 #マウス位置用、最初は画面ド真ん中という事にしておく
anime=0 #アニメ用カウント
tama=0 #何番の弾を出すか
sv("walk",false) #歩いているかどうか、つまりジャンプ可能かどうか


startInput() #入力受付
key=true
while key

while hasInput()
takeInput()

if isMouseMove()
 p=getMousePosition()
elsif isMouseDown() && gv("walk") #歩いてるときにクリックしたら、ジャンプ
 gv("dy")[0]=-36; sv("walk",false); playSound(66602)
elsif isKeyUp("ESC")
 key=false
end

end #hasInput終

gv("dy")[0]=gv("dy")[0]+4 #重力による自由落下

if p[0]<gv("x")[0]-32 #プレイヤーキャラ宇宙人の横移動
 gv("dx")[0]=-8; gv("j")[0]=1 #左向き
elsif gv("x")[0]+32<p[0]
 gv("dx")[0]=8; gv("j")[0]=2 #右向き
else
 gv("dx")[0]=0
end

wallcheck() #宇宙人と、床壁との衝突判定

if 800<gv("y")[0] #もしもの壁抜けに対応
 speak("画面外に落ちた"); gv("x")[0]=100; gv("y")[0]=-100
end

anime=anime+1 #◆アニメカウントが一定になったら絵を切り替える
if anime==6
 if gv("dx")[0]==0 #横移動してたらそっちを向く
  m=0
 elsif gv("dx")[0]<0
  m=32
 else #0<gv("dx")[0]
  m=64
 end
 setSpriteRect(gv("h")[0], 32,m,32,32, -32,-32,64,64)
elsif anime==12
 if gv("dx")[0]==0 #横移動してないときは正面向き
  m=0
 elsif gv("dx")[0]<0 #横移動してたらそっちを向く
  m=32
 else #0<gv("dx")[0]
  m=64
 end
 setSpriteRect(gv("h")[0], 0,m,32,32, -32,-32,64,64)
 anime=0; tama=tama+1 #一定の間隔で、自動で弾がひとつ出る
 if tama==5
  tama=1
 end
 if gv("j")[tama]==0 #今回の弾番号が出てない状態なら、位置と飛ぶ方向を決める
  gv("x")[tama]=gv("x")[0]; gv("y")[tama]=gv("y")[0]
  case gv("j")[0]
  when 1 gv("j")[tama]=1
  when 2 gv("j")[tama]=2
  end #case終
 end
end

setSpritePosition(gv("h")[0], gv("x")[0], gv("y")[0]) #宇宙人位置更新

n=1
while n<=4 #◆弾位置更新
 case gv("j")[n]
 when 1 #左向き移動中
  gv("x")[n]=gv("x")[n]-12
  if gv("x")[n]<-40
   gv("j")[n]=0 #画面外に来たら出てない状態にする
  end
 when 2 #右向き移動中
  gv("x")[n]=gv("x")[n]+12
  if 840<gv("x")[n]
   gv("j")[n]=0 #画面外に来たら出てない状態にする
  end
 end #case終
 hitcheck(n)
 setSpritePosition(gv("h")[n], gv("x")[n],gv("y")[n])
n=n+1
end

setText(z, "walk=",gv("walk"),"\nx0=",gv("x")[0],"\ny0=",gv("y")[0],"\nlife=",gv("j")[11] )
drawCanvas(); waitTime(20) #忘れずに入れる

end #keyループ終
endInput() #入力終


goBadEnding()
このメイン部分からは、ほぼ変更してないカモ
臨時のテキスト表示は完成したら消す
#chapter2
speak("ZONE ",gv("zone"),"  Clear")
sv("zone",gv("zone")+1)

deleteTextAll()

changeChapter("chapter1")
ゾーンクリア時の演出、そして次へ
【こんな感じになった】


よし、後はどんだけ根気良くゾーンを配置していくか、だけだわぁ~
つくってみるブログはとりあえず、終了カモ?仕組みは全部書いちゃったので、とりあえずゾーン20くらいを目標に作業を進めましょーか

ここまで読んでるくらいの暇な人はコレをベースにオリジナルな続きを作って勝手に公開しちゃってくだちぃ
お疲れしたー

コメントする

コメントするには、ログインする必要があります。

コメント一覧

コメントはありません。