忍者ブログ
まったくのプログラミング素人の筆者がC++/HSPを使用してSTG(シューティングゲーム)を作っていく過程を書くブログでしたが最近は脱線気味。プログラミング以外にも、ゲーム関連の記事、日々の戯言など。
×

[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。

以前、自機にレーザーを撃たせようとしたのですが、表示方法がわからずに後回しにしていました。
何がわからなかったのかと言うと、自機が移動していない時は良いのですが、自機が移動している時に
レーザーを発射すると↓のような状態に・・・
1151.jpg
これは、レーザー自体を短い画像を繋げて表現しているからなのですが、これを自機が動いている時は全てのレーザーを移動させようとして
やり方がわかりませんでした。

hspdxfixのスプライト機能はとても優秀で、一度移動方向を指定すれば後は指示を書かなくても勝手に移動して画面から消えると勝手に消えてくれます。
非常に便利なのですが、この勝手に動いてくれるおかげで、動かした後に別の方向に移動させるにはどうすれば???となってしまったんです。

で、簡単なレーザー表示スクリプトを作って考えてみました。
*************************************
*start
#include "hspdxfix.as"
#include "CK_JOYFORCE.AS"
;■ DirectX 初期化&チェック
dialog "fullscreenで起動しますか?「はい」を選択した場合、画面解像度を640×480に変更します。",2,"Config"
if stat=6:screenmode=0
if stat=7:screenmode=1
es_ini 1124,1124,360;スプライト最大数1124,キャラクタ最大数1124,角度360度
es_screen 640,480,16,0,screenmode,1;directX使用時の解像度640*480
if stat=1 : goto *dxerr1
if stat=2 : goto *dxerr2
goto *setup
*dxerr1
dialog "DirectXの初期化に失敗しました。",1 : end
*dxerr2
dialog "スクリーンの初期化に失敗しました。",1 : end
*dxerr3
es_bye : wait 100
dialog "VRAMの容量が不足しています。",1 : end

*setup
;■ バッファへ画像の読みこみ
buffer 2,640,480,0 ;バッファ作成
pos 0,0 : picload "laser.jpg",1 ;バッファへ読み込み
es_buffer 0,0 ;オフスクリーンバッファへの転送
if stat=1 : goto *dxerr3
;自機,0
es_size 48,48,20,0
es_pat 0,0,0
;自機レーザー,1
es_size 48,48,80,0
es_pat 1,48,0,0

;■スプライト登録
es_window 0,0,412,480 ;スプライト描写範囲設定
es_area -128,-145,413,481 ;スプライト有効範囲設定
es_set 701,px,py,0 ;自機スプライト登録(0)
es_type 701,1 ;自機Type値設定(1)
gsel 0
es_cls
es_sync
wait 100

*gamesetup
px=192:py=432 ;自機の初期位置
move=2 ;自機速度

;■ メインルーチン
*main
es_cls;画面クリア
gosub *jikimove
gosub *jikitama1
es_draw;スプライト描画
gosub *kabehyouji
gosub *fpshyouji
await 0
es_sync 16,2;ウェイト
getkey syuryo,27:if syuryo=1:end;ESCを押すと強制終了
goto *main

*jikimove;自機移動処理
ck_joystick ky,15;キーボードのチェック,非トリガータイプ設定
xv=(ky>>2&1)-(ky&1);x軸移動処理
yv=(ky>>3&1)-(ky>>1&1);y軸移動処理
px=xv*move+px : py=yv*move+py;自機移動処理
;画面からはみ出さない為の処理
if px<0 :px=0
if px>368 :px=368
if py<0 :py=0
if py>432 :py=432
es_pos 701,px,py;スプライト表示(バッファ画面)
return

*jikitama1;自機弾移動処理
shottime--;連射時間をマイナス
ck_joystick ky,2048
if ky&2048:if shottime<0 : shot=1;Zキーのチェック
if shot=1 {
es_exnew jikitama,900,999
if jikitama=-1 : return
es_set jikitama,px,py,1 ;自機弾スプライト設置(キャラクタ番号1)
es_type jikitama,4 ;自機弾type値(4)
shottime=1 ;連射制御
shot=0
}
;レーザー処理
jikitama=0
repeat
es_find jikitama,4,jikitama
if jikitama=-1 : break
es_apos jikitama,0,-10,150 ;レーザー表示
es_get jikitamax,jikitama,3 ;x座標取得
es_get jikitamay,jikitama,5 ;Y座標取得
if ky&1:es_pos jikitama,jikitamax-2,jikitamay;レーザー移動処理
if ky&4:es_pos jikitama,jikitamax+2,jikitamay;レーザー移動処理
if px=0 : es_pos jikitama,jikitamax,jikitamay;レーザー移動処理
if px=368 : es_pos jikitama,jikitamax,jikitamay;レーザー移動処理
jikitama++
loop
return

*kabehyouji
gmode 0,228,480
es_fill 416,0,50;画面右をを塗り潰す
return

*fpshyouji
;fps表示
es_getfps fps
color 255,255,255
pos 416,440
es_fmes"ky"+ky+""
pos 416,460
es_fmes"fps"+fps+""
return
*************************************
HSP3.0使用 hspdxfix使用 CK_JOYFORCE使用 画像は↓を使用
laser.jpg
具体的にどうするのかと言うと、まずZボタンを押した時にレーザーを表示させます。
で、その表示されたレーザー全てを検索して、例えば右に動いている時は上に移動している移動量+右に動いている移動量をプラスして
表示するようにすれば、レーザーっぽく見えるようになりました^^

今までは、レーザーの移動にes_adir jikitama,180,1000と言うような書き方をしていたので、右に動いた時は移動方向はどうすれば?
となってしまっていたのですが、es_adirではなくes_aposを使って、es_getでレーザーのX軸座標とY軸座標を調べて
自機の移動速度をレーザーのX座標にプラスすれば、上手く出来ました^^

1052.jpg
こんな感じで(といっても画像じゃわかりませんが^^;)自機が移動しても、レーザーはちゃんと真っ直ぐに表示されるようになりました^^
PR
昨日作ったアイテムを自動回収出来るようにしてみました。
まず、昨日作った時点で敵を倒すと、その地点から下に向かってアイテムが移動するだけだったのですが、出来れば一瞬上に移動してから
下に落ちるように(ジャンプしてるみたいな感じ)したかったので、最初にそれを作ってみました。

アイテム(クリスタル)の出現は↓のようなスクリプトで出現させているのですが
*************************************
;クリスタル出現処理
es_exnew cry,1,499
if cry=-1 : break
es_set cry,ex,ey,150
es_effect cry,36,36,0,0,0,ESB_ALPHA,200
; 爆風設置
es_type cry,512
; 効果type値(512)
es_apos cry,0,-10,100
*************************************
最後の行のes_apos cry,0,-10,100でまずY軸方向に上に移動させます。

で、次にアイテムを↓のように検索して・・・
*************************************
cry=0
repeat
es_find cry,512,cry ;クリスタル(512)スプライト検索
if cry=-1 : break ;無ければbreak
es_get cryy,cry,9 ;クリスタルy座標取得
cryy++ ;クリスタル速度アップ
if cryy>4 : cryy=4
es_apos cry,0,cryy,100 ;クリスタル移動
cry++
loop
*************************************
Y軸方向の移動距離をプラスしていけば、最初はマイナスだったのがプラスに移動するので、上に上がってから下がってきます。
このままだと下がっていく時に速度が上がり過ぎるので、下がっていく時の速度を一定以上にしないようにすればOK。

で、自動回収ですが、これは自機とアイテムの距離を計算して、一定以下になったら自機に向かってくるようにしました。
*************************************
;クリスタル移動,自動回収処理
cry=0
repeat
es_find cry,512,cry ;クリスタル(512)スプライト検索
if cry=-1 : break ;無ければbreak
es_get cryy,cry,9 ;クリスタルy座標取得
cryy++ ;クリスタル速度アップ
if cryy>4 : cryy=4
es_apos cry,0,cryy,100 ;クリスタル移動
if (jikicnt<150)&(jiki>0){
es_check jikicry,cry,1 ;クリスタルと自機の当り判定
es_get cryex,cry,3 ;x座標取得
es_get cryey,cry,5 ;Y座標取得

jcx=(cryex+13)-(px+24) ;自機とクリスタルの当り判定計算
jcy=(cryey+13)-(py+24) ;
if (abs(jcx)<100)&(abs(jcy)<100):es_aim cry,px,py,800
;自機とクリスタルの位置が100ドット以下なら、自動回収
if jikicry>0 {
es_kill cry ;自機とクリスタルが当ったらクリスタル消去
}
}
cry++
loop
*************************************
このような感じで、まずアイテムのX座標とY座標を取得してjcx=(cryex+13)-(px+24)と jcy=(cryey+13)-(py+24)でそれぞれの
座標の差を求めます。
後はif (abs(jcx)<100)&(abs(jcy)<100):es_aim cry,px,py,800で自機とアイテムのX座標とY座標の差が
100ドット以下になったら自機に向かってアイテムが移動するようにしました。
で、自機とアイテムが当ったらアイテム消去しています。
後は、ここにアイテムを取ったときの処理を入れれば良いのですが、どうするかは悩み中です(汗)

とりあえずこれで、自機とアイテムの距離が100ドット以下になったら、自動回収が出来るようになりました^^
ここ最近ゲームシステムを考えているのですが、どうも考えが上手くまとまりません・・・
とりあえず、稼ぎシステムとして回収アイテムは出そうと思っていたので、先に作ってみました。
イメージ的には回転するクリスタルを作ろうと思って書いてみたのですが、全然上手く書けません(汗)
どうしよう・・・と思っていたのですが、良く考えてみるとDOGAを使ってクリスタルっぽいのを作れば簡単や!って事に気づきました^^
で、こんなの作ってみました↓
11_1.jpg
なかなかクリスタルっぽいです^^
後は回転させながら、作画していけば立派な回転するクリスタルの完成です!
CRY.GIF
こんな感じで回転します。(実際には半透明処理もさせていますが)

で、とりあえず敵を倒した時に出現するようにしてみました。
11_10.jpg
でも、今の所ただ出現するだけで、まだ回収は出来ません^^;

と言うか、このクリスタルをどう使うかを悩んでいるんですよね・・・
弾消しで、一気に出現させて一気に回収でスコアアップとか気持ち良さそうやなぁとか思ったり思わなかったりで
色々と悩み中で先に進めません(汗)
ゲームのリプレイ機能は是非とも導入したいと思っていたのですが、なんとなく非常にややこしいのでは?と思っていました。
それにゲーム自体出来ていないし、リプレイなんてまだまだ先の事・・・と思っていたのですが、興味本位で検索してみるとわかりやすく
説明されているサイトを発見しました。
Presys net.さんと言うサイトのHSP-Roomにリプレイのサンプルがあり見てみると、とても簡単に実現出来そうです^^
(他にも色々なサンプルがあり、とても参考になります)

で、それを元に以前作った自機狙いサンプルを改造してリプレイ機能を足してみました↓
*************************************
*get_mode
;リプレイ記録用変数
sdim replay,32000
fname="replay1.dat"
timer=0;ゲームタイマー
dialog "「はい」:ゲームプレイ/「いいえ」:リプレイ再生",2
if stat=6 : playmode=0
if stat=7 : playmode=1 : gosub *load_data
*strat
screen 0,240,320,0,0,0 ;メインウインドウ0を240×320で用意
px=112:py=304 ;自機の初期位置
ex=0:ey=10 ;敵の初期位置
etx=0:ety=10 ;敵弾の初期位置
dx=8:dy=8 ;敵の移動量
dx=1:dy=1 ;敵弾の移動量

*main
getkey syuryo,27:if syuryo=1:end;ESCを押すと強制終了
timer=timer+(timer<32000) ;ゲームタイマー加算
if playmode=0 : gosub *key_input;ゲームプレイ時はキー入力へ
if playmode=1 : gosub *read_replay;リプレイ再生時はリプレイファイル読み込みへ
redraw 0 ;仮想画面を指定
color 0,0,0 ;色に黒を指定
boxf 0,0,240,320 ;指定色で画面を塗りつぶす

pos px,py ;自機の座標指定
color 0,0,255 : mes "▲" ;青で▲を表示
if px<0 :px=0
if px>224 :px=224
if py<0 :py=0
if py>304 :py=304

;敵移動処理
ex=ex+dx ;敵座標に移動量をプラス
if(ex<0)|(ex>224) :dx=-dx ;画面端で反転
ey=ey+dy
if(ey<0)|(ey>304) :dy=-dy
pos ex,ey
color 255,0,0 : mes "■"

;敵弾処理
if etf=0 { ;敵弾が画面にない時{}内の処理を行う
ds=5 ;敵弾の速さ
r=atan(py-ey, px-ex) ;敵と自機との角度を求める
etxv = cos(r)*ds ;敵弾のx軸方向の移動量
etyv = sin(r)*ds ;敵弾のy軸方向の移動量
etf=1 ;弾の存在を有にする
etx=ex : ety=ey ;敵弾の初期座標
}
if etf=1 { ;敵弾が画面に有る時{}内の命令を行う
etx=etxv+etx ;敵弾のx軸の座標指定
ety=etyv+ety ;敵弾のx軸の座標指定
pos etx,ety ;敵弾の座標指定
color 255,255,0 : mes "●"

;敵弾当り判定
if (abs(px-etx)<8)&(abs(py-ety)<8) { ;自機と敵との差が4ドット以下なら{}}内の命令を行う
gosub *gameover};*gameoverに行く


if etx>240 : etf=0 ;敵弾が画面から消えたら存在をなしにする
if etx<0 : etf=0
if ety>320 : etf=0
if ety<0 : etf=0
}
pos 0,0:color 255,255,255:mes ""+ky+"";キー入力を表示
redraw 1 ;画面を更新
await 1
goto *main ;*mainに戻る

