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

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

先日リプレイを実装しようとしていたのですが、どうも上手く行きませんでした。
色々と検証してみた所、キー情報が128くらいまでだと上手く行くのですが256以上になると上手く動きませんでした。
なのでZキー(コード2048)などのキーの場合、リプレイが上手く動かなかったんですよね。

で、pokeのヘルプを読んでみると「p1で指定した変数のバッファ上で、p2で指定したインデックスの場所に
p3の値を書き込みます。値は0〜255までの1バイト(8bit)値になります。」
とあります。
つまり255以上の数字はpokeでは書き込めないんだろうと思い、wpokeを使用してみたりしたのですが、やはり上手く行かなかったんです。

よくよく考えてみたのですが、私はキー情報の書き込み時↓のようなスクリプトで書き込みしていました。
wpoke replay,timer,ky
ゲームタイマーに合わせてキー情報をreplayファイルに書き込んでいたのですが、このゲームタイマーは1フレームに付き1バイトづつ増えます。
でもwpokeは2バイトで書き込みをする命令なので、wpoke replay,timer,kyとしてしまうと、ゲームタイマーは1バイトしか増えないのに
replayファイルには2バイトで書き込んでしまうので、おかしくなっていたんです。

でwpoke replay,timer,kyをwpoke replay,timer*2,kyとする事で、上手く動くようになりました^^
(ちなみにlpokeを使うならtimer*4にすれば良いと思います)

そして、replayファイルを1つに纏める事も出来ました。
まずpoke命令ですが、これは単純に0123456789・・・・・・・・・・・と順番に書き込んで行ってると考えて良いようです。
なので、まずreplayファイル先頭にランダム用の数字を書き込み、その後からリプレイファイルを書き込みするようにすれば
ファイルを1つに纏める事が出来ました。

まずランダム用の数字をこんな感じで書き込みます→wpoke replay,0,randn
ランダム用の数字は4桁なので、replayファイルの先頭より4バイトを使用するって事になります。
イメージ的には例えばランダム用の数字が4355だとすると、replayファイルには4355000000000000・・・・・・・・・・と記録されるイメージ。

で次にリプレイファイルをwpoke replay,10+timer*2,kyと言う感じで記述すれば
キー情報はreplayファイルの先頭より10番目から記録されていくって感じ。
435500000041802148・・・・・・・・・・と記録されるイメージ。
あくまでも私の勝手なイメージですけどね^^;

で、それを別々にrandn=wpeek(replay,0)、ky=wpeek(replay,10+timer*2)と言う感じで取り出せばOKでした^^
なので、これを応用すればスコア情報などの色んな情報も一つに纏めれそうな感じですね。

で、上記をふまえてリプレイファイルを一つに纏めたスクリプトを作成してみました↓
*************************************
*get_mode
;リプレイ記録用変数
sdim replay,64000;リプレイ用にメモリを確保
fname="replay.dat"
timer=0;ゲームタイマー
dialog "「はい」:ゲームプレイ/「いいえ」:リプレイ再生",2
if stat=6 : playmode=0
if stat=7 : playmode=1 : gosub *load_data
*strat
screen 0,320,320,0,0,0 ;メインウインドウ0を240×320で用意

;■配列宣言
tmx=10 ;自機弾の数
dim tx,tmx ;自機弾のX座標の配列変数
dim ty,tmx ;自機弾のY座標の配列変数
dim tf,tmx ;自機弾が画面にあるか無いかを調べる配列変数
emt=1000;敵の弾
dim etx,emt : dim ety,emt ;敵弾の位置、移動量
dim etxv,emt ; etxv 敵弾x方向運動量
dim etyv,emt ; etyv 敵弾y方向運動量
dim etf,emt;敵弾のフラグ

SMAX=100;星の最大数
DIM X,SMAX ;星のx軸座標
DIM Y,SMAX ;星のy軸座標
DIM C,SMAX ;星の色
DIM S,SMAX ;星の移動速度

;星をランダムに表示
GSEL 0 : COLOR 0,0,0 : BOXF 0,0,320,320
REPEAT SMAX
X(CNT)=rnd(240)
Y(CNT)=rnd(320)
S(CNT)=rnd(4):S(CNT)=S(CNT)+1
COLOR rnd(245)+10,rnd(245)+10,rnd(245)+10
PSET X(CNT),Y(CNT)
LOOP
;流れる星のスクリプトは窓々遊々様のスクリプトを使用させて頂きました
;http://homepage1.nifty.com/takanon/

;■初期化
px=112:py=304 ;自機の初期位置
ex=0:ey=10 ;敵の初期位置
etx(cnt)=0:ety(cnt)=10 ;敵弾の初期位置
etxv(cnt)=-10:etyv(cnt)=-10;敵弾の移動量
etf(cnt)=0;敵弾の有無,0は無し
dx=8:dy=8 ;敵の移動量
dx=1:dy=1 ;敵弾の移動量
tx(cnt)=px:ty(cnt)=py ;自機弾の初期位置
tf(cnt)=0;自機弾の有無,0は無し
shottime=0;連射速度
st=0;ショットフラグ
ky=0;自機移動
space=0;ショットボタン
ef=1;敵の有無,1は有り
eh=0;敵弾用の変数
r=0.;敵弾用の変数
sc=0;スコア用
tamasu=1;弾の排出量

