OpenGLでAABB
操作方法は昨日と同じです。
AABBは頂点の最小値と最大値を引っ張ってきて、
比較するだけなので、判定処理は簡単ですね。
むしろ、箱を表示するのに手間がかかりました…(´∀`;
#include <math.h> #include <string> #include <iostream> #include <glut.h> #include <ctype.h> using namespace std; /** * 3次元ベクトル構造体 */ struct Vec3 { float x, y, z; Vec3(float x=0, float y=0, float z=0){this->x=x; this->y=y; this->z=z;} Vec3 operator +(Vec3 &vec) {return Vec3(this->x+vec.x, this->y+vec.y, this->z+vec.z);} Vec3 operator -(Vec3 &vec) {return Vec3(this->x-vec.x, this->y-vec.y, this->z-vec.z);} Vec3 operator *(float f) {return Vec3(this->x*f, this->y*f, this->z*f);} Vec3 operator /(float f) {return Vec3(this->x/f, this->y/f, this->z/f);} Vec3 operator =(Vec3 &vec) {return Vec3(this->x=vec.x, this->y=vec.y, this->z=vec.z);} Vec3 operator ==(Vec3 &vec) {return (this->x==vec.x && this->y==vec.y && this->z==vec.z);} Vec3 operator !=(Vec3 &vec) {return (this->x!=vec.x || this->y!=vec.y || this->z!=vec.z);} void Set(float x, float y, float z) {this->x=x; this->y=y; this->z=z;} // スカラの二乗を求める float LengthSq() {return x*x + y*y + z*z;} // スカラ float Length() {return sqrt(LengthSq());} // 正規化 Vec3 Normalize() { float m = LengthSq(); if (m > 0.0f) m = 1.0f / m; else m = 0.0f; return Vec3(x*m, y*m, z*m); } // 内積 float Dot(Vec3 &vec) { return (this->x*vec.x + this->y*vec.y + this->z*vec.z); } // 外積 Vec3 Cross(Vec3 &vec) { return Vec3( this->y*vec.z - this->z*vec.y, this->z*vec.x - this->x*vec.z, this->x*vec.y - this->y*vec.x); } string Debug() { char tmp[256]; sprintf(tmp, "(x,y,z)=(%f,%f,%f", x, y, z); string ret = tmp; return ret; } }; /** * 箱構造体 */ struct TCube { Vec3 pos; // 中心座標 Vec3 radius; // 半径 Vec3 rot; // 回転角度 Vec3 GetMinVec3() { return Vec3( pos.x-radius.x, pos.y-radius.y, pos.z-radius.z); } Vec3 GetMaxVec3() { return Vec3( pos.x+radius.x, pos.y+radius.y, pos.z+radius.z); } }; // 境界箱(AABB)による当たり判定 bool IsCollideBoxAABB(Vec3 vMin1, Vec3 vMax1, Vec3 vMin2, Vec3 vMax2) { if( vMin1.x < vMax2.x && vMax1.x > vMin2.x && vMin1.y < vMax2.y && vMax1.y > vMin2.y && vMin1.z < vMax2.z && vMax1.z > vMin2.z) { return true; } return false; } /** * 箱の描画 */ void DrawCube(Vec3 pos, Vec3 radius, Vec3 rot, int color) { // シーンの描画 static GLfloat red[] = { 0.8, 0.2, 0.2, 1.0 }; static GLfloat gleen[] = { 0.2, 0.8, 0.2, 1.0 }; static GLfloat blue[] = { 0.2, 0.2, 0.8, 1.0 }; GLfloat *c; if(color == 0) c = red; else if(color == 1) c = gleen; else c = blue; // 陰影付けをONにする glEnable(GL_LIGHTING); // 球描画 glPushMatrix(); { glTranslatef(pos.x, pos.y, pos.z); glRotatef(rot.x, 1, 0, 0); glRotatef(rot.y, 0, 1, 0); glRotatef(rot.z, 0, 0, 1); glScaled(radius.x*2, radius.y*2, radius.z*2); glMaterialfv(GL_FRONT, GL_DIFFUSE, c); glutSolidCube(1); } glPopMatrix(); // 陰影付けをOFFにする glDisable(GL_LIGHTING); } TCube self; // 箱1(コイツが動く) TCube target; // 箱2(コイツは動かない) Vec3 vEye; // カメラ座標 /** * 初期化 */ void Init(void) { // 初期設定 glClearColor(0.0, 0.0, 1.0, 0.0); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_LIGHT0); // 箱を作る self.pos = Vec3(1, 0, 0); self.radius = Vec3(0.5f, 0.5f*2, 0.5f); self.rot = Vec3(0, 0, 0); target.pos = Vec3(0, 0, 0); target.radius = Vec3(0.5f, 0.5f, 0.5f*2); target.rot = Vec3(0, 0, 0); // カメラ座標初期化 vEye = Vec3(0, 0, -5); } /** * キーが押されたときの処理 * @param key 押下キー * @param x, y 座標 */ void InputKey(unsigned char key, int x, int y) { // 動かす float mov = 0.1f; float rot = 1; switch(toupper(key)) { case 'Z': self.pos.x -= mov; break; case 'X': self.pos.x += mov; break; case 'A': self.pos.y -= mov; break; case 'S': self.pos.y += mov; break; case 'Q': self.pos.z -= mov; break; case 'W': self.pos.z += mov; break; case 'C': self.rot.x -= rot; break; case 'V': self.rot.x += rot; break; case 'D': self.rot.y -= rot; break; case 'F': self.rot.y += rot; break; case 'E': self.rot.z -= rot; break; case 'R': self.rot.z += rot; break; case 0x1b: // ESCキー // プログラムを終了 exit(0); break; } // 当たり判定 Vec3 vMin1 = self.GetMinVec3(); Vec3 vMax1 = self.GetMaxVec3(); Vec3 vMin2 = target.GetMinVec3(); Vec3 vMax2 = target.GetMaxVec3(); if(IsCollideBoxAABB(vMin1, vMax1, vMin2, vMax2)) { cout << "隊長!当たってます!!" << endl; } else { cout << "当たってません。" << endl; } } /** * 特殊キーが押されたときの処理 * @param key 押下キー * @param x, y 座標 */ void InputKeySp(int key, int x, int y) { // カメラ移動 Vec3 vAxis; Vec3 vN; switch(key) { case GLUT_KEY_UP: // 上キー vAxis = Vec3(-1, 0, 0); break; case GLUT_KEY_DOWN: // 下キー vAxis = Vec3(1, 0, 0); break; case GLUT_KEY_LEFT: // 左キー vAxis = Vec3(0, 1, 0); break; case GLUT_KEY_RIGHT: // 右キー vAxis = Vec3(0, -1, 0); break; } vN = vEye.Normalize().Cross(vAxis); vEye = vEye + vN; } /** * 描画 */ void Display(void) { // 画面クリア glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 視点の移動 glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(vEye.x, vEye.y, vEye.z, 0, 0, 0, 0, 1, 0); // 箱の描画 DrawCube(self.pos, self.radius, self.rot, 0); DrawCube(target.pos, target.radius, target.rot, 1); // 地面を線画で描く glColor3d(0.0, 0.0, 0.0); glBegin(GL_LINES); { for (int i = -10; i <= 10; i++) { glVertex3d((GLdouble)i, -0.5, -10.0); glVertex3d((GLdouble)i, -0.5, 10.0); glVertex3d(-10.0, -0.5, (GLdouble)i); glVertex3d( 10.0, -0.5, (GLdouble)i); } } glEnd(); glutSwapBuffers(); } /** * ウィンドウのリサイズ */ void Resize(int w, int h) { // ウィンドウ全体をビューポートにする glViewport(0, 0, w, h); // 透視変換行列を設定する glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(30.0, (double)w / (double)h, 1.0, 100.0); // モデルビュー変換行列を指定しておく glMatrixMode(GL_MODELVIEW); } /** * アイドル時 */ void Idle() { glutPostRedisplay(); } /** * メイン関数 */ int main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA | GLUT_DEPTH | GLUT_DOUBLE); glutCreateWindow(argv[0]); glutDisplayFunc(Display); glutReshapeFunc(Resize); // キーボード入力用関数を登録 glutKeyboardFunc(InputKey); glutSpecialFunc(InputKeySp); glutIdleFunc(Idle); Init(); // メインループ glutMainLoop(); return 0; }
役に立つのかどうか分からない会話2
今作っているゲームを先生に見てもらいました。
以下は、その会話の抜粋。
先生「お、3Dか。一通りシーンのループして、、、マップもあるね。 当たり判定はスフィアか、、。まあ、これだけやれば、(うちの学校の)賞は取れるよ」 kenmo「…あの、、、これ持って就職活動できますかね?」 先生「それは無理(あっさり)」 kenmo「ガーンΣ(゜Д゜) ど、どほすればいいですかね…。」 先生「うーん、この敵キャラ、アニメしないっしょ。メッシュのアニメーションは常識」 kenmo「…」 先生「あと、地味。 頭飛ばしたときに、エフェクト。敵にぶつけて、エフェクト。 敵にぶつかってもエフェクト、ぐらいしないと。 『1アクションに1エフェクト』。基本だよ」 kenmo「…」 先生「地形に何もないよね。アイテムとか、破壊できるオブジェクトを置かないと、単調だよ」 kenmo「…あ、ありがとうございました…」 先生「いえいえ」
kenmoの課題がいっぺんに増えました…(´Д`;