Dxlibを使って2dのアクションゲームを作っているのですが、
坂道の部分の作り方がわかりません
マップを作るとき、マップデータの配列を読込んでその情報をもとに四角いマップチップ?からマップを作るので階段状になってしまうと思うのですが、
マップとのあたり判定もプレイヤーのいる位置を配列の番号に変換して、移動量を足したときの配列の番号がマップの番号になっていないか確認するので
どうやっても無理なんじゃないかとおもっているのですが、どうやって作っているのですか?
2dアクションゲームの坂道
Re: 2dアクションゲームの坂道
お聞きしたいのですが
0,0,0...
1,player,0...
1,1,0...
1,1,1...
...
このプレイヤーの位置での下端、左端
0,0,0...
1,0,player...
1,1,0...
1,1,1...
...
このプレイヤーの位置での角部分
これの左右で6つということですか?
これはつまり1pxごとにあたり判定を取るということでしょうか?予想ですけど、ピクセル画像の単位が32x32としたときに、
char sakamiti_atari[32][32] = {
0,0,0...
1,0,0...
1,1,0...
1,1,1...
...
};
すみません。どこの6つなのでしょうか?判定しなければならない坂道は最高6つになりますよね
(キャラクター2x1で中途半端なところにいるのを勘案して3x2)。
0,0,0...
1,player,0...
1,1,0...
1,1,1...
...
このプレイヤーの位置での下端、左端
0,0,0...
1,0,player...
1,1,0...
1,1,1...
...
このプレイヤーの位置での角部分
これの左右で6つということですか?
Re: 2dアクションゲームの坂道
右上がりの坂がバグっていますが、やり方は示していると思います。
直線の坂なので、当たり判定を配列ではなく、1次不等式に変えました。
(製作時間5時間くらいかかっているから勘弁してほしいー)
直線の坂なので、当たり判定を配列ではなく、1次不等式に変えました。
(製作時間5時間くらいかかっているから勘弁してほしいー)
#include "DxLib.h"
#define _USE_MATH_DEFINES
#include <math.h>
const int BLOCKSIZE = 20;
const UCHAR map_transpose[6][7] = {
// 012345
"WWWWWW",
"W W",
"W W",
"W W",
"W@ P/W",
"WWWWWW" };
UCHAR map[6][6];
int px, py; // キャラクターの位置
int vx, vy; // キャラクターの速度
int npx, npy; // キャラクターの次の位置
bool up = false, left = false, right = false; // キー状態
void DrawMap() {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
if (map[i][j] == 'W')
DrawBox(i * BLOCKSIZE, j * BLOCKSIZE, (i + 1)*BLOCKSIZE, (j + 1)*BLOCKSIZE,
GetColor(0xff, 0x00, 0x00), TRUE);
else if (map[i][j] == '@')
DrawTriangle(i * BLOCKSIZE, j * BLOCKSIZE, (i + 1)*BLOCKSIZE, (j + 1)*BLOCKSIZE,
i*BLOCKSIZE, (j + 1)*BLOCKSIZE, GetColor(0xff, 0x00, 0x00), TRUE);
else if (map[i][j] == '/')
DrawTriangle(i * BLOCKSIZE, (j + 1) * BLOCKSIZE, (i + 1)*BLOCKSIZE, j*BLOCKSIZE,
(i + 1)*BLOCKSIZE, (j + 1)*BLOCKSIZE, GetColor(0xff, 0x00, 0x00), TRUE);
}
}
}
void DrawCharacter() {
DrawBox(px, py, px + BLOCKSIZE, py + 2 * BLOCKSIZE,
GetColor(0x00, 0xff, 0x00), TRUE);
}
bool IsContact() {
int i = px / BLOCKSIZE, j = py / BLOCKSIZE;
if (px % BLOCKSIZE == 0 && py % BLOCKSIZE == 0) {
// キャラクターはブロック交差点上
if (map[i][j + 2] == 'W' || map[i][j + 2] == '@' || map[i][j + 2] == '/') return true;
if (map[i - 1][j + 2] == '@' || map[i - 1][j + 2] == '/') return true;
if (map[i + 1][j + 2] == '@' || map[i + 1][j + 2] == '/') return true;
return false;
}
if (py % BLOCKSIZE == 0) {
// キャラクターはブロック横棒境界線上
if (map[i][j + 2] == 'W' || map[i + 1][j + 2] == 'W') return true;
return false;
}
if (px % BLOCKSIZE == 0) {
// キャラクターはブロック縦線境界線上
return false;
}
// キャラクターはブロック内
if (map[i][j + 2] == '@') {
if (px % BLOCKSIZE == py % BLOCKSIZE) return true;
}
if (map[i][j + 2] == '/') {
if ((px % BLOCKSIZE) + (py % BLOCKSIZE) == BLOCKSIZE - 1) return true;
}
return false;
}
// プログラムは WinMain から始まります
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
if (DxLib_Init() == -1) return -1;
// マップを転置(x->y, y->x)
for (int i = 0; i < 6; i++)
for (int j = 0; j < 6; j++)
map[i][j] = map_transpose[j][i];
// キャラクターの初期化
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 6; j++) {
if (map[i][j] == 'P') {
px = i * BLOCKSIZE;
py = (j - 1) * BLOCKSIZE;
}
}
}
SetDrawScreen(DX_SCREEN_BACK);
while (!CheckHitKey(KEY_INPUT_ESCAPE)) {
up = (CheckHitKey(KEY_INPUT_UP) != 0);
left = (CheckHitKey(KEY_INPUT_LEFT) != 0);
right = (CheckHitKey(KEY_INPUT_RIGHT) != 0);
ClearDrawScreen();
DrawMap();
DrawCharacter();
if (IsContact()) {
if (up) vy = -15; else vy = 0;
if (left) vx = -1;
else if (right) vx = 1;
else vx = 0;
}
else {
vy += 2;
}
npx = px + vx;
npy = py + vy;
// 横の接触修正
int ni = npx / BLOCKSIZE;
int nj = npy / BLOCKSIZE;
if (npx % BLOCKSIZE == 0) {
// ブロック縦線境界上
; // void
}
else if (npy % BLOCKSIZE == 0) {
// ブロック横線境界上
if (vx > 0 && (map[ni + 1][nj] == 'W' || map[ni + 1][nj + 1] == 'W'))
npx -= npx % BLOCKSIZE;
if (vx < 0 && (map[ni][nj] == 'W' || map[ni][nj + 1] == 'W'))
npx += BLOCKSIZE - npx % BLOCKSIZE;
}
else {
if (vx > 0 && (map[ni + 1][nj] == 'W' || map[ni + 1][nj + 1] == 'W' || map[ni + 1][nj + 2] == 'W'))
npx -= npx % BLOCKSIZE;
if (vx < 0 && (map[ni][nj] == 'W' || map[ni][nj + 1] == 'W' || map[ni][nj + 2] == 'W'))
npx += BLOCKSIZE - npx % BLOCKSIZE;
}
// 縦の接触修正
if (npy % BLOCKSIZE == 0 && npx % BLOCKSIZE == 0) {
// ブロック境界交差点上
; // void
} else if (npy % BLOCKSIZE == 0) {
// ブロック横線境界上
if (map[ni][nj + 1] == '@') {
npy -= BLOCKSIZE;
npy += npx % BLOCKSIZE;
vy = 0;
}
if (map[ni + 1][nj + 1] == '/') {
npy = npy - (npx % BLOCKSIZE);
vy = 0;
}
}
else if (npx % BLOCKSIZE == 0) {
// ブロック縦線境界上
if (vy < 0 && map[ni][nj] == 'W') {
npy += BLOCKSIZE - (npy % BLOCKSIZE);
vy = -vy;
}
if (vy > 0 && (map[ni][nj + 2] == 'W' || map[ni][nj+2]=='@'||map[ni][nj+2]=='/')) {
npy -= npy % BLOCKSIZE;
vy = 0;
}
}
else {
if (vy < 0 && (map[ni][nj] == 'W' || map[ni + 1][nj] == 'W')) {
npy += BLOCKSIZE - (npy % BLOCKSIZE);
vy = -vy;
}
if (vy > 0 && (map[ni][nj + 2] == 'W' || map[ni + 1][nj + 2] == 'W')) {
npy -= npy % BLOCKSIZE;
vy = 0;
}
if (map[ni][nj + 2] == '@' && (npy % BLOCKSIZE > npx % BLOCKSIZE)) {
npy = npy - (npy % BLOCKSIZE) + (npx % BLOCKSIZE);
vy = 0;
}
if (map[ni + 1][nj + 2] == '/' && ((npx % BLOCKSIZE) + (npy % BLOCKSIZE) > BLOCKSIZE - 1)) {
npy = npy - (npy % BLOCKSIZE) + (BLOCKSIZE - 1) - (npx % BLOCKSIZE);
vy = 0;
}
}
px = npx;
py = npy;
ScreenFlip();
ProcessMessage();
}
DxLib_End(); // DXライブラリ使用の終了処理
return 0; // ソフトの終了
}
- Dixq (管理人)
- 管理人
- 記事: 1662
- 登録日時: 14年前
- 住所: 北海道札幌市
- 連絡を取る:
Re: 2dアクションゲームの坂道
複雑な地面との当たり判定であれば地面の画像の上にキャラクタの画像を上書きして画像と画像の当たり判定を計算。
もし当たっていれば進行方向と反対方向に押し戻せばいいのではないかと思います。
3Dのポリゴン地面上を歩き回るサンプルがDXライブラリのHPに乗っていますが、考え方は参考にしたらいいのではないかと思います。
http://dxlib.o.oo7.jp/program/dxprogram_3D.html
もし当たっていれば進行方向と反対方向に押し戻せばいいのではないかと思います。
3Dのポリゴン地面上を歩き回るサンプルがDXライブラリのHPに乗っていますが、考え方は参考にしたらいいのではないかと思います。
http://dxlib.o.oo7.jp/program/dxprogram_3D.html
Re: 2dアクションゲームの坂道
Dixq さん
貴重なご意見どうもありがとうございます。
私も少しコードを書いてみて気づいたことがあるのですが、フレーム毎の移動量を大きくすると壁のすり抜けみたいな現象が発生しました。当たり判定を何回かやり直せばうまくいくのではないかと思いますが、Dixqさんのほうではどのように行っていますか?
貴重なご意見どうもありがとうございます。
私も少しコードを書いてみて気づいたことがあるのですが、フレーム毎の移動量を大きくすると壁のすり抜けみたいな現象が発生しました。当たり判定を何回かやり直せばうまくいくのではないかと思いますが、Dixqさんのほうではどのように行っていますか?
Re: 2dアクションゲームの坂道
あんどーなつ さん
わざわざサンプルプログラムまで作っていただいてありがとうございます
これを参考にしばらく自分で頑張ってみようかと思います
Dixq さん
教えていただきありがとうございます。そちらも参考にしながら進めていきたいと思います
わざわざサンプルプログラムまで作っていただいてありがとうございます
これを参考にしばらく自分で頑張ってみようかと思います
Dixq さん
教えていただきありがとうございます。そちらも参考にしながら進めていきたいと思います
- Dixq (管理人)
- 管理人
- 記事: 1662
- 登録日時: 14年前
- 住所: 北海道札幌市
- 連絡を取る:
Re: 2dアクションゲームの坂道
あんどーなつさん
当たり判定の計算って正確にやろうとしたら結構真面目に数学の知識が必要になります。
当たり判定を簡略化しても、です。
で、簡略化するために、キャラクターは一般的なゲームにおいては簡単な三角形(または円)の集合の場合が多いです。
地面も三角形の集合ですから、三角形と三角形の当たり判定が計算出来ればよいことになります。
現在のご質問は三角形と三角形(四角形)の当たり判定を正確に計算しても上図のようにすり抜けが判定できないと言うことだと思いますが、
これは進んでいるベクトルが分かっているので三角形の頂点がそのベクトルにどれだけ進んだのかという線分を3本計算し、
それと衝突対象との計算をすればすり抜けると言うことはありません。
で、計算方法ですが、私はこのような計算方法の参考には、この本を使っています。
この本に載っている三角形と三角形の当たり判定の計算方法の紹介を一部紹介します。








