HSPポータル
サイトマップ お問い合わせ


HSPTV!掲示板


未解決 解決 停止 削除要請

2016
0711
Freedom Programmer(ふりぷろ)ビート●ニア風ゲームを作ろうと奮闘していますが、数々の問題が…8解決


Freedom Programmer(ふりぷろ)

リンク

2016/7/11(Mon) 19:31:26|NO.76151

こんばんは。

ビート●ニアIIDX風のゲームを夏の自由課題プロジェクトとして
製作しているのですが、2つの問題に頭を抱えています。
その問題が何かというと

1、譜面のタイミングが合わない (これが最重要)
2、譜面再生中、キーボードのキーを押すとFPSが変動する
  あと、「キーを押した直後のみ判定を行う」の実装がわからない

【スクリプト】

#include "d3m.hsp" title "Beatrush 譜面テスター" screen 0,800,600 max=2000 bpm=0 dim timing,max dim key,max dim ny,max dim tuuka,max dim dr,max dim tk,8 dim cir,8 dim xmore,8 dim ymore,8 dim feed,8 dim tim,8 sdim filename sdim musicname sdim log sdim notes sdim keys sdim bpms repeat max-1 timing(cnt)=double(timing(cnt)) ny(cnt)=double(ny(cnt)) loop time = double(time) movms = double(movms) onebeat = double(onebeat) *filenameinput mes "譜面ファイル" mesbox filename,300,60,5 mes "" mes "音楽ファイル" mesbox musicname,300,60,5 mes "" button goto "",*check stop *check cls mes "Checking Notes Timing Data..." exist filename : if strsize =-1 { mes "譜面ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ notesel log noteload filename exist musicname : if strsize =-1 { mes "音楽ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ mmload musicname,0,1 mes "タイミング情報を読み込んでいます" repeat noteget notes,count if notes="" { mes "done." break }else{ timing(cnt) = double(notes)  count + 1 noteget keys,count if keys = "" { mes "Error in Keycode Read Line(" + count + ")" stop }else{ if keys="A" : key(cnt)=1 if keys="I" : key(cnt)=2 if keys="S" : key(cnt)=3 if keys="O" : key(cnt)=4 if keys="D" : key(cnt)=5 if keys="P" : key(cnt)=6 if keys="F" : key(cnt)=7 if keys="B" : key(cnt)=8 count + 1 } } loop noteget bpms,count+1 if bpms = "" { mes "Error in BPM read line" stop }else{ bpm = int(bpms) } } } onebeat = 60000/bpm  //一拍の時間 movms = 500.0/onebeat //Y座標が0から500までの1pxあたりの移動量 dim ny,max mmplay 0 repeat redraw 0 color 0,0,0 : boxf color 255,255,255 line 30,0,30,600 line 50,0,50,600 line 70,0,70,600 line 90,0,90,600 line 110,0,110,600 line 130,0,130,600 line 150,0,150,600 line 170,0,170,600 line 0,500,170,500 pos 200,0 mes "First Notes : " + timing(0) mes "Time :" + time mes "FPS :" + d3getfps() mes "BPM :" + bpm mes "movms:" + movms mes "one.b:" + onebeat mes "All.n:" + count/2 mes "ライン通過:" + tuuka gosub *draw gosub *move time + movms redraw 1 await 16 loop *draw repeat count/2 if timing(cnt)<=time :if dr(cnt)=1{ if key(cnt) = 1 : color 255,255,255 : boxf 31,ny(cnt),50,ny(cnt)+5 if key(cnt) = 2 : color 0,0,255 : boxf 51,ny(cnt),70,ny(cnt)+5 if key(cnt) = 3 : color 255,255,255 : boxf 71,ny(cnt),90,ny(cnt)+5 if key(cnt) = 4 : color 0,0,255 : boxf 91,ny(cnt),110,ny(cnt)+5 if key(cnt) = 5 : color 255,255,255 : boxf 111,ny(cnt),130,ny(cnt)+5 if key(cnt) = 6 : color 0,0,255 : boxf 131,ny(cnt),150,ny(cnt)+5 if key(cnt) = 7 : color 255,255,255 : boxf 151,ny(cnt),170,ny(cnt)+5 if key(cnt) = 8 : color 255,0,0 : boxf 0,ny(cnt),30,ny(cnt)+5 } loop return *move repeat count/2 if dr(cnt)=0 : if timing(cnt)<=time : dr(cnt)=1 if dr(cnt)=1 : ny(cnt)+movms if dr(cnt)=1 : if ny(cnt)>=500 : dr(cnt)=2 : tuuka+1 { if key(cnt)=1 : tk(0)=1 //ここから if key(cnt)=2 : tk(1)=1 if key(cnt)=3 : tk(2)=1 if key(cnt)=4 : tk(3)=1 if key(cnt)=5 : tk(4)=1 if key(cnt)=6 : tk(5)=1 if key(cnt)=7 : tk(6)=1 if key(cnt)=8 : tk(7)=1 //ここまでのスプリクトは関係ありません } loop return

