クォータービューRPGでマップチップ数値で移動可能か判定する
-
chalaza
クォータービューRPGでマップチップ数値で移動可能か判定する
クォータービュー(斜め見降ろし)のRPGみたいなマップを作っていて、
横48縦24のひし形を計算でマップチップを使い斜めに15×5に綺麗に描画することはできたのですが、
その計算では表示するひし形画像の左上の座標を求めただけなので当たり判定には使えないと思い、考えたのですが
マップチップが0のところは通れないとして、マップ配列を作った場合、さすがにひし形のマップチップは作れないと思うのですが、
やっぱりマップチップは描画しない正方形等にしておいて、正方形でキャラの前は通れない。など計算処理をして
それをひし形に考えなおして描画する。というのが一般的なのでしょうか…
そういう場合、キャラ表示用のプレイヤー座標と正方形で計算するための何も描画しないプレイヤー座標を分けて
両方を同時に斜めと縦に動かす…という考え方も使えるのでしょうか?
横48縦24のひし形を計算でマップチップを使い斜めに15×5に綺麗に描画することはできたのですが、
その計算では表示するひし形画像の左上の座標を求めただけなので当たり判定には使えないと思い、考えたのですが
マップチップが0のところは通れないとして、マップ配列を作った場合、さすがにひし形のマップチップは作れないと思うのですが、
やっぱりマップチップは描画しない正方形等にしておいて、正方形でキャラの前は通れない。など計算処理をして
それをひし形に考えなおして描画する。というのが一般的なのでしょうか…
そういう場合、キャラ表示用のプレイヤー座標と正方形で計算するための何も描画しないプレイヤー座標を分けて
両方を同時に斜めと縦に動かす…という考え方も使えるのでしょうか?
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
クォーター画面の表示座標は、マップ座標から計算出来るので両方持つとかえって混乱しますよ。
当たり判定も四角形のマップ座標系で行います。
当たり判定も四角形のマップ座標系で行います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
その通りでした。
表示位置は少し計算してマップチップから出せたのですが、その後またクォータービューで、
MAP[15][15]というマップとScope[15][15]という移動範囲をかさねて、
Player.scope(移動距離)の数に合わせてScope[15][15](全部0)のマップデータをプレイヤー座標を中心に1にしていきたいのですが…
Player.Scopeはもちろん奇数で、乗せた後にMAP[y][x]が0でなく、さらにScope[y][x]が1でないと通れない…みたいにしたいところなのですが、
プレイヤーを中心として、scope[15][15]の好きな数値分の距離を1にする簡略な式の考え方ってないでしょうか…
プレイヤーの座標はMAPのマス単位の数値です。
ちなみに作りたい範囲は、チェスのボードのような綺麗な辺ではなく、回転させた感じの辺がギザギザした範囲です。
分かりにくかったらすみません。
表示位置は少し計算してマップチップから出せたのですが、その後またクォータービューで、
MAP[15][15]というマップとScope[15][15]という移動範囲をかさねて、
Player.scope(移動距離)の数に合わせてScope[15][15](全部0)のマップデータをプレイヤー座標を中心に1にしていきたいのですが…
Player.Scopeはもちろん奇数で、乗せた後にMAP[y][x]が0でなく、さらにScope[y][x]が1でないと通れない…みたいにしたいところなのですが、
プレイヤーを中心として、scope[15][15]の好きな数値分の距離を1にする簡略な式の考え方ってないでしょうか…
プレイヤーの座標はMAPのマス単位の数値です。
ちなみに作りたい範囲は、チェスのボードのような綺麗な辺ではなく、回転させた感じの辺がギザギザした範囲です。
分かりにくかったらすみません。
//MAP
#define SCREEN_WIDTH 480
#define SCREEN_HEIGHT 360
#define MAP_PIXEL_HEIGHT (24*15+12)
#define MAP_PIXEL_WIDTH (48*8+24)
#define MAP_HEIGHT (MAP_PIXEL_HEIGHT/12)
#define MAP_WIDTH (MAP_PIXEL_WIDTH/24)
int MAP[MAP_HEIGHT][MAP_WIDTH] =
{
{2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,},
{2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,},
{2,2,2,2,2,2,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,0,0,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
{1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,},
};
//移動範囲をこの中に作る
int scope[15][15] =
{
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,},
};
//////////////////////////////
void DrawScope()
{
//この瞬間だけにプレイヤー座標をスコープポジションにコピー
//描画後動かないように表示にはにはスコープポジションを使う
if(ScopeDecision==0)
if( (CommandNumber==1 ||CommandNumber==2) &&CommandSelect==1 ){
ScopePositionX = Player.X;
ScopePositionY = Player.Y;
ScopeDecision=1;
}
int x,y;
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
for(y=0;y<15;++y)
{
for(x=0;x<15;++x)
{
//プレイヤーを中心に『Player.scope』の数値分のひろがりを1にする(未完成)
if(MAP[y][x]!=0)
scope[ScopePositionY][ScopePositionX] = 1;
//移動範囲で1の部分に青い枠を描画
if(MAP[y][x]!=0){
if(scope[y][x]!=0){
DrawGraph(
(15-y)*(48/2)+(x*24)-24-CameraX,
(x+y)*12-CameraY-24,
Scope,
TRUE); //マップ描画
}
}
}
}
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
説明がよくわからないのですが、シミュレーションRPGの移動範囲みたいなものですかね?
scopeをどの様にしたいのか参考例を書いてもらうと答えられると思います。
分からないポイント
・Player.Scopeはもちろん奇数で ← 何が奇数なのでしょうか?そこが良く分かりません。
・チェスのボードのような綺麗な辺ではなく、回転させた感じの辺がギザギザした範囲です ← 菱形と言うことでしょうか?。
・『Player.scope』の数値分のひろがりを1にする ← 距離はどの数値なのでしょう?
[参考]
SLGの移動範囲
「戦術SLGの作り方(移動範囲を求める)」
http://www5f.biglobe.ne.jp/~kenmo/progr ... /move.html
「Article: ゲームプログラミング講座」
http://gumina.sakura.ne.jp/CREATION/OLD ... index.html
scopeをどの様にしたいのか参考例を書いてもらうと答えられると思います。
分からないポイント
・Player.Scopeはもちろん奇数で ← 何が奇数なのでしょうか?そこが良く分かりません。
・チェスのボードのような綺麗な辺ではなく、回転させた感じの辺がギザギザした範囲です ← 菱形と言うことでしょうか?。
・『Player.scope』の数値分のひろがりを1にする ← 距離はどの数値なのでしょう?
[参考]
SLGの移動範囲
「戦術SLGの作り方(移動範囲を求める)」
http://www5f.biglobe.ne.jp/~kenmo/progr ... /move.html
「Article: ゲームプログラミング講座」
http://gumina.sakura.ne.jp/CREATION/OLD ... index.html
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
その通りSRPGの移動範囲のことです。
改めて調べてみたところ、プレイヤーを中心に範囲を表示するのではなく、移動距離を減らしながら全方向に範囲を広げていく方法が
一般的だったようなのでその方法にすることにしました。
この方法なら、自動的に斜めにしたひし形のような範囲になると思うので問題ないようです。
『Player.scope』がキャラの移動できるマス数の数値です。4くらいにしてあります。
そしてサイトを参考にして作ってみたのですが、
1.自分のいるマスに残り移動距離を代入
2.もし移動距離が残っているならば
1.上にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
2.右にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
3.下にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
4.左にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
3.移動力を今いるマスのコスト分だけ回復させ、もと来た道を戻る → ジャンプ元へ戻る
というのを再現しようとしてみたものの、4方向全体に進まずに上→ジャンプ→上→ジャンプとなったり、
ジャンプを入れなかったら上→右→下→左と範囲が一周するだけになってしまうのですが、
4方向全種類をひとつづつ調べるにはどう書きかえれば良いでしょうか…
改めて調べてみたところ、プレイヤーを中心に範囲を表示するのではなく、移動距離を減らしながら全方向に範囲を広げていく方法が
一般的だったようなのでその方法にすることにしました。
この方法なら、自動的に斜めにしたひし形のような範囲になると思うので問題ないようです。
『Player.scope』がキャラの移動できるマス数の数値です。4くらいにしてあります。
そしてサイトを参考にして作ってみたのですが、
1.自分のいるマスに残り移動距離を代入
2.もし移動距離が残っているならば
1.上にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
2.右にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
3.下にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
4.左にあるマスが移動可能なら残り移動距離を減らして進む → 1へジャンプ
3.移動力を今いるマスのコスト分だけ回復させ、もと来た道を戻る → ジャンプ元へ戻る
というのを再現しようとしてみたものの、4方向全体に進まずに上→ジャンプ→上→ジャンプとなったり、
ジャンプを入れなかったら上→右→下→左と範囲が一周するだけになってしまうのですが、
4方向全種類をひとつづつ調べるにはどう書きかえれば良いでしょうか…
void DrawScope()
{
//この瞬間だけにプレイヤー座標をスコープポジションにコピー
//描画後動かないように表示にはにはスコープポジションを使う
if(ScopeDecision==0)
if( (CommandNumber==1 ||CommandNumber==2) &&CommandSelect==1 ){
ScopePositionX = Player.X;
ScopePositionY = Player.Y;
ScopeDecision=1;
}
int x,y;
for(y=0;y<15;++y)
{
for(x=0;x<15;++x)
{
if(MAP[ScopePositionY][ScopePositionX]!=0)
scope[ScopePositionY][ScopePositionX] = Player.scope;//現在の位置に残り移動距離を設定
if(Player.scope>0){ //のこり歩数が0でなかったら
if(MAP[ScopePositionY-1][ScopePositionX] != 0){ //現在地の上が通れたら
ScopePositionY -= 1; //範囲を上に移動
scope[ScopePositionY][ScopePositionX] = Player.scope;//範囲座標に現在座標をに代入
Player.scope -= 1; //残り移動距離を1減らす
}
if(MAP[ScopePositionY][ScopePositionX+1] != 0){ //現在地の右が通れたら
ScopePositionX += 1; //範囲を右に移動
scope[ScopePositionY][ScopePositionX] = Player.scope;//範囲座標に現在座標をに代入
Player.scope -= 1; //残り移動距離を1減らす
}
if(MAP[ScopePositionY+1][ScopePositionX] != 0){ //現在地の下が通れたら
ScopePositionY += 1; //範囲を下に移動
scope[ScopePositionY][ScopePositionX] = Player.scope;//範囲座標に現在座標をに代入
Player.scope -= 1; //残り移動距離を1減らす
}
if(MAP[ScopePositionY][ScopePositionX-1] != 0){ //現在地の左が通れたら
ScopePositionX -= 1; ////範囲を左に移動
scope[ScopePositionY][ScopePositionX] = Player.scope;//範囲座標に現在座標をに代入
Player.scope -= 1; //残り移動距離を1減らす
}
Player.scope += scope[ScopePositionY][ScopePositionX];
}
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
//移動範囲で0以外の部分に青い枠を描画
if(MAP[y][x]!=0){
if(scope[y][x]!=0){
DrawGraph(
(15-y)*(48/2)+(x*24)-24-CameraX,
(x+y)*12-CameraY-24,
Scope,
TRUE); //マップ描画
}
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );
}
}
}
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
申し訳ありません、インデントを正確に設定してもらえますか?ソースコードが凄く読みづらいです。
あとx,yループと、その中で行っているScopePositionY、ScopePositionXの移動がまったく無関係なので狙った動きと描画にならないと思います。
そもそもx,yループ内にある意図が分かりません。
移動範囲の処理は専用のループや再帰処理で行ってください。
あと出来れば実験プログラムとして画像不要で単体で動くものを作ってもらえると、こちらでも再現試験が出来るので都合が良いです。
あとx,yループと、その中で行っているScopePositionY、ScopePositionXの移動がまったく無関係なので狙った動きと描画にならないと思います。
そもそもx,yループ内にある意図が分かりません。
移動範囲の処理は専用のループや再帰処理で行ってください。
あと出来れば実験プログラムとして画像不要で単体で動くものを作ってもらえると、こちらでも再現試験が出来るので都合が良いです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
インデント幅気にしていませんでした…すみません。気をつけます。
再帰というのを使って書きなおしてみました。
これならわかりやすいと思うのですが、ひし形を描画する関数を知らないので単体で動くのが今のところ作れませんでした…すみません。
そして、プレイヤーからの距離を表す領域が表示されたのは良いのですが、領域の内側に穴があいてしまいます。
プレイヤーの位置から、Player.scope(移動量)を始めとして、動いた数だけその量を減らしてその数を座標に記録していっているのですが
おそらく参考にしたサイトに書いてあった、『これから数値をつける足場の数値が存続の足場の数値より少ない場合は処理を上書きする』という
部分が再現できていないんだと思いますが、どう直したら良いでしょうか…
再帰というのを使って書きなおしてみました。
これならわかりやすいと思うのですが、ひし形を描画する関数を知らないので単体で動くのが今のところ作れませんでした…すみません。
そして、プレイヤーからの距離を表す領域が表示されたのは良いのですが、領域の内側に穴があいてしまいます。
プレイヤーの位置から、Player.scope(移動量)を始めとして、動いた数だけその量を減らしてその数を座標に記録していっているのですが
おそらく参考にしたサイトに書いてあった、『これから数値をつける足場の数値が存続の足場の数値より少ない場合は処理を上書きする』という
部分が再現できていないんだと思いますが、どう直したら良いでしょうか…
void FindDistance(int SCx,int SCy,int SCn){
if(ScopeDecision==0){
SCx = Player.X;
SCy = Player.Y;
SCn = Player.scope;
ScopeDecision = 1;
}
scope[SCy][SCx] = SCn;
if(SCn==0)
return; //処理終了
if(MAP[SCy-1][SCx]!=0 || scope[SCy-1][SCx] < scope[SCy][SCx] ){//MAPの上が0でないかscopeの上が記録した数が現在座標より少ない場合上に動かす
FindDistance(SCx,SCy-1,SCn-1); //残りの判定
scope[SCy][SCx] = SCn; //移動した足場の座標に移動残り数値を記録
}
if(MAP[SCy][SCx+1]!=0 || scope[SCy][SCx+1] < scope[SCy][SCx] ){//MAPの右が0でないかscopeの右が記録した数が現在座標より少ない場合右に動かす
FindDistance(SCx+1,SCy,SCn-1); //残りの判定
scope[SCy][SCx] = SCn; //移動した足場の座標に移動残り数値を記録
}
if(MAP[SCy+1][SCx]!=0 || scope[SCy+1][SCx] < scope[SCy][SCx] ){//MAPの下が0でないかscopeの下が記録した数が現在座標より少ない場合下に動かす
FindDistance(SCx,SCy+1,SCn-1); //残りの判定
scope[SCy][SCx] = SCn; //移動した足場の座標に移動残り数値を記録
}
if(MAP[SCy][SCx-1]!=0 || scope[SCy][SCx-1] < scope[SCy][SCx] ){//MAPの左が0でないかscopeの左が記録した数が現在座標より少ない場合左に動かす
FindDistance(SCx-1,SCy,SCn-1); //残りの判定
scope[SCy][SCx] = SCn; //移動した足場の座標に移動残り数値を記録
}
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
DrawTriangleを2つ使えば菱形は作れますよ。
それと再帰関数がScopeDecisionに頼るのは止めた方が良いと思います(不要だと思いますが)。
[追記]
scope[SCy][SCx] = SCn;
は一箇所で良いのでは?
それとscope[SCy][SCx] = SCn;で代入前に前の値と比較して書きこめば最大値を残せると思います。
それと再帰関数がScopeDecisionに頼るのは止めた方が良いと思います(不要だと思いますが)。
[追記]
scope[SCy][SCx] = SCn;
は一箇所で良いのでは?
それとscope[SCy][SCx] = SCn;で代入前に前の値と比較して書きこめば最大値を残せると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
scope[SCy][SCx] = SCn;を四方向処理の後に1つだけにして、
ScopeDecisionにプレイヤーXY座標を代入するのは別関数にして切り離してみました。
そこでとりあえず移動先の値と比較せずに処理してみたところ、
0001000
0010100
0101010
1234101
0101010
0010101
0001000(4がプレイヤー)
こんな感じになったのですが、これは値の比較をしていないせいなだけで良いのですよね?
ここまでが間違ってるかもしれないので…
そして、値の比較の処理なのですが…
すべての座標に処理の最大値を残せば良いことは分かったのですが、その処理で
『代入前の値<代入する値 の場合に、現在の座標に残り移動量を代入』 ということだと思うんですけど、
代入前の値と代入する値をどうやって表現するか悩んでいるのですが
簡単なことだと思うんですけどどうすればいいか教えてください…
ScopeDecisionにプレイヤーXY座標を代入するのは別関数にして切り離してみました。
そこでとりあえず移動先の値と比較せずに処理してみたところ、
0001000
0010100
0101010
1234101
0101010
0010101
0001000(4がプレイヤー)
こんな感じになったのですが、これは値の比較をしていないせいなだけで良いのですよね?
ここまでが間違ってるかもしれないので…
そして、値の比較の処理なのですが…
すべての座標に処理の最大値を残せば良いことは分かったのですが、その処理で
『代入前の値<代入する値 の場合に、現在の座標に残り移動量を代入』 ということだと思うんですけど、
代入前の値と代入する値をどうやって表現するか悩んでいるのですが
簡単なことだと思うんですけどどうすればいいか教えてください…
void FindDistance(int SCx,int SCy,int SCn){
scope[SCy][SCx] = SCn;
if(SCn==0)
return; //処理終了
if(MAP[SCy-1][SCx]!=0 ){//MAPの上が0でないかscopeの上が記録した数が現在座標より少ない場合上に動かす
FindDistance(SCx,SCy-1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx+1]!=0 ){//MAPの右が0でないかscopeの右が記録した数が現在座標より少ない場合右に動かす
FindDistance(SCx+1,SCy,SCn-1); //残りの判定
}
if(MAP[SCy+1][SCx]!=0 ){//MAPの下が0でないかscopeの下が記録した数が現在座標より少ない場合下に動かす
FindDistance(SCx,SCy+1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx-1]!=0 ){//MAPの左が0でないかscopeの左が記録した数が現在座標より少ない場合左に動かす
FindDistance(SCx-1,SCy,SCn-1); //残りの判定
}
//代入前より代入後が大きかったら代入(間違い)
if( scope[SCy][SCx] < SCn )
scope[SCy][SCx] = SCn; //移動した足場の座標に移動残り数値を記録
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
ここはヒントに留めておきます。
「最大値を残せ」は、既に必要な要素は出てきていますので、じっくり考えてみてください。
あと、これで合っているかも自分で確かめてみてください。
自分で間違いを直せる力を付けないとゲームは作れませんので、もし間違えたとして、それは良い経験です。そこで何が悪いんだろうと考えたり調べたりするのが力を付ける最大のチャンスです。特にSRPGは、ここからどんどん難しくなるのでよく考える事は重要です。
途中の値を確認するテクニックの一端をご紹介しておきます。
「簡単RPG講座 番外編。 デバッグ入門 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/blog.php?u=114&b=982&c=2
[補足]
ただ、あんまり悩むようなら聞いてくださいね。
悩んだ後なら、より理解できるようになっていると思います。
「最大値を残せ」は、既に必要な要素は出てきていますので、じっくり考えてみてください。
あと、これで合っているかも自分で確かめてみてください。
自分で間違いを直せる力を付けないとゲームは作れませんので、もし間違えたとして、それは良い経験です。そこで何が悪いんだろうと考えたり調べたりするのが力を付ける最大のチャンスです。特にSRPGは、ここからどんどん難しくなるのでよく考える事は重要です。
途中の値を確認するテクニックの一端をご紹介しておきます。
「簡単RPG講座 番外編。 デバッグ入門 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/blog.php?u=114&b=982&c=2
[補足]
ただ、あんまり悩むようなら聞いてくださいね。
悩んだ後なら、より理解できるようになっていると思います。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
なんとかできました。
先にのこり移動量が座標より大きいときだけその座標に移動量を代入してから
範囲を移動させていけばよかったのですね。コードもすっきりしました。
そこで、大変申し訳ないのですが、もうひとつ移動についてこれだけは聞いておきたいというものがあるのですが、よろしいでしょうか?
キャラをキーで動かす時のことなのですが…キャラとマップの座標単位が、数値1で1マスを表しているので、
上キーを押したときにキャラ座標を-1 のようにすると、一瞬で上の座標まで高速移動します。
一回のキー入力で上の座標までゆっくり動かしたいのですが、
これはキャラ描画座標とからませたりマップ座標単位を増やさないといけないのでしょうか?
先にのこり移動量が座標より大きいときだけその座標に移動量を代入してから
範囲を移動させていけばよかったのですね。コードもすっきりしました。
void FindDistance(int SCx,int SCy,int SCn){
if( SCn>scope[SCy][SCx] )//座標の数値が残り移動量より少ない場合
scope[SCy][SCx] = SCn;//その座標に移動量を代入
if(SCn==0)
return; //処理終了
if(MAP[SCy-1][SCx]!=0 ){//MAPの上が0でない場合上に動かす
FindDistance(SCx,SCy-1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx+1]!=0 ){//MAPの右が0でない場合右に動かす
FindDistance(SCx+1,SCy,SCn-1); //残りの判定
}
if(MAP[SCy+1][SCx]!=0 ){//MAPの下が0でない場合下に動かす
FindDistance(SCx,SCy+1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx-1]!=0 ){//MAPの左が0でない場合左に動かす
FindDistance(SCx-1,SCy,SCn-1); //残りの判定
}
}
キャラをキーで動かす時のことなのですが…キャラとマップの座標単位が、数値1で1マスを表しているので、
上キーを押したときにキャラ座標を-1 のようにすると、一瞬で上の座標まで高速移動します。
一回のキー入力で上の座標までゆっくり動かしたいのですが、
これはキャラ描画座標とからませたりマップ座標単位を増やさないといけないのでしょうか?
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
すっきりしましたね。これで正解だと思います。
移動に関しては、こちらが参考になると思います。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
19. キャラをキー入力によって移動させる。
20. キャラを一区間単位で移動させる。
21. キャラを一区間歩かせる。
22. キャラを4方向に歩かせる。
なんにしても「ゲームプログラミングの館」の内容は一通り頭に入れておいたほうが良いでしょう。
移動に関しては、こちらが参考になると思います。
「新・C言語 ~ゲームプログラミングの館~ [DXライブラリ]」
http://dixq.net/g/
19. キャラをキー入力によって移動させる。
20. キャラを一区間単位で移動させる。
21. キャラを一区間歩かせる。
22. キャラを4方向に歩かせる。
なんにしても「ゲームプログラミングの館」の内容は一通り頭に入れておいたほうが良いでしょう。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
いちおうプログラミングの館の 22. キャラを4方向に歩かせる。を参考にして形はできたのですが、
プログラミングの館ではぴったり1区間を歩かせるために、キャラ座標を32ピクセルで割り切れるまで歩かせるようにしていますが、
私のプログラムだと1区間がキャラの1座標なので、キャラの座標を+1しただけで一瞬でぴったり隣の座標に動いてしまうのです。
小数を使ったりしても駄目だったのですが、プログラミングの館の方とどう変えればよいのでしょうか?
プログラミングの館ではぴったり1区間を歩かせるために、キャラ座標を32ピクセルで割り切れるまで歩かせるようにしていますが、
私のプログラムだと1区間がキャラの1座標なので、キャラの座標を+1しただけで一瞬でぴったり隣の座標に動いてしまうのです。
小数を使ったりしても駄目だったのですが、プログラミングの館の方とどう変えればよいのでしょうか?
void PlayerMove()//プレイヤー操作
{
if(Player.X%1==0 && Player.Y%1==0){ //座標が割り切れたら入力可能
Player.walk=1; //歩くフラグを立てる。
if (( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_UP ) != 0 ) //上ボタンが押されたら
Player.muki=0; //上向きフラグを立てる
else if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_RIGHT ) != 0 ) //右ボタンが押されたら
Player.muki=1; //右向きフラグを立てる
else if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_DOWN ) != 0 ) //下ボタンが押されたら
Player.muki=2; //下向きフラグを立てる
else if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_LEFT ) != 0 ) //左ボタンが押されたら
Player.muki=3; //左向きフラグを立てる
else //何のボタンも押されてなかったら
Player.walk=0; //歩かないフラグを立てる
}
if(Player.walk==1){ //歩くフラグが立っていたら
if(Player.muki==0 && MAP[Player.Y-1][Player.X]!=0 && scope[Player.Y-1][Player.X]!=0 ){ //上向きなら右上へ
Player.Y -=1;
Player.img=Made[(Player.X%96)/24 +20];
}
else if(Player.muki==1 && MAP[Player.Y][Player.X+1]!=0 && scope[Player.Y][Player.X+1]!=0 ){ //右向きなら右下へ
Player.X +=1;
Player.img=Made[(Player.X%96)/24 +4];
}
else if(Player.muki==2 && MAP[Player.Y+1][Player.X]!=0 && scope[Player.Y+1][Player.X]!=0 ){ //下向きなら左下へ
Player.Y +=1;
Player.img=Made[(Player.X%96)/24 +12];
}
else if(Player.muki==3 && MAP[Player.Y][Player.X-1]!=0 && scope[Player.Y][Player.X-1]!=0 ){ //左向きなら左上へ
Player.X -=1;
Player.img=Made[(Player.X%96)/24 +28];
}
}
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
ゲームプログラミングの館と同じ考え方です。
あの場合は、一区画が32ドット=歩く距離となっていますが、クォータービューでも仮想的に内部で距離を持てば良いです。
同様に÷32で一区画としてはどうでしょうか?実際のピクセル数や座標は画面に合わせて変換してください。
あの場合は、一区画が32ドット=歩く距離となっていますが、クォータービューでも仮想的に内部で距離を持てば良いです。
同様に÷32で一区画としてはどうでしょうか?実際のピクセル数や座標は画面に合わせて変換してください。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
どうやらXY座標を基準にプレイヤーを描画すると1マスづつ瞬間移動してしまうようなので、
プレイヤーのXY座標とプレイヤーの画像描画座標に分けて作ってみました。
プレイヤー描画座標は、移動する前の最初の状態のうちにXY座標を使って計算して最初の描画位置を決めて、
そこからは、たとえば右を押したとしたら、プレイヤー描画座標が右上にうごいて、1マスで割り切れる範囲に到着したらXY座標を右に1つふやす。
というような感じで同時に動かす方法にしてみたところ、実際の処理は上手くいったので
ついでに移動中にキャンセルボタン(Z)を押すと移動か攻撃かのコマンドを選ぶ部分まで戻って、移動中の座標をすべて最初の状態に
戻す処理も作ってみました。実際の操作は問題ないのですが、やはりコードに無駄がないか心配なので関数の部分だけでも見てもらえないでしょうか・・
長々と質問してしまっていましたが、実際の移動範囲の問題は解決しているので、このスレッドは解決にさせておきます。
変数宣言は省いてしまっています。とても長いのでよかったらでいいです
プレイヤーのXY座標とプレイヤーの画像描画座標に分けて作ってみました。
プレイヤー描画座標は、移動する前の最初の状態のうちにXY座標を使って計算して最初の描画位置を決めて、
そこからは、たとえば右を押したとしたら、プレイヤー描画座標が右上にうごいて、1マスで割り切れる範囲に到着したらXY座標を右に1つふやす。
というような感じで同時に動かす方法にしてみたところ、実際の処理は上手くいったので
ついでに移動中にキャンセルボタン(Z)を押すと移動か攻撃かのコマンドを選ぶ部分まで戻って、移動中の座標をすべて最初の状態に
戻す処理も作ってみました。実際の操作は問題ないのですが、やはりコードに無駄がないか心配なので関数の部分だけでも見てもらえないでしょうか・・
長々と質問してしまっていましたが、実際の移動範囲の問題は解決しているので、このスレッドは解決にさせておきます。
変数宣言は省いてしまっています。とても長いのでよかったらでいいです
void Input(){//ゲームパッド入力(どのくらい入力しているかに変換)
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_UP ) != 0 )
UPcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_UP ) == 0 )
UPcount=0;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_RIGHT ) != 0 )
RIGHTcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_RIGHT ) == 0 )
RIGHTcount=0;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_LEFT ) != 0 )
LEFTcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_LEFT ) == 0 )
LEFTcount=0;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_DOWN ) != 0 )
DOWNcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_DOWN ) == 0 )
DOWNcount=0;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_1 ) != 0 )
Zcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_1 ) == 0 )
Zcount=0;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_2 ) != 0 )
Xcount++;
if(( GetJoypadInputState( DX_INPUT_KEY_PAD1 ) & PAD_INPUT_2 ) == 0 )
Xcount=0;
}
void DrawMap()//マップとクリッドライン描画
{
if(Key[KEY_INPUT_A]==1 ){//Aを奇数回入力した時にグリッドライン表示
LineCount++;
}
int x,y;
for(y=0;y<MAP_HEIGHT;++y)
{
for(x=0;x<MAP_WIDTH;++x)
{
if(MAP[y][x]!=0){
DrawGraph(
(15-y)*(48/2)+(x*24)-24-CameraX,
(x+y)*12-CameraY,
chip[(MAP[y][x])-1],
TRUE); //マップ描画
}
if(LineCount%2==1){
if(MAP[y][x]!=0){
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 200 );//半透明で描画
DrawGraph(
(15-y)*(48/2)+(x*24)-24-CameraX,
(x+y)*12-CameraY,
Line,
TRUE); //ライン描画
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );//半透明解除
}
}
}
}
}
void DrawChara(){//キャラクター描画
if(Player.muki==0 )//プレイヤー1アニメ
Player.img=Made[(animetime%64)/16+16];
if(Player.muki==1 )
Player.img=Made[(animetime%64)/16];
if(Player.muki==2 )
Player.img=Made[(animetime%64)/16+8];
if(Player.muki==3 )
Player.img=Made[(animetime%64)/16+24];
DrawGraph(Player.DrawX-CameraX,Player.DrawY-CameraY,Player.img,TRUE);//プレイヤー1描画
Player2.img=Hukei[(animetime%64)/16+16];//プレイヤー2アニメ
DrawGraph(Player2.X-CameraX,Player2.Y-CameraY,Player2.img,TRUE);//プレイヤー2描画
Muriceanime = animetime%85;//モンスターアニメ
if(Muriceanime<=20)
Murice=Muriceimg[0];
if(Muriceanime>=21 && Muriceanime<=52)
Murice=Muriceimg[Muriceanime%16/8];
if(Muriceanime>=53 && Muriceanime<=85)
Murice=Muriceimg[Muriceanime%16/8+4];
DrawGraph(336-CameraX,130-CameraY,Murice,TRUE);//モンスター描画(まだXY座標指定ではない)
}
void FindDistance(int SCx,int SCy,int SCn){//移動範囲座標計算
if( SCn>scope[SCy][SCx] )//座標の数値が残り移動量より少ない場合
scope[SCy][SCx] = SCn;//その座標に移動量を代入
if(SCn==0)
return; //処理終了
if(MAP[SCy-1][SCx]!=0 ){//MAPの上が0でない場合上に動かす
FindDistance(SCx,SCy-1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx+1]!=0 ){//MAPの右が0でない場合右に動かす
FindDistance(SCx+1,SCy,SCn-1); //残りの判定
}
if(MAP[SCy+1][SCx]!=0 ){//MAPの下が0でない場合下に動かす
FindDistance(SCx,SCy+1,SCn-1); //残りの判定
}
if(MAP[SCy][SCx-1]!=0 ){//MAPの左が0でない場合左に動かす
FindDistance(SCx-1,SCy,SCn-1); //残りの判定
}
}
void DrawScope()//移動範囲描画
{
ScopeDecision=1;
if( CommandSelect==1 ){ //コマンドセレクトが決定した後
FindDistance( SCx, SCy, SCn);
for(int y=0;y<15;++y)
{
for(int x=0;x<15;++x)
{
SetDrawBlendMode( DX_BLENDMODE_ALPHA, 128 );
//移動範囲で0以外の部分に青い枠を描画
if(MAP[y][x]!=0){
if(scope[y][x]!=0){
DrawGraph(
(15-y)*(48/2)+(x*24)-24-CameraX,
(x+y)*12-CameraY-24,
Scope,
TRUE); //マップ描画
}
SetDrawBlendMode( DX_BLENDMODE_NOBLEND, 0 );
}
}
}
}
if( CommandSelect==0 ){//スコープ計算用(FindDistanceには入れられない)
SCx = Player.X;
SCy = Player.Y;
SCn = Player.scope;
}
}
void DrawStates(){//ステータスを描画
//ステータス背景
DrawGraph(16,288,StatesBar,TRUE);
DrawGraph(128,288,StatesBar,TRUE);
DrawGraph(240,288,StatesBar,TRUE);
DrawGraph(352,288,StatesBar,TRUE);
//キャラ顔1
DrawGraph(16,288,MadeFace,TRUE);
DrawGraph(128,288,HukeiFace,TRUE);
//キャラ1
DrawGraph(80,304,HPBack,TRUE); //HPの枠
DrawGraph(80,320,MPBack,TRUE); //MPの枠
DrawGraph(80,336,CPBack,TRUE); //CPの枠
//ステータスマスク
CreateMaskScreen(); // マスクここから
DrawMask( 16, 288, StatesMask, DX_MASKTRANS_BLACK ); // マスク範囲のみを描画領域に
// 初期座標
DrawGraph(84-(40*(Player.HPMAX-Player.HP)/Player.HPMAX),314,HPBar,TRUE); //HPバー(全体からHPが減った分左にずれていく)
DrawGraph(84-(40*(Player.MPMAX-Player.MP)/Player.MPMAX),330,MPBar,TRUE); //MPバー(全体からMPが減った分左にずれていく)
DrawGraph(84-(40*(Player.CPMAX-Player.CP)/Player.CPMAX),346,CPBar,TRUE); //CPバー(全体からCPが減った分左にずれていく)
DeleteMaskScreen(); // マスクここまで
DrawFormatStringToHandle( 82 , 291 , GetColor(255,255,255) , BattleStatesFont , "綾梶 Lv%2d" , 20 ); //レベル表示
DrawFormatStringToHandle( 84 , 303 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player.HP );//HP数値表示
DrawFormatStringToHandle( 84 , 319 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player.MP );//MP数値表示
DrawFormatStringToHandle( 84 , 335 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player.CP );//CP数値表示
//キャラ2
DrawGraph(80+112,304,HPBack,TRUE); //HPの枠
DrawGraph(80+112,320,MPBack,TRUE); //MPの枠
DrawGraph(80+112,336,CPBack,TRUE); //CPの枠
//ステータスマスク
CreateMaskScreen(); // マスクここから
DrawMask( 128, 288, StatesMask, DX_MASKTRANS_BLACK ); // マスク範囲のみを描画領域に
DrawGraph((84+112)-(40*(Player2.HPMAX-Player2.HP)/Player2.HPMAX),314,HPBar,TRUE); //HPバー(全体からHPが減った分左にずれていく)
DrawGraph((84+112)-(40*(Player2.MPMAX-Player2.MP)/Player2.MPMAX),330,MPBar,TRUE); //MPバー(全体からMPが減った分左にずれていく)
DrawGraph((84+112)-(40*(Player2.CPMAX-Player2.CP)/Player2.CPMAX),346,CPBar,TRUE); //CPバー(全体からCPが減った分左にずれていく)
DeleteMaskScreen(); // マスクここまで
DrawFormatStringToHandle( 82+112 , 291 , GetColor(255,255,255) , BattleStatesFont , "御伽 Lv%2d" , 20 ); //レベル表示
DrawFormatStringToHandle( 84+112 , 303 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player2.HP );//HP数値表示
DrawFormatStringToHandle( 84+112 , 319 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player2.MP );//MP数値表示
DrawFormatStringToHandle( 84+112 , 335 , GetColor(255,255,255) , BattleStatesFont , " %4d" , Player2.CP );//CP数値表示
}
void DrawCommand(){ //コマンドの表示(選んでいるものは左に24pixずらして決定したら画像を変える)
//攻撃
if(CommandNumber!=1){
DrawGraph(384,32,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 40 , "攻撃", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==1){
if(CommandSelect==0){
DrawGraph(360,32,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 40 , "攻撃", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,32,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 40 , "攻撃", GetColor(255,255,255) , CommandFont ) ;
}
}
//移動
if(CommandNumber!=2){
DrawGraph(384,72,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 80 , "移動", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==2){
if(CommandSelect==0){
DrawGraph(360,72,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 80 , "移動", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,72,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 80 , "移動", GetColor(255,255,255) , CommandFont ) ;
}
}
//魔法
if(CommandNumber!=3){
DrawGraph(384,112,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 120 , "魔法", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==3){
if(CommandSelect==0){
DrawGraph(360,112,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 120 , "魔法", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,112,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 120 , "魔法", GetColor(255,255,255) , CommandFont ) ;
}
}
//特技
if(CommandNumber!=4){
DrawGraph(384,152,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 160 , "特技", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==4){
if(CommandSelect==0){
DrawGraph(360,152,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 160 , "特技", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,152,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 160 , "特技", GetColor(255,255,255) , CommandFont ) ;
}
}
//道具
if(CommandNumber!=5){
DrawGraph(384,192,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 200 , "道具", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==5){
if(CommandSelect==0){
DrawGraph(360,192,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 200 , "道具", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,192,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 200 , "道具", GetColor(255,255,255) , CommandFont ) ;
}
}
//退却
if(CommandNumber!=6){
DrawGraph(384,232,CommandWaku[0],TRUE);
DrawStringToHandle( 408 , 240 , "退却", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandNumber==6){
if(CommandSelect==0){
DrawGraph(360,232,CommandWaku[0],TRUE);
DrawStringToHandle( 384 , 240 , "退却", GetColor(255,255,255) , CommandFont ) ;
}
if(CommandSelect==1){
DrawGraph(360,232,CommandWaku[1],TRUE);
DrawStringToHandle( 384 , 240 , "退却", GetColor(255,255,255) , CommandFont ) ;
}
}
}
void PlayerMove()//プレイヤー操作
{
if( CommandSelect==1 ){//コマンドセレクトが決まった後
if(Player.muki==0 )//立ってるだけのときのプレイヤー1アニメ
Player.img=Made[(animetime%64)/16+16];
if(Player.muki==1 )
Player.img=Made[(animetime%64)/16];
if(Player.muki==2 )
Player.img=Made[(animetime%64)/16+8];
if(Player.muki==3 )
Player.img=Made[(animetime%64)/16+24];
if(Player.DrawX%24==0 && Player.DrawY%12==0){ //描画座標が1マス分で割り切れたら入力可能
Player.walk=1; //歩くフラグを立てる。
if ( UPcount != 0 ) //上ボタンが押されたら
Player.muki=0; //上向きフラグを立てる
else if( RIGHTcount != 0 ) //右ボタンが押されたら
Player.muki=1; //右向きフラグを立てる
else if(DOWNcount != 0 ) //下ボタンが押されたら
Player.muki=2; //下向きフラグを立てる
else if(LEFTcount != 0 ) //左ボタンが押されたら
Player.muki=3; //左向きフラグを立てる
else //何のボタンも押されてなかったら
Player.walk=0; //歩かないフラグを立てる
}
if(Player.walk==1){ //歩くフラグが立っていたら
if(Player.muki==0 && MAP[Player.Y-1][Player.X]!=0 && scope[Player.Y-1][Player.X]!=0 ){ //上向きなら描画座標を右上へ
Player.DrawY -=1;
Player.DrawX +=2;
Player.img=Made[(Player.DrawX%96)/24 +20]; //歩くアニメーション
}
else if(Player.muki==1 && MAP[Player.Y][Player.X+1]!=0 && scope[Player.Y][Player.X+1]!=0 ){ //右向きなら描画座標を右下へ
Player.DrawY +=1;
Player.DrawX +=2;
Player.img=Made[(Player.DrawX%96)/24 +4]; //歩くアニメーション
}
else if(Player.muki==2 && MAP[Player.Y+1][Player.X]!=0 && scope[Player.Y+1][Player.X]!=0 ){ //下向きなら描画座標を左下へ
Player.DrawY +=1;
Player.DrawX -=2;
Player.img=Made[(Player.DrawX%96)/24 +12]; //歩くアニメーション
}
else if(Player.muki==3 && MAP[Player.Y][Player.X-1]!=0 && scope[Player.Y][Player.X-1]!=0 ){ //左向きなら描画座標を左上へ
Player.DrawY -=1;
Player.DrawX -=2;
Player.img=Made[(Player.DrawX%96)/24 +28]; //歩くアニメーション
}
}
if(Player.walk==1 && Player.DrawX%24==0 && Player.DrawY%12==0){ //歩くフラグが立っていて座標が割り切れるとき
if(Player.muki==0 && MAP[Player.Y-1][Player.X]!=0 && scope[Player.Y-1][Player.X]!=0 )//XY座標の上が足場だったら
Player.Y -=1; //XY座標を上に動かす
if(Player.muki==1 && MAP[Player.Y][Player.X+1]!=0 && scope[Player.Y][Player.X+1]!=0 )//XY座標の右が足場だったら
Player.X +=1; //XY座標を右に動かす
if(Player.muki==2 && MAP[Player.Y+1][Player.X]!=0 && scope[Player.Y+1][Player.X]!=0 )//XY座標の下が足場だったら
Player.Y +=1; //XY座標を下に動かす
if(Player.muki==3 && MAP[Player.Y][Player.X-1]!=0 && scope[Player.Y][Player.X-1]!=0 )//XY座標の左が足場だったら
Player.X -=1; //XY座標を左に動かす
}
}
}
void MapScroll()//マップスクロール
{
//X座標スクロール
CameraX = Player.DrawX - SCREEN_WIDTH/2 + 24;
if(CameraX < 0)CameraX = 0;
if(CameraX > (MAP_WIDTH*48)-SCREEN_WIDTH-24) CameraX = (MAP_WIDTH*48)-SCREEN_WIDTH-24;
//背景表示座標をスクロール
PlayerViewX = Player.DrawX - CameraX;
//Y座標スクロール
CameraY = Player.DrawY - SCREEN_HEIGHT/2 + 24;
if(CameraY < 0)CameraY = 0;
if(CameraY > (MAP_HEIGHT*12)-SCREEN_HEIGHT-12) CameraY = (MAP_HEIGHT*12)-SCREEN_HEIGHT-12;
//背景表示座標をスクロール
PlayerViewY = Player.DrawY - CameraY;
}
void Command(){//コマンド選択
if( CommandSelect==0 &&(DOWNcount==1 ||( DOWNcount%5==0 && DOWNcount>30))){
// たった今押したか、30カウンター以上押しっぱなしかつ5回に一度
CommandNumber++; //選んでいるコマンドを+1
if(CommandNumber==7) //7になったら(数を超えたら)1にする
CommandNumber=1;
}
if( CommandSelect==0 &&(UPcount==1 ||( UPcount%5==0 && UPcount>30))){
// たった今押したか、30カウンター以上押しっぱなしかつ5回に一度
CommandNumber--; //選んでいるコマンドを-1
if(CommandNumber==0) //0になったら(数より減ったら)6にする
CommandNumber=6;
}
if( CommandSelect==0 && Zcount ==1){ //Zを押したらコマンドを決定
CommandSelect=1;
}
}
void PlayerTurn(){//プレイヤーのターンの処理
if(CommandSelect==0) //コマンド決定していないとき
Command(); //コマンド選択可能
if(BeforeCheck==0){ //移動前の座標と向きを記録
Player.MoveBeforeX = Player.X;
Player.MoveBeforeY = Player.Y;
Player.MoveBeforeMuki = Player.muki;
BeforeCheck=1;
}
if((CommandNumber==1||CommandNumber==2)&&CommandSelect==1){//攻撃か移動を選んだとき
PlayerMove(); //移動可能
if(ScopeDecision==0){ //スコープの基準座標をプレイヤー座標にする
SCx = Player.X;
SCy = Player.Y;
SCn = Player.scope;
ScopeDecision = 1;
}
DrawScope(); //スコープ表示
}
if( CommandSelect==1 && Xcount ==1){//コマンドを決定した後にキャンセルしたらセレクト状態に戻す
CommandSelect=0;
}
if( CommandSelect==0 && BeforeCheck==1){//コマンドをキャンセルした時
Player.X = Player.MoveBeforeX; //プレイヤー座標と向きを移動前の状態に戻す
Player.Y = Player.MoveBeforeY;
Player.muki = Player.MoveBeforeMuki;
Player.DrawX = (15-Player.MoveBeforeY)*(48/2)+(Player.MoveBeforeX*24)-24 ;//XY座標から描画座標を計算
Player.DrawY = (Player.MoveBeforeX+Player.MoveBeforeY)*12-24 ;
BeforeCheck=0; //処理終了
}
MapScroll(); //マップがプレイヤーを中心にスクロール
}
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow ){
SetMainWindowText("RPG");
ChangeWindowMode(TRUE);
SetGraphMode(480,360,32);
if(DxLib_Init() == -1 || SetDrawScreen( DX_SCREEN_BACK )!=0) return -1;//初期化と裏画面化
int GetJoypadInputState( int InputType ) ;//ジョイパ使用
//画像ロードと代入
int RockChip1 = LoadGraph( "image/RockChip1.png" );
int GrassChip1 = LoadGraph("image/GrassChip1.png");
Line = LoadGraph( "image/BasisLine.png" );
Scope = LoadGraph( "image/Scope.png" );
Scope2 = LoadGraph( "image/Scope2.png" );
//ステージ1
chip[0] = RockChip1;
chip[1] = GrassChip1;
//プレイヤーキャラ
LoadDivGraph( "image/Chara/Made.png" , 32 , 8 , 4 , 48 , 48 , Made );
LoadDivGraph( "image/Chara/Hukei.png" , 32 , 8 , 4 , 48 , 48 , Hukei );
//モンスター
LoadDivGraph( "image/Murice.png" , 8 , 4 , 2 , 48 , 48 , Muriceimg );
//ステータス
StatesBar = LoadGraph( "image/States/BasisStates.png" );
MadeFace = LoadGraph( "image/Chara/MadeFace.png" );
HukeiFace = LoadGraph( "image/Chara/HukeiFace.png" );
HPBack = LoadGraph( "image/States/HPBack.png" );
MPBack = LoadGraph( "image/States/MPBack.png" );
CPBack = LoadGraph( "image/States/CPBack.png" );
HPBar = LoadGraph( "image/States/HPBar.png" );
MPBar = LoadGraph( "image/States/MPBar.png" );
CPBar = LoadGraph( "image/States/CPBar.png" );
StatesMask = LoadMask( "image/States/StatesMask.png" );
//コマンド
LoadDivGraph( "image/Command/Waku.png" , 2 , 1 , 2 , 80 , 32 , CommandWaku );
Waku = CommandWaku[0];
//初期設定
//プレイヤー1
Player.X = 6 , Player.Y = 8 ; //プレイヤー座標
Player.DrawX = (15-Player.Y)*(48/2)+(Player.X*24)-24 ; //描画座標をXY座標から計算
Player.DrawY = (Player.X+Player.Y)*12-24 ; //描画座標をXY座標から計算
Player.walk = 0;
Player.muki = 0;
Player.scope = 5; //移動距離
Player.img = Made[16];
Player.HPMAX = 1000;
Player.HP = Player.HPMAX;
Player.MPMAX = 620;
Player.MP = Player.MPMAX;
Player.CPMAX = 535;
Player.CP = Player.CPMAX;
//プレイヤー2 //まだ操作はできない
Player2.X = 240 , Player2.Y = 216 ;
Player2.HPMAX = 700;
Player2.HP = Player2.HPMAX;
Player2.MPMAX = 300;
Player2.MP = Player2.MPMAX;
Player2.CPMAX = 57;
Player2.CP = Player2.CPMAX;
//文字サイズ、フォント
BattleStatesFont = CreateFontToHandle("MS ゴシック" , 10 , 1 , DX_FONTTYPE_NORMAL);
CommandFont = CreateFontToHandle("MS ゴシック" , 15 , 1 , DX_FONTTYPE_NORMAL);
while(ProcessMessage()==0 && ClearDrawScreen()==0 && GetHitKeyStateAll_2(Key)==0 && Key[KEY_INPUT_ESCAPE]==0){
//↑メッセージ処理 ↑画面をクリア ↑入力状態を保存 ↑ESCが押されていない
DrawFormatString( 0, 0, GetColor( 0, 255, 0 ), "%d", Zcount );
animetime++;
Input();//キー入力
DrawMap(); //マップを描画
if(Turn==0){ //ターンが0ならプレイヤーのターン
PlayerTurn();
}
MapScroll(); //マップがスクロール(ターンが増えた後に消す)
DrawChara(); //キャラ描画
DrawStates(); //ステータス描画
DrawCommand(); //コマンド描画
if(Player.HP<=0) //HPは0より下がらない
Player.HP = 0;
if(Player.HP>=Player.HPMAX) //HPはMAXより上がらない
Player.HP = Player.HPMAX;
if(Player.MP<=0) //MPは0より下がらない
Player.MP = 0;
if(Player.MP>=Player.MPMAX) //MPはMAXより上がらない
Player.MP = Player.MPMAX;
if(Player.CP<=0) //CPは0より下がらない
Player.CP = 0;
if(Player.CP>=Player.CPMAX) //CPはMAXより上がらない
Player.CP = Player.CPMAX;
ScreenFlip();
}
- softya(ソフト屋)
- 副管理人
- 記事: 11677
- 登録日時: 15年前
- 住所: 東海地方
- 連絡を取る:
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
見た範囲ではOKですが、直接数値が打ち込まれている所が多数ありますので今後のためには表示座標を求める関数を作るとか値はconst変数にするとかしないと後で苦労すると思います。
注意したほうが良いなと思ったこと。
(1)同じような処理や計算が何度も出てくると時は要注意。1行の計算式でもなんどでも出てくるなら関数化を心がける。
(2)数値の意味が半年先に分からなくならないように名前付けする。
(3)マップの大きさなど可変する要素の可能性のあるものは今の内に変数にしておく。
(4)ステータスなどでもenumで名前付けをする。
注意したほうが良いなと思ったこと。
(1)同じような処理や計算が何度も出てくると時は要注意。1行の計算式でもなんどでも出てくるなら関数化を心がける。
(2)数値の意味が半年先に分からなくならないように名前付けする。
(3)マップの大きさなど可変する要素の可能性のあるものは今の内に変数にしておく。
(4)ステータスなどでもenumで名前付けをする。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。
-
chalaza
Re: クォータービューRPGでマップチップ数値で移動可能か判定する
とりあえずXY座標から描画座標を求める式は早めに関数化しておきます。
変数にして名前を付けるのもこれから先を作る前にやっといたほうが良いようですね。
わざわざ長いのに見てくれてありがとうございました。
この問題も解決です。
変数にして名前を付けるのもこれから先を作る前にやっといたほうが良いようですね。
わざわざ長いのに見てくれてありがとうございました。
この問題も解決です。