このような流れで計算可能です。
線分と三角形の当たり判定の計算方法も載っていますのでもしこのような計算方法を学びたければ書籍をどうぞ。
この本でなくとも似たような本は沢山あります。
プログラミングの特定の分野では数学が切っても切り離せない部分がありますので。
で、こんな計算をいちいちするのはめんどくさいので自分でせっせとあらかじめライブラリを作ってしまうか、
人が作ったライブラリを利用するか、DXライブラリならDXライブラリ標準関数を使うかするといいでしょう。
例えばこんな面倒な計算をしなくても、三角形と線分の当たり判定を計算してくれる関数はDXライブラリ内にあります。
http://dxlib.o.oo7.jp/function/dxfunc_3d.html#R16N4
当たり判定の計算は正直めんどくさいですよね。
当たり判定の計算って正確にやろうとしたら結構真面目に数学の知識が必要になります。
当たり判定を簡略化しても、です。
で、簡略化するために、キャラクターは一般的なゲームにおいては簡単な三角形(または円)の集合の場合が多いです。
地面も三角形の集合ですから、三角形と三角形の当たり判定が計算出来ればよいことになります。
現在のご質問は三角形と三角形(四角形)の当たり判定を正確に計算しても上図のようにすり抜けが判定できないと言うことだと思いますが、
これは進んでいるベクトルが分かっているので三角形の頂点がそのベクトルにどれだけ進んだのかという線分を3本計算し、
それと衝突対象との計算をすればすり抜けると言うことはありません。
で、計算方法ですが、私はこのような計算方法の参考には、この本を使っています。
この本に載っている三角形と三角形の当たり判定の計算方法の紹介を一部紹介します。
このような流れで計算可能です。
線分と三角形の当たり判定の計算方法も載っていますのでもしこのような計算方法を学びたければ書籍をどうぞ。
この本でなくとも似たような本は沢山あります。
プログラミングの特定の分野では数学が切っても切り離せない部分がありますので。
で、こんな計算をいちいちするのはめんどくさいので自分でせっせとあらかじめライブラリを作ってしまうか、
人が作ったライブラリを利用するか、DXライブラリならDXライブラリ標準関数を使うかするといいでしょう。
例えばこんな面倒な計算をしなくても、三角形と線分の当たり判定を計算してくれる関数はDXライブラリ内にあります。
http://dxlib.o.oo7.jp/function/dxfunc_3d.html#R16N4
当たり判定の計算は正直めんどくさいですよね。
Re: 2dアクションゲームの坂道
Dixq さん
あたり判定について虎の巻のようなものをご教授頂けるとは思いませんでした。
本当に本当にありがとうございます。
また、己の浅学を自覚させられました。精進いたします。
あたり判定について虎の巻のようなものをご教授頂けるとは思いませんでした。
本当に本当にありがとうございます。
また、己の浅学を自覚させられました。精進いたします。