※譜面再生用スクリプトなのでタイミング判定はありません。
 (自分がタイミング判定のスクリプトを上手く組めないという理由もある)

【譜面データ】

1000.000000 タイミング(これを基本としてタイミングを合わせます)
A      キー (どこのノーツなのかを表します)

2行がまとまり、1つのノーツタイミングデータとなります


【問題△砲弔い董暸keycode変数はあらかじめ、文字コードを代入しています。

repeat redraw 0 color 0,0,0 : boxf color 255,255,255  (中略) repeat 9,1 getkey a,keycode(cnt) : if a {  (判定処理) } loop redraw 1 await 16 loop …一体なにがいけないんでしょうか? だれか、助けてください!!



この記事に返信する


通りすがり

リンク

2016/7/11(Mon) 20:32:15|NO.76152

直ぐにわかる範囲だと
boxfで全画面塗りつぶさなくてもいいのでは?

gcopyで別の画面に描写したものを写す(boxfも必要なくなる)が基本



通りすがり

リンク

2016/7/11(Mon) 20:48:09|NO.76153

過去に 似たような質問があったよ

ttp://hsp.tv/play/pforum.php?mode=pastwch&num=21566



Freedom Programmer(ふりぷろ)

リンク

2016/7/11(Mon) 21:43:06|NO.76155

似たような質問がありましたか…
申し訳ありません。調べ不足です…。

あと、説明が雑ですいません。

ご迷惑をおかけしました…。



暇人

リンク

2016/7/11(Mon) 21:46:07|NO.76156

色々とおかしい・・・
>movms = 500.0/onebeat //Y座標が0から500までの1pxあたりの移動量
これは500ドットを1ビートの時間内に進む時の1msの移動量になってるので
使用時にはミリ秒の経過時間を掛ける必要がある
> if dr(cnt)=1 : ny(cnt)+movms
これを

if dr(cnt)=1 : ny(cnt)=movms*ノートの経過ミリ秒
の様にする

>time + movms


time=スタートからの経過ミリ秒
にする

それから
> if dr(cnt)=0 : if timing(cnt)<=time : dr(cnt)=1
これだと出現タイミングになってしまうので
判定位置のタイミングにはならない

手っ取り早い解決策としては
上のmovms、timeの修正をしてる仮定で
>movms = 500.0/onebeat //Y座標が0から500までの1pxあたりの移動量
の下あたりに

repeat count/2 timing(cnt)-=500.0/movms loop
を追加すると
500ドット分タイミングがずれるので
判定位置で経過時間と元の指定タイミングが同じになる



Freedom Programmer(ふりぷろ)

リンク

2016/7/12(Tue) 22:15:46|NO.76165

…すいません。ご返信が遅れました。
ご指摘ありがとうございます。

・・・まだ、試行錯誤中です。



Freedom Programmer(ふりぷろ)

リンク

2016/7/13(Wed) 20:00:55|NO.76180

暇人さん


