初代マリオカート、もしくは初代F-ZEROの処理をするには?

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
KEYONN_

初代マリオカート、もしくは初代F-ZEROの処理をするには?

#1

投稿記事 by KEYONN_ » 16年前

こんばんは、TKOZです。
スーパーマリオカート、もしくは初代F-ZEROの様な画面処理を行う
アルゴリズムを考えていたのですが、なかなか思いつかず、
困っています。
そこで、googleで検索してみました。
すると、
ttp://hakuhin.hp.infoseek.co.jp/main/as/raster_efc.html#RASTER_EFC_04

上記のURLでは、Flash8を使って、F-ZERO風の画面処理を行っているのですが、
ソースを見ても、DXライブラリに移植する方法が思いつきません。

点を描画する関数は、作りました。実際に動きますが、
sin,cos関数などを使う場合、ループの中に使わずに、
事前にテーブル処理しないと、30FPSは出ない気がします。
void PSet(int x,int y,int r,int g,int b)
{
	DrawPixelSoftImage( handle, x, y, r, g, b, 0 ) ;
}
どうすればいいのでしょうか?
お願いします。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#2

投稿記事 by Justy » 16年前


>DXライブラリに移植する方法が思いつきません

 DXライブラリであれば、普通に 3D機能使えばいいんじゃないでしょうか?

 適当に板を1枚置いて、カメラの向きを斜めから見るように配置すれば
それっぽくなると思いますが。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#3

投稿記事 by KEYONN_ » 16年前

ああ、そのやり方がありましたね。
気づきませんでした。
Justyさん、ありがとうございます。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#4

投稿記事 by KEYONN_ » 16年前

カメラの向きの角度と、カメラの座標を操作する関数みたいなものは、ありますでしょうか?
一応、ポリゴンの座標点を操作して、それっぽい画面を作ってみました。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#5

投稿記事 by KEYONN_ » 16年前

自分なりに回転と移動を実装してみましたが、うまくいきませんでした。
どこがおかしいのでしょうか?
ソースを添付します。
void YRotate(float angle)
{
	for(int i=0;i<6;i++)
	{
		float xt=Vertex.pos.x;float zt=Vertex.pos.z;
		float xd=xt*cos(angle*RAD)-zt*sin(angle*RAD);
		float zd=xt*sin(angle*RAD)+zt*cos(angle*RAD);

		Vertex.pos.x=xd;
		Vertex.pos.z=zd;
	}
}


void move(float speed)
{
	for(int i=0;i<6;i++)
	{
		Vertex.pos.x+=cos(CameraRot*RAD)*speed;
		Vertex.pos.z-=sin(CameraRot*RAD)*speed;
	}
}

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#6

投稿記事 by Justy » 16年前


>カメラの座標を操作する関数みたいなものは、ありますでしょうか

 あります。
 SetTransformToView()がそうで、カメラのビュー行列を指定します。
 ビュー行列は CreateLookAt*()系の関数で作成できます。



>回転と移動を実装してみましたが、うまくいきませんでした

 そんなしち面倒な計算は自前でやらなくても、せっかくDXライブラリがあるのですがら
それを使いましょう。


1 オブジェクトの姿勢を決める(移動・回転行列を作る)
 CreateIdentityMatrix() / CreateTranslationMatrix() / CreateRotation?Matrix() / CreateMultiplyMatrix()など

2 1をワールド行列として設定
 SetTransformToWorld()

3 オブジェクトを描画
 DrawPolygon3D() / DrawPolygon3DBase()

 これで移動・回転したオブジェクトが表示されるはずです。

 つまり、Vertexの中身は最初に設定したものをそのまま使い、以降は行列を変更することで
移動・回転・拡大を行います。

 ただ、注意が必要なのは、DXライブラリの初期のカメラの位置は [0, 0, 0]ではく、
2D画面と合わせようとおかしな位置にあるので、カメラの位置もきちんと併せて設定した方がいいでしょう。

 FZero/Mカートを作るなら、今の形のように背景を動かして移動するのではなく、
コース(地面・背景)は位置を固定し、キャラを行列で移動させ、プレイヤーをカメラが追っ掛ける、
という形で作ると楽かと思います。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#7

投稿記事 by KEYONN_ » 16年前

Justyさん、すみませんが、行列系の関数の使い方がいまいち分かりません。
実行してみたら、うまくいきませんでした。

サンプルプログラムみたいなものを書いて頂くか、
ソースを添削して頂くと大変嬉しいです。

私が書いたソースプログラムをアップします。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#8