*key_input
;自機移動処理
stick ky,15 ;キーボードのチェック
if ky&1 :px-=4
if ky&4 :px+=4
if ky&2 :py-=4
if ky&8 :py+=4
;変数kyをリプレイデータに記録
poke replay,timer,ky
return

*read_replay
;リプレイデータを変数kyに代入
ky=peek(replay,timer)
if ky&1 :px-=4
if ky&4 :px+=4
if ky&2 :py-=4
if ky&8 :py+=4
return

*load_data
bload fname,replay,32000;replayデータにfnameをロード
wait 10
return

*gameover
if playmode=0 {
bsave fname,replay,32000;fnameにreplayデータをセーブ
wait 10
}
goto *get_mode
*************************************
HSP3.0使用
実行すると、まずダイアログが出てきてゲームプレイかリプレイ再生かを聞いてきます。
で、ゲームプレイ開始で敵弾に当るとゲームオーバーでダイアログが出てきてゲームプレイかリプレイ再生のどちらかを選ぶループになっています。
実行するとこんな感じ↓
1025.jpg
当初、参考にさせて頂いたサンプルがHSP2.6用だったので、HSP3.0とは記述が違い悩みました(汗)
(特にpeekの記述方法が違うのに全然気づかず悩みました^^;)

基本的な考え方は、ゲーム時間の変数timerとキー読み込みの為の変数kyとを同期させて変数replayに記録するって感じでしょうか?