#include "d3m.hsp" title "Beatrush 譜面テスター" screen 0,800,600 max=2000 bpm=0 dim timing,max //タイミング情報用 dim key,max //出現位置 dim ny,max //ノートのYポジション dim tuuka,max //通過フラグ dim dr,max //描画フラグ dim tk,8 dim cir,8 dim xmore,8 dim ymore,8 dim feed,8 dim tim,8 dim keika,max //ノートごとの通過フラグ dim keikastart,max //ノートごとの出現時の時間代入用 dim lk,max sdim filename sdim musicname sdim log sdim notes sdim keys sdim bpms repeat max-1 timing(cnt)=double(timing(cnt)) ny(cnt)=double(ny(cnt)) loop time = double(time) movms = double(movms) onebeat = double(onebeat) filename = "max300.brn" musicname = "max 300.mp3" *filenameinput mes "譜面ファイル" mesbox filename,300,60,5 mes "" mes "音楽ファイル" mesbox musicname,300,60,5 mes "" button goto "",*check stop //ここから *check cls mes "Checking Notes Timing Data..." exist filename : if strsize =-1 { mes "譜面ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ notesel log noteload filename exist musicname : if strsize =-1 { mes "音楽ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ mmload musicname,0,1 mes "タイミング情報を読み込んでいます" repeat noteget notes,count if notes="" { mes "done." break }else{ timing(cnt) = double(notes)// - 8.174 count + 1 noteget keys,count if keys = "" { mes "Error in Keycode Read Line(" + count + ")" stop }else{ if keys="A" : key(cnt)=1 if keys="I" : key(cnt)=2 if keys="S" : key(cnt)=3 if keys="O" : key(cnt)=4 if keys="D" : key(cnt)=5 if keys="P" : key(cnt)=6 if keys="F" : key(cnt)=7 if keys="B" : key(cnt)=8 count + 1 } } loop noteget bpms,count+1 if bpms = "" { mes "Error in BPM read line" stop }else{ bpm = int(bpms) } } } //ここまでタイミング・ノート位置のデータ読み込み部分 onebeat = 60000/bpm //1拍の時間を求める movms = 500.0/onebeat //1msあたりの移動量を求める repeat count/2 timing(cnt) - 500.0/movms //500ドット分ずらす loop mmplay 0 start_tim = d3timer() //再生開始時間をstart_timに代入 repeat redraw 0 color 0,0,0 : boxf color 255,255,255 line 30,0,30,600 line 50,0,50,600 line 70,0,70,600 line 90,0,90,600 line 110,0,110,600 line 130,0,130,600 line 150,0,150,600 line 170,0,170,600 line 0,500,170,500 pos 200,0 mes "First Notes : " + timing(0) //こ↑こ↓から mes "Time :" + time mes "FPS :" + d3getfps() mes "BPM :" + bpm mes "movms:" + movms mes "one.b:" + onebeat mes "All.n:" + count/2 mes "ライン通過:" + tuuka mes "経過時間" + keika(0) //こ↑こ↓までデバッグ用のモニターみたいなやつ gosub *draw gosub *move gosub *tims time = d3timer() - start_tim redraw 1 await 16 loop *draw repeat count/2 if timing(cnt)<=time :if dr(cnt)=1{ if key(cnt) = 1 : color 255,255,255 : boxf 31,ny(cnt),50,ny(cnt)+5 :if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 //フラグが0でノート出現のタイミングが来たら if key(cnt) = 2 : color 0,0,255 : boxf 51,ny(cnt),70,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 //ノートの出現時に現在の時間を記録し、フラグを1にする if key(cnt) = 3 : color 255,255,255 : boxf 71,ny(cnt),90,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 if key(cnt) = 4 : color 0,0,255 : boxf 91,ny(cnt),110,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 if key(cnt) = 5 : color 255,255,255 : boxf 111,ny(cnt),130,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 if key(cnt) = 6 : color 0,0,255 : boxf 131,ny(cnt),150,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 if key(cnt) = 7 : color 255,255,255 : boxf 151,ny(cnt),170,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 if key(cnt) = 8 : color 255,0,0 : boxf 0,ny(cnt),30,ny(cnt)+5:if lk(cnt)=0 : keikastart(cnt)=d3timer() : lk(cnt)=1 } loop return *move repeat count/2 if dr(cnt)=0 : if timing(cnt)<=time : dr(cnt)=1 if dr(cnt)=1 :ny(cnt)=movms*keika(cnt) //移動量*ノート経過時間 if dr(cnt)=1 : if ny(cnt)>=500 : dr(cnt)=2 : tuuka+1 { } loop return *tims repeat count/2 if dr(cnt)= 1 : keika(cnt) = abs( keikastart(cnt) - d3timer()) //ノート経過時間を計算 loop return

このスクリプトで実行すると
データで指定した時間にきちんとタイミングを合わせてくれたものの
一瞬しかノートが見えなくなってしまいました。

原因を探しましたがわからずのままです…

申し訳ありませんが、お教えいただけませんか?



暇人

リンク

2016/7/13(Wed) 21:30:08|NO.76183

ざっと見ただけだけど
keikastartは描画時じゃ無く出現時に入れないと
>if dr(cnt)= 1 : keika(cnt) = abs( keikastart(cnt) - d3timer()) //ノート経過時間を計算
がgosub *drawからgosub *timsまでの時間しかkeika(cnt)に入らない

て、言うか発生タイミングはtimingに入ってるんだから座標決定時に
再生開始からの経過時間を引けば良い

こんな感じ

#include "d3m.hsp" title "Beatrush 譜面テスター" screen 0,800,600 dim tk,8 dim cir,8 dim xmore,8 dim ymore,8 dim feed,8 dim tim,8 sdim filename sdim musicname sdim log sdim notes sdim keys sdim bpms //各キーのノート表示x座標(0は無しで1〜8を使用するので要素数9) notx=0, 31,51, 71,91, 111,131, 151, 0 //各キーのノート幅 notsx=0, 20,20, 20,20, 20, 20, 20, 30 //各キーのノート色 notr=0, 255,0, 255,0, 255,0, 255, 255 notg=0, 255,0, 255,0, 255,0, 255, 0 notb=0, 255,255, 255,255, 255,255, 255, 0 //テスト用にデータ設定 musicname=dir_exe+"\\hsptv\\bgm1.mid" //bgm1.mid用のノートデータを作る ob = 60000.0/144.0 //bgm1.midの一拍の時間 tempstr="" repeat 200 //基本的なドラムをセット if (cnt\2)=0 { if (cnt\4)=2 {tempstr+=""+(ob*cnt-ob/2.0)+"\nB\n"} tempstr+=""+(ob*cnt)+"\nB\n" }else{ tempstr+=""+(ob*cnt)+"\nA\n" } loop tempstr+="\n144.0" memfile tempstr //作ったデータをnoteloadで読み込めるようにメモリストリームに設定 filename="MEM:file.mid" //メモリストリームを読み込むためのファイル名を代入 //ここまで *filenameinput mes "譜面ファイル" mesbox filename,300,60,5 mes "" mes "音楽ファイル" mesbox musicname,300,60,5 mes "" button goto "",*check stop *check cls mes "Checking Notes Timing Data..." exist filename : if strsize =-1 { mes "譜面ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ notesel log noteload filename ddim timing,notemax/2 dim key,notemax/2 ddim ny,notemax/2 dim dr,notemax/2 exist musicname : if strsize =-1 { mes "音楽ファイルが存在しません" wait 100 cls 1 goto *filenameinput }else{ //mmload musicname,0,1 //midiの場合デフォルトのデバイスだと時間関係の精度が使い物にならないのでmpegvideoを使用(mp3,wav等も使用できる) //これはmmplayで再生する場合にも言えるのでmidiの場合mmplayは使わない方が良い(精度が必要な場合) mci "open \""+musicname+"\" type mpegvideo alias bgm" //以降 bgm がこのファイルを示す文字列になる if stat = -1 {mci "open \""+musicname+"\" type mpegvideo2 alias bgm"} //mpegvideoが使えなかったらmpegvideo2を使用 mci "setaudio bgm volume to 100" //midiの場合ボリュームが最大になってる事があるので調整 onexit *exit mes "タイミング情報を読み込んでいます" repeat noteget notes,count if notes="" { mes "done." break }else{ timing(cnt) = double(notes)  count + 1 noteget keys,count if keys = "" { mes "Error in Keycode Read Line(" + count + ")" stop }else{ if keys="A" : key(cnt)=1 if keys="I" : key(cnt)=2 if keys="S" : key(cnt)=3 if keys="O" : key(cnt)=4 if keys="D" : key(cnt)=5 if keys="P" : key(cnt)=6 if keys="F" : key(cnt)=7 if keys="B" : key(cnt)=8 count + 1 } } loop noteget bpms,count+1 mes bpms if bpms = "" { mes "Error in BPM read line" stop }else{ bpm = double(bpms)//整数とは限らないので } } } max=count/2 //ノート総数 onebeat = 60000.0/bpm //一拍(四分音符)の時間(bpmが実数だったり誤差を少なくしたいので実数で計算) ViewerTime=onebeat*4 //ノートが画面から消えるまでの時間(onebeat*4で1小節分) movms =500.0/ViewerTime //Y座標が0から500までの1msあたりの移動量 //判定位置までの必要時間を算出 StartAdjust=500.0/movms-onebeat/4 //midiだからかonebeat/4(16部音符分)遅らせるとタイミングが合う //mmplay 0 mci "play bgm" start_tim=d3timer()-StartAdjust //再生開始時間代入(タイミングを判定位置到着タイミングにするために上で出した時間を引く) repeat redraw 0 color 0,0,0 : boxf color 255,255,255 line 30,0,30,600 line 50,0,50,600 line 70,0,70,600 line 90,0,90,600 line 110,0,110,600 line 130,0,130,600 line 150,0,150,600 line 170,0,170,600 line 0,500,170,500 pos 200,0 mes "First Notes : " + timing(0) mes "Time :" + time mes "FPS :" + d3getfps() mes "BPM :" + bpm mes "movms:" + movms mes "one.b:" + onebeat mes "All.n:" + count/2 mes "ライン通過:" + tuuka time=double(d3timer())-start_tim //経過時間 stick k if k&128 {goto *exit} //Escキーで終了 gosub *move //確認用に最後に押されたボタンのタイミングで判定内に有ったノートを表示 color 255,255,0 gradf notx(hit_key),hit_ny,notsx(hit_key),5 gosub *draw redraw 1 await 16 loop *move repeat max if dr(cnt)=0 : if timing(cnt)<=time : dr(cnt)=1 if dr(cnt)=1 { ny(cnt)=movms*(time-timing(cnt)) //経過時間から出現タイミングを引いてノートの経過時間を出して移動量を掛けてY座標にする if ny(cnt)>=480 { if ny(cnt)<=520 {//480〜520の間なら判定する if k {//キーが押された hit_ny=ny(cnt) hit_key=key(cnt) dr(cnt)=2 tuuka+1 } }else{//判定範囲を超えたので消す dr(cnt)=2 tuuka+1 } } } loop return *draw repeat max if timing(cnt)<=time :if dr(cnt)=1{ kid=key(cnt) color notr(kid),notg(kid),notb(kid) gradf notx(kid),ny(cnt),notsx(kid),5 } loop return *exit mci "close all" //念のため終了時にmciを閉じる end
スペース等で簡易的にタイミング検証できるようにした
await 16なので最大 movms*16 ドット押したタイミングよりずれる
今回の場合movmsが0.3なので最大5ドットぐらいずれる



Freedom Programmer(ふりぷろ)

リンク

2016/7/13(Wed) 22:05:52|NO.76185

暇人さん
ありがとうございます!!
タイミングもバッチシ合いました!
ノートが一瞬だけ表示されるという事もなくなり
無事にビート●ニア風のゲームが開発できそうです!

あと、わざわざスクリプトを書いてくださり
お手数をおかけしました。

本当にありがとうございます。



ONION software Copyright 1997-2023(c) All rights reserved.