投稿記事 by Justy » 16年前

 ざっくりとサンプルを作ってみました。
 添付のサンプルは cart.pngと course.pngがあれば動きます。
 
 Cart::Draw()内の処理を見るとわかると思いますが、CreateTranslationMatrixはただ移動するだけ、
CreateRotation*Matrixはただ回転するだけの行列を生成しますので、移動して回転するには
それぞれの行列を CreateMultiplyMatrix()で合成しなけばなりません。
[color=#d0d0ff" face="monospace]
MATRIX m, matTrans, matRotY;

CreateTranslationMatrix(&matTrans, m_Pos.x, m_Pos.y, m_Pos.z);
CreateRotationYMatrix(&matRotY, m_RotY);
CreateMultiplyMatrix(&m, &matRotY, &matTrans);

SetTransformToWorld(&m);
[/color]


 そのあたりに注意して自分なりに書き直してみてください。


※ 5/19 00:04 ちょっとバグ修正と調整をしました

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#9

投稿記事 by KEYONN_ » 16年前

地面との当たり判定を行ってみました。一応、うまく動作します。
やり方は、LoadSoftImage関数で頂点群と同じ大きさの画像を扱える形のデータ
(courcedat.png::2000×1500の大きさ)
にして、GetPixelSoftImage関数で無理やりRGBAを読み取り、緑色(0,255,0)だったら、
カートのスピードを遅くするというものです。しかし、コースを外れて、
コース外にでて、しばらく何もキーを押さずにすると、後ろに下がってしまいます。

ソースアップします。

あと、
>>そのあたりに注意して自分なりに書き直してみてください。
難しすぎて、自分には、少しのパラメータを自分好みにアレンジすることしか
できませんでした。

バグ

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#10

投稿記事 by バグ » 16年前

遅くするのではなく、最高速度を下げるというのはどうでしょうか?

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#11

投稿記事 by Justy » 16年前


>カートのスピードを遅くするというものです

 そりゃまぁ Accelerator()に負を入れるというのは逆噴射しているようなものなので
速度が0になるまで減速したらそのままバックします。

 地面の状態によって速度を変えたいのであれば、摩擦係数を変えるのが一番楽です。
 UpdateParameter()の中で 0,99を掛けていたところがあったと思いますが、その値を
変動(小さくなるよう)させれば減速します。

 先のやつを少し改造して、LSHIFTキーで(芝生に入った感になるよう)減速するように
してみました。
(ついでに計算結果が NaNになる嫌なバグも直しました)

 このサンプルでは押し続ければ続けただけどんどん係数を小さくしているので速度は延々と
落ちていきますが、実際のゲームでは係数を毎フレーム変動させないで一定値にするとか、
毎フレーム変動させるとしてもどこかで止めるとか状況に合わせて工夫をした方がいいでしょう。



>難しすぎて、自分には、少しのパラメータを自分好みにアレンジすることしか
できませんでした

 理解しないまま、コピペルーチンを使うと後々修正・調整出来なくなるので、
使うのであれば理解できるよう頑張ってください。


05/21 23:58 GetVectorAngle()のバグ修正

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#12

投稿記事 by KEYONN_ » 16年前

リプレイデータを作成して、敵の動きを作ろうと思ったので、
作ってみました。なんと562KBもありました。
バイナリデータで、この値は大きいのでしょうか?
添付データは120KBが限界みたいなので、載せません。
圧縮技術については、あまりよく分からないのですが、
ttp://homepage2.nifty.com/natupaji/DxLib/lecture/Press/press.html
上のURLで勉強したほうがいいのでしょうか?

あと、敵を動かすのは、リプレイデータから座標と角度を代入すれば
いいので、簡単でできるのですが、
敵の位置と敵の移動角度、カメラの位置を判断して、カメラから見た
敵の角度は、どうやって計算して、描画すればいいのか分かりません。

僕としては、15度ずつY軸で、ずらした車の画像を横並びに並べて、24枚の画像を
つなげた画像を用意しようと考えています。

ソースアップします。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#13

投稿記事 by Justy » 16年前


>バイナリデータで、この値は大きいのでしょうか?

  36000フレーム(60fpsで10分)なので多少大きくはなるとは思いますが
本当に必要なデータが入ってるなら、今時の Windows環境であれば
さほど大きいわけではないと思います。

 ただ、ソースを見ると位置と角度をまんま保存しているように見えます。、
 この手のゲームならキー入力を保存しておいて、再生時はそのデータを元に
キー入力を偽装していけば、リプレイは可能だと思いますがいかがでしょうか?

龍神録プログラミングの館にリプレイをつける
ttp://www.play21.jp/board/formz.cgi?action=res&resno=22359&page=&lognum=70&id=dixq&rln=22441

リプレイ保存の方法
ttp://www.play21.jp/board/formz.cgi?action=res&resno=32519&page=&lognum=&id=dixq&rln=33526&vino=69

 キー入力を保存する方式であれば、データはもっとずっと小さくなるはずです。



>圧縮技術については、あまりよく分からないのですが

 どうしてもよほど大きくなるようなら圧縮も検討した方がいいでしょうが、
キー入力を保存する形式にすればそれほど大きくなりませんよ。



>敵の位置と敵の移動角度、カメラの位置を判断して、カメラから見た
>敵の角度は、どうやって計算して、描画すればいいのか分かりません。

 えーと、今ひとつピンとこないのですが、敵の角度……つまり、
まっすぐ進んでいるのか曲がっているのかの計算ということですか?

 前のフレームの位置と現在の位置とのベクトルを毎フレーム出して、
その変化の具合を見ればどれくらい曲がっているのかはわかると思います。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#14

投稿記事 by KEYONN_ » 16年前

ネットカフェからです。こんにちは、TKOZです。
>>えーと、今ひとつピンとこないのですが、敵の角度……つまり、
>>まっすぐ進んでいるのか曲がっているのかの計算ということですか?
すみません、私の説明が分かりにくかったみたいです。

敵座標にビルボードのようなポリゴンを生成して、テクスチャーは、
敵の向きを向いている画像にしたかったのです。

角度から画像を取り出すには、元X座標は、(角度/15)*64で良いと思います。
あとは、 DrawRectGraph()で出来るはずです。

あと、先の誘導で、リプレイデータの生成について、
Justyさんが、素晴らしいリプレイデータの作成アルゴリズムを書いてあったのを
見つけました。
そのおかげで、リプレイデータは、32kbくらいまで大幅に減りました。
ありがとうございます。

しかし、
自カートは、リプレイデータを適用すると、うまく動いたのですが、
敵カートがうまく動いてくれません。ソースをアップするので、
どこがおかしいか指摘していただくと嬉しいです。

追記:2009/5/21/17:48 SetRePlay()関数内の最後にEnemyCart.Update()としても駄目でした。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#15

投稿記事 by Justy » 16年前


>敵カートがうまく動いてくれません

 EnemyCart.Update()が行われているのであれば、おかしいのは表示の部分(DrawCube3Dのあたり)でしょう。
 
 DrawCube3Dを止めて、EnemyCartのテクスチャを読み込んだ上で、従来通り DrawPolygon3DBase()で
描画するとどうなりますか?

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#16

投稿記事 by KEYONN_ » 16年前

>>EnemyCart.Update()が行われているのであれば、
>>おかしいのは表示の部分(DrawCube3Dのあたり)でしょう。
>>DrawCube3Dを止めて、EnemyCartのテクスチャを読み込んだ上で、従来通り DrawPolygon3DBase()で
>>描画するとどうなりますか?

テクスチャーは読み込まれませんが、黒い四角形が移動しました。
ありがとうございます。敵が動くようになりました。
あとは、ビルボードの処理がうまくいけばいいと思います。

追記:2009/5/21/20:47
EnemyCart.LoadImage();をInit()内に書き込みましたが、それでもうまくテクスチャーが張られないようです。
きちんと、2のn乗のサイズにしてあるのですが…何故でしょうか?

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#17

投稿記事 by Justy » 16年前


>それでもうまくテクスチャーが張られないようです

 テクスチャが読み込めてないのでは?
 LoadGraphの戻り値を確認してください。



>ビルボードの処理

 こちらが参考になると思います。
 
ビルボード - ゲームプログラミングWiki
ttp://www.c3.club.kyutech.ac.jp/gamewiki/index.php?%A5%D3%A5%EB%A5%DC%A1%BC%A5%C9#w8cf1d9a

 Cameraクラスがカメラ行列を持っているので、そのまま適用できるはずです。
 求めた行列(カメラの方を向く回転行列)と敵の位置の分だけ移動した行列を掛け合わせたものを
ワールド行列に設定して、あとは DrawPolygon3DBase(CartVertex)とかで表示すれば、
敵の位置に常にカメラの方を向いたテクスチャが表示されるはずです。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#18

投稿記事 by Justy » 16年前

 あぁ、そうそう。
 何点か修正しておいた方が良い箇所があります。

[color=#d0d0ff" face="monospace]
VECTOR NegativeVector(const VECTOR &v)
{
VECTOR rv;
rv.x = -v.x;
rv.y = -v.y;
rv.z = -v.z;
return rv;
}
VECTOR VectorSlerp(const VECTOR &src, const VECTOR &dest, float t)
{
float theta = DotProduct(src, dest);
float invT = 1.0f - t;

VECTOR src_v;
VECTOR dest_v;
if(theta < 0.0f)
{
src_v = NegativeVector(src_v, src);
theta = -theta;
}
[/color]

 これは前回の投稿では直したのですが、VectorSlerp()の最初の SubVectorはこのままですと
不定になってしまうので、NegativeVectorにしておいてください。

[color=#d0d0ff" face="monospace]
float GetVectorAngle(const VECTOR &v1, const VECTOR &v2)
{
float r = DotProduct(v1, v2);
if(r > 1.f) r = 1.f;
else
if(r < -1.f) r = -1.f;
return acos(r);
}
[/color]

 これも直しておいたのですが、誤差で NaNになってしまう可能性がありますので
こうしておいてください。

[color=#d0d0ff" face="monospace]
float VectorLength(const VECTOR &v)
{
return sqrtf(v.x * v.x + v.y * v.y + v.z * v.z);
}
[/color]

 さっき気づきました……orz。
 こちらも修正しておいてください。

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#19

投稿記事 by KEYONN_ » 16年前

ビルボード処理を行うためにいろいろ試してみましたが、
うまくいきませんでした。
サンプルプログラムが欲しいです。
あと、画像は、正常に読み込まれているようです。
racing.mp3は、重いので、外しました。

どうやら、テクスチャーの左上の座標だけが、全体の色になっているようです。
DrawPolygon3DBaseのバグでしょうか?

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#20

投稿記事 by Justy » 16年前


>ビルボード処理を行うためにいろいろ試してみましたが、
>うまくいきませんでした。

 どううまくいかなかったのでしょうか。
 添付されたコードにはカメラ行列を使ってどうこうした形跡がないのですが……。

 ところで一つお訊きしますが、3Dにおける行列の概念はきちんと理解されていますか?



>サンプルプログラムが欲しいです

 先のページに二種類の方法で載っていまし、動くであろうサンプルが
zipファイルでDLできるようになっていますよ。
 これを読み解いて概念を理解すれば応用できるはずです。



>テクスチャーの左上の座標だけが、全体の色になっているようです。

 よく意味がわかりません。
 左上の座標の1点が、全体の色になっている????

KEYONN_

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#21

投稿記事 by KEYONN_ » 16年前

>>3Dにおける行列の概念はきちんと理解されていますか?
行列は、あんまり理解していません。
単位行列がIdentityMatrix()で作成できて、
TranslationMatrix()で平行移動行列が作成できること、
MultiplyMatrix()で行列同士を合成できることくらいですかね。

レースゲームの作成は中断して、行列を勉強することにします。

Justy

Re:初代マリオカート、もしくは初代F-ZEROの処理をするには?

#22

投稿記事 by Justy » 16年前


>行列を勉強することにします。

 行列の各値が何を意味しているのか、ベクトルの関係とか諸々が理解できると
いろいろ応用が利くようになります。

 ビルボードは結局のところ、回転要素だけ見ればカメラの向きを反対に向けたものとなります。
 従って、カメラの行列を元に回転要素を取り出し、その逆行列を求めることで
カメラの向きの反対を向く行列となります。
 この行列と敵の位置の行列とを掛け合わせれば、敵がこっちをむいた行列になります。

 先の紹介したページにあるように、カメラ行列を転置させて作っていいですね。


 ただ、このレースゲームの敵の描画、という観点から見るとビルボードで行う場合
Y軸だけは上を向いていた方がいいかもしれません。

 つまり、Y軸はワールドに対して上を向き、カメラの位置に対して回転するのはXZ軸のみ、
のようなビルボードにしないと、カメラの位置(たとえば真上から車をとらえた時など)に
よっては不自然な描画となってしまうかもしれません。
(この方法も先の紹介したページに載っています)


 あと、すでにお気づきかもしれませんが別の懸念点もありまして、
添付の図のようにコースが 180度曲がるような急なカーブで、
敵の車が先行していたような場合、敵の絵が後ろから見たものだと、
車の後ろを見せながらプレイヤーの横を通ることになり、不自然な絵となる
可能性があります。

 このあたりも考慮に入れて頑張って見てください。

閉鎖

“C言語何でも質問掲示板” へ戻る