こんな簡単な記述だけでリプレイ機能が出来るとは夢にも思っていなかったので、ちょっと感動してしまいました^^
といっても、敵の動きに乱数を使った場合などはどうするのかは、まだ良くわかってませんので
ちゃんとしたリプレイ機能には程遠い感じもしますが(汗)
ここ最近は自機の当り判定を無しにして無敵状態でスクリプトを作っていました。
で、色々と確認する為に無敵を解除したところ、自機が死んだ時に本来は何も表示されないはずなのに
何故か敵弾が勝手に自機の位置に表示されてしまいます・・・
しかも、表示されたりされなかったりで、一定の条件で発生するって訳でもなく原因を探すのに苦労しました(汗)

色々と原因を探ってみた所、自機の当り判定画像を表示させないようにするとバグが発生しない事がわかりました。
(気づくの相当時間かかりましたが^^;)
今までは自機が敵か敵弾に当った時に自機の当り判定画像を削除していたのですが、そうするのではなく
自機が復活するまでのカウントをしている変数で削除するように
if (jikicnt<250)&(jikicnt>150) : es_kill 700
みたいにすれば表示されなくなり、なんとかバグ取りする事が出来ました^^

これからも、ちょこちょことバグ取りしなければならないと思うと憂鬱です・・・
Twitter
カレンダー
02 2026/03 04
S M T W T F S
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31
最新コメント
[04/20 kt.]
[04/19 うぇむ]
[11/24 kt.]
[11/21 NONAME]
[11/24 kt.]
プロフィール
HN:
kt.
性別:
男性
自己紹介:
プログラミング経験は昔ファミリーベーシックでちょっとさわったくらい。
好きなSTGは、怒首領蜂大往生、エスプガルーダ(2)等の弾幕STGやら雷電シリーズなんかの非弾幕、バトルガレッガ、グラディウスシリーズ、R-TYPE等、STGなら何でも好きです。
音楽がカッコイイSTGが特に好きで、並木学氏は最高!
ブログ内検索
忍者ブログ [PR]