;■ランダム生成
if playmode=0 : gosub *rando_load;ゲームプレイ時はrandomize実行
if playmode=1 : gosub *rando_read;リプレイ再生時はrandomize読み込み

;■メインルーチン
*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 ;指定色で画面を塗りつぶす

;■星表示
REPEAT SMAX
COLOR rnd(245)+10,rnd(245)+10,rnd(245)+10
Y(CNT)=Y(CNT)+S(CNT)
IF Y(CNT)>320 :Y(CNT)=0
PSET X(CNT),Y(CNT)
LOOP

;■自機移動処理
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

;■自機弾発射処理
shottime-- ;連射為の処理
if hassya=1 : if shottime<0: st=1 ;スペースキーが押されていて、かつshottimeが0以下の時、stに1を代入
repeat tmx ;repeat〜loop間をtmx回繰り返す
if tf(cnt)=0 : if st=1{ ;tf(cnt)が0の時=画面に弾がない時、かつstが1の時(スペースキーを押している時){}内の命令を行う
tx(cnt)=px ;tx(cnt)(弾のx座標)にpx(自機のx座標)の値を代入
ty(cnt)=py ;ty(cnt)(弾のy座標)にpy(自機のy座標)の値を代入
tf(cnt)=1 ;tf(cnt)に1を代入。つまり画面に弾があると言う事
st=0 ;連射の為の処理
shottime=3 ;連射の為の処理
}
ty(cnt)-=5 : if ty(cnt)<-16 : tf(cnt)=0 :ty(cnt)=-16: st=0;弾を進めて画面から出たら弾を消す

if tf(cnt)=1{ ;画面に弾があるとき、{}内の命令を行う
pos tx(cnt),ty(cnt) ;自機弾の座標指定
color 255,255,255 : mes "□";□を表示
}
loop

;■敵発生、移動処理
if ef=0 : ex=rnd(220) : ey=0 :ef=1;敵が画面にいない時は敵生成
if ef=1 {;敵が画面にいる時は{}内の命令を行う
ex=ex+dx ;敵座標に移動量をプラス
if(ex<0)|(ex>224) :dx=-dx ;画面端で反転
ey=ey+dy
if(ey<0)|(ey>100) :dy=-dy ;y軸0〜100ドットの間で反転
pos ex,ey
color 255,0,0 : mes "■" ;■を表示
}

;■敵弾処理
if sc>500 : tamasu=2
if sc>1000 : tamasu=3
if sc>1500 : tamasu=4
if sc>2000 : tamasu=5
if sc>2500 : tamasu=6
if sc>3000 : tamasu=7
if sc>3500 : tamasu=8
if sc>4000 : tamasu=9
if sc>4500 : tamasu=10
if sc>5000 : tamasu=11
if timer¥6=0 : gosub *tama ;timer÷6の余りが0の時*tamaに移動
repeat emt ;emt回繰り返す
if etf(cnt)=1 { ;敵弾が画面に有る時{}内の命令を行う
etx(cnt)=etxv(cnt)+etx(cnt) ;敵弾のx軸の座標指定
ety(cnt)=etyv(cnt)+ety(cnt) ;敵弾のx軸の座標指定
pos etx(cnt),ety(cnt) ;敵弾の座標指定
color 255,255,0 : mes "○" ;○を表示
if etx(cnt)>240 : etf(cnt)=0 ;敵弾が画面から消えたら存在をなしにする
if etx(cnt)<-16 : etf(cnt)=0
if ety(cnt)>320 : etf(cnt)=0
if ety(cnt)<-16 : etf(cnt)=0
}
loop

;■敵弾当り判定
repeat emt ;emt回繰り返す
if etf(cnt)=0 : continue ;敵弾がない時はループを繰り返す。
ddx=(etx(cnt)+8)-(px+8) ;中心座標の計算
ddy=(ety(cnt)+8)-(py+8) ;中心座標の計算
if (abs(ddx)<4)&(abs(ddy)<4) { ;自機と敵との差が4ドット以下なら{}内の命令を行う
gosub *gameover};*gameoverに行く
loop

;■自機弾当り処理
repeat tmx ;repeat〜loop間をemx回繰り返す
if tf(cnt)=0 : continue ;tf(cnt)が0(画面に自機弾がない)ならばrepeatに戻る
if (abs(ex-tx(cnt))<16)&(abs(ey-ty(cnt))<16) { ;自機弾と敵との差が16ドット以下なら{}内の命令を行う
ef=0 : sc+50;敵消去
}
loop

color 0,50,50 ;色に黒を指定
boxf 240,0,320,320 ;指定色で画面を塗りつぶす
;■インフォ表示
pos 240,0:color 255,255,255:mes "score";スコアを表示
pos 240,20:color 255,255,255:mes ""+sc+"";スコアを表示
pos 240,50:color 255,255,255:mes "timer";タイマー入力を表示
pos 240,70:color 255,255,255:mes ""+timer+"";タイマー入力を表示
pos 240,100:color 255,255,255:mes "randomize";randomize数を表示
pos 240,120:color 255,255,255:mes ""+randn+"";randomize数を表示
pos 240,150 :color 255,255,255:mes "ky";キー入力数を表示
pos 240,170 :color 255,255,255:mes ""+ky+"";キー入力数を表示

;■Fps表示
fp++ ;フレーム数を覚えておく変数
time=gettime(6) ;timeに現在の秒数を代入
if time!=time2 { ;timeとtime2が等しくなければ{}内の命令を行う
fpc=fp ;fpc(表示するFps数)にfp(現在のフレーム数)を代入
fp=0 } ;フレーム数をクリア
pos 240,200 : mes "Fps";フレーム数の表示
pos 240,220 : mes ""+fpc+"" ;フレーム数の表示
time2=time ;time2に現在の秒数を代入(1秒ごとに比べる為)

redraw 1 ;画面を更新
await 16
goto *main ;*mainに戻る

;以下サブルーチン
;■敵弾処理
*tama
repeat emt ;emt回繰り返す
if etf(cnt)>0 : continue ;画面に弾がある時はrepeatに戻る
eh=eh+1 ;弾の数の為の計算
etf(cnt)=1 ;弾の存在を有にする
etx(cnt)=double(ex) : ety(cnt)=double(ey) ;弾の座標を実数で設定
ds=2 ;敵弾の速さ
r=double(r+0.6) ;弾の角度を実数で計算
etxv(cnt)=cos(r)*ds : etyv(cnt)=sin(r)*ds ;弾の移動量を角度より計算
if eh>tamasu : eh=0 :break ;10発弾を撃った時点でrepeatを抜ける
loop
return

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

;■方向キー入力
*key_input
;自機移動処理
stick ky,1039 ;キーボードのチェック
if ky&1 :px-=3
if ky&4 :px+=3
if ky&2 :py-=3
if ky&8 :py+=3
if ky&1024 {hassya=1}else{hassya=0}
wpoke replay,10+timer*2,ky;変数kyをリプレイデータに記録
return

;■方向キー出力
*read_replay
;リプレイデータを変数kyに代入
ky=wpeek(replay,10+timer*2)
if ky&1 :px-=3
if ky&4 :px+=3
if ky&2 :py-=3
if ky&8 :py+=3
if ky&1024 :{hassya=1}else{hassya=0}
return

;■ランダム入力
*rando_load
randn = gettime(4)*1000 + gettime(5)*100 + gettime(6)
randomize randn
wpoke replay,0,randn;replayファイルにランダム数を書き込み
return

;■ランダム出力
*rando_read
randn=wpeek(replay,0);replayファイルにランダム数を読み込み
randomize randn
return

;■ゲームオーバー
*gameover
if playmode=0 {
bsave fname,replay,64000;fnameにreplayデータをセーブ
wait 10
}
goto *get_mode
*************************************
HSP3.0使用
タブキーで弾発射
実行すると↓こんな感じ
214.jpg
文字が読みにくかったので分けて表示するようにし、得点とレベル?のような物も追加しました。
それと、画面が寂しかったので窓々遊々さんの所にあった流れる星のスクリプトを活用させてもらって、背景も追加しました。
このスクリプトではタブキーが弾発射になっています。
ホントはZキーで作りたかったのですが、stick命令ではzキーは扱えないみたいなので、stick命令で扱える一番大きい数字のキーが
タブキー(コード1024)だったので、タブキーが弾発射になっています。

とりあえずコレで、リプレイは何とかなりそうな感じ。
でも、実際にコレを今作っているSTGに組み込むと、また色んな不具合が出るんやろな〜と思ってる次第です^^;
PR
この記事にコメントする
お名前
タイトル
メールアドレス
URL
コメント
パスワード   Vodafone絵文字 i-mode絵文字 Ezweb絵文字
この記事へのトラックバック
この記事にトラックバックする:
Twitter
カレンダー
03 2024/04 05
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
最新コメント
[04/20 kt.]
[04/19 うぇむ]
[11/24 kt.]
[11/21 NONAME]
[11/24 kt.]
プロフィール
HN:
kt.
性別:
男性
自己紹介:
プログラミング経験は昔ファミリーベーシックでちょっとさわったくらい。
好きなSTGは、怒首領蜂大往生、エスプガルーダ(2)等の弾幕STGやら雷電シリーズなんかの非弾幕、バトルガレッガ、グラディウスシリーズ、R-TYPE等、STGなら何でも好きです。
音楽がカッコイイSTGが特に好きで、並木学氏は最高!
ブログ内検索
忍者ブログ [PR]