ブラウザ上でゲーム開発を行える「Code.9leap.net」,β版サービスが始まる
これにあたり、「code.9leapカスタム・チュートリアルチャレンジ!」というコンテストが開催されました。
っということで、私もチャレンジしてみようと思います!
私がenchant.jsで最初に悩んだところは画面遷移でした。
ということで、そのあたりのチュートリアルを作ってみました 。
ゲームの基本「タイトル画面 → プレイ画面 → エンド画面」の流れを簡単に説明しています。
かっしぃの日々のメモ帳です。 気づいたことや思ったこと、プログラミングのコツ、 最近気になることなどをメモしてます。 Twitter http://twitter.com/kassy708
HRESULT NuiInitialize( DWORD dwFlags )
KINECT_DEPTH_WIDTHを#defineで事前に定義して、ここで条件分岐しています。
KinectSDKはBetaの時はDepth画像の解像度を320x240しか設定できなかったのですがenchant.PhyPolygonSprite(width, height, vertexs, type, density, friction, restitution, awake)
var width = 20; var height = 50; var vertexs = new Array( new b2Vec2(-width / 2, -height / 2), new b2Vec2(width / 2, -height / 2), new b2Vec2(width / 2, height / 2), new b2Vec2(-width / 2, height / 2)); var phyPolygonSprite = new PhyPolygonSprite(width, height, vertexs, DYNAMIC_SPRITE, 1.0, 0.1, 0.2, true); game.rootScene.addChild(phyPolygonSprite); // シーンに追加
var vertexCount = 5; var radius = 20; var vertexs = new Array(); for (var i = 0; i < vertexCount; i++) { vertexs[i] = new b2Vec2(radius * Math.cos(2 * Math.PI / vertexCount * i), radius * Math.sin(2 * Math.PI / vertexCount * i)); } var phyPolygonSprite = new PhyPolygonSprite(radius * 2, radius * 2, vertexs, DYNAMIC_SPRITE, 1.0, 0.1, 0.2, true); game.rootScene.addChild(phyPolygonSprite); // シーンに追加
//軸 var axis = new PhyCircleSprite(8, STATIC_SPRITE); axis.position = { x: 160, y: 160 }; game.rootScene.addChild(axis); // シーンに追加 //ボール生成 var ball = new PhyCircleSprite(8, DYNAMIC_SPRITE); ball.position = { x: 100, y: 250 }; game.rootScene.addChild(ball); // シーンに追加 //距離ジョイント var joint = new PhyDistanceJoint(axis, ball);
//軸 var axis = new PhyCircleSprite(8, STATIC_SPRITE); axis.position = { x: 160, y: 160 }; game.rootScene.addChild(axis); // シーンに追加 //ボール生成 var ball = new PhyCircleSprite(8, DYNAMIC_SPRITE); ball.position = { x: 100, y: 250 }; game.rootScene.addChild(ball); // シーンに追加 //距離ジョイント var joint = new PhyRevoluteJoint(axis, ball); joint.enableMotor = true; joint.maxMotorTorque = 100; joint.motorSpeed = 90;
var box = new PhyBoxSprite(16, 8, DYNAMIC_SPRITE, 1.0, 0.5, 0.2, true); box.position = { x: game.width * 2 / 3, y: game.height / 2 }; var prismaticAxis = new b2Vec2(1.0, 0); //x軸にスライドを設定(右が正の値) //スライドジョイント var prismaticJoint = new PhyPrismaticJoint(box, prismaticAxis); //スライドオブジェクトにモーター機能を持たせる場合 //prismaticJoint.enableMotor = true; //モータの有効化 //prismaticJoint.maxMotorForce = 100.0; //モータの最大力を設定 //prismaticJoint.motorSpeed = 50; //モータの速度を設定
var ball1 = new PhyCircleSprite(8, DYNAMIC_SPRITE); ball1.position = { x: 80, y: 160 }; var ball2 = new PhyCircleSprite(8, DYNAMIC_SPRITE); ball2.position = { x: 240, y: 160 }; //滑車ジョイント var pulleyJoint = new PhyPulleyJoint(ball1, ball2, new b2Vec2(80, 100), new b2Vec2(240, 100), 1);
GLCapture glCapture; void init(){ //glCaptureの設定 glCapture.setWriteFile("output.avi"); } void display(){ glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); //~描画するプログラム~ glFlush(); glutSwapBuffers(); //動画ファイルに書き込み glCapture.write(); }と、こんな感じです。
context.FindExistingNode(XN_NODE_TYPE_USER, userGenerator); xn::SkeletonCapability skeleton = userGenerator.GetSkeletonCap(); // ユーザー認識のコールバックを登録 // キャリブレーションのコールバックを登録 XnCallbackHandle userCallbacks, calibrationCallbacks; userGenerator.RegisterUserCallbacks(&::UserDetected, 0, 0, userCallbacks); skeleton.RegisterCalibrationCallbacks( 0, &::CalibrationEnd, 0, calibrationCallbacks ); skeleton.SetSkeletonProfile(XN_SKEL_PROFILE_ALL);
// ユーザー検出 void XN_CALLBACK_TYPE UserDetected( xn::UserGenerator& generator, XnUserID nId, void* pCookie ) { printf("ユーザID%d 検出 %d人目\n",nId,generator.GetNumberOfUsers()); generator.GetSkeletonCap().RequestCalibration(nId, TRUE); } // キャリブレーションの終了 void XN_CALLBACK_TYPE CalibrationEnd(xn::SkeletonCapability& capability, XnUserID nId, XnBool bSuccess, void* pCookie) { if ( bSuccess ) { printf("ユーザID%d キャリブレーション成功\n",nId); capability.StartTracking(nId); } else { printf("ユーザID%d キャリブレーション失敗\n",nId); } }
XnUserID aUsers[15]; XnUInt16 nUsers = 15; userGenerator.GetUsers(aUsers, nUsers); for (int i = 0; i < nUsers; ++i){ if (userGenerator.GetSkeletonCap().IsTracking(aUsers[i])){ XnSkeletonJointPosition joint; //aUsers[i]の頭部位置をjointに格納 userGenerator.GetSkeletonCap().GetSkeletonJointPosition(aUsers[i], XN_SKEL_HEAD, joint); } }
#include <GL/glut.h> #include <opencv2/opencv.hpp> #ifdef _DEBUG //Debugモードの場合 #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220d.lib") // opencv_core #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220d.lib") // opencv_imgproc #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220d.lib") // opencv_highgui #else //Releaseモードの場合 #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_core220.lib") // opencv_core #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_imgproc220.lib") // opencv_imgproc #pragma comment(lib,"C:\\OpenCV2.2\\lib\\opencv_highgui220.lib") // opencv_highgui #endif #include <XnCppWrapper.h> #pragma comment(lib,"C:/Program files/OpenNI/Lib/openNI.lib") #define SAMPLE_XML_PATH "C:/Program Files/OpenNI/Data/SamplesConfig.xml" using namespace cv; using namespace xn; //openNIのための宣言・定義 //マクロ定義 #define KINECT_IMAGE_WIDTH 640 #define KINECT_IMAGE_HEGIHT 480 #define KINECT_DEPTH_WIDTH 640 #define KINECT_DEPTH_HEGIHT 480 DepthGenerator depthGenerator;// depth context ImageGenerator imageGenerator;//image context UserGenerator userGenerator; DepthMetaData depthMD; ImageMetaData imageMD; Context context; //トラッキングの際のコールバック void XN_CALLBACK_TYPE UserDetected( xn::UserGenerator& generator, XnUserID nId, void* pCookie ); void XN_CALLBACK_TYPE CalibrationEnd(xn::SkeletonCapability& capability, XnUserID nId, XnBool bSuccess, void* pCookie); Mat image(480,640,CV_8UC3); Mat depth(480,640,CV_16UC1); //ポイントクラウドの座標 Mat pointCloud_XYZ(480,640,CV_32FC3,cv::Scalar::all(0)); void retrievePointCloudMap(Mat &depth,Mat &pointCloud_XYZ); //3次元ポイントクラウドのための座標変換 void drawPointCloud(Mat &rgbImage,Mat &pointCloud_XYZ); //ポイントクラウド描画 void drawUserJoint(); //ユーザの関節を描画 void DrawLimb(XnUserID player, XnSkeletonJoint eJoint1, XnSkeletonJoint eJoint2); void DrawJoint(XnUserID player, XnSkeletonJoint eJoint1); //openGLのための宣言・定義 //---変数宣言--- int FormWidth = 640; int FormHeight = 480; int mButton; float twist, elevation, azimuth; float cameraDistance = 0,cameraX = 0,cameraY = 0; int xBegin, yBegin; //---マクロ定義--- #define glFovy 45 //視角度 #define glZNear 1.0 //near面の距離 #define glZFar 150.0 //far面の距離 void polarview(); //視点変更 //描画 void display(){ // clear screen and depth buffer glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); // Reset the coordinate system before modifying glLoadIdentity(); glEnable(GL_DEPTH_TEST); //「Zバッファ」を有効 gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 1.0, 0.0); //視点の向き設定 //wait and error processing context.WaitAnyUpdateAll(); imageGenerator.GetMetaData(imageMD); depthGenerator.GetMetaData(depthMD); depthGenerator.GetAlternativeViewPointCap().SetViewPoint(imageGenerator);//ズレを補正 memcpy(image.data,imageMD.Data(),image.step * image.rows); //イメージデータを格納 memcpy(depth.data,depthMD.Data(),depth.step * depth.rows); //深度データを格納 //3次元ポイントクラウドのための座標変換 retrievePointCloudMap(depth,pointCloud_XYZ); //視点の変更 polarview(); //ポイントクラウド drawPointCloud(image,pointCloud_XYZ); //関節の描画 drawUserJoint(); //convert color space RGB2BGR cvtColor(image,image,CV_RGB2BGR); imshow("image",image); imshow("depth",depth); glFlush(); glutSwapBuffers(); } //初期化 void init(){ context.InitFromXmlFile(SAMPLE_XML_PATH); context.FindExistingNode(XN_NODE_TYPE_DEPTH, depthGenerator); context.FindExistingNode(XN_NODE_TYPE_IMAGE, imageGenerator); context.FindExistingNode(XN_NODE_TYPE_USER, userGenerator); if (!userGenerator.IsCapabilitySupported(XN_CAPABILITY_SKELETON)) { // スケルトン・トラッキングをサポートしているか確認 printf("ユーザー検出をサポートしてません\n"); } // キャリブレーションにポーズが必要 xn::SkeletonCapability skeleton = userGenerator.GetSkeletonCap(); if ( skeleton.NeedPoseForCalibration() ) { printf("このOpenNIのバージョンはポーズ無しには対応していません\n"); } // ユーザー認識のコールバックを登録 // キャリブレーションのコールバックを登録 XnCallbackHandle userCallbacks, calibrationCallbacks; userGenerator.RegisterUserCallbacks(&::UserDetected, 0, 0, userCallbacks); skeleton.RegisterCalibrationCallbacks( 0, &::CalibrationEnd, 0, calibrationCallbacks ); skeleton.SetSkeletonProfile(XN_SKEL_PROFILE_ALL); } // アイドル時のコールバック void idle(){ //再描画要求 glutPostRedisplay(); } //ウィンドウのサイズ変更 void reshape (int width, int height){ FormWidth = width; FormHeight = height; glViewport (0, 0, (GLsizei)width, (GLsizei)height); glMatrixMode (GL_PROJECTION); glLoadIdentity (); //射影変換行列の指定 gluPerspective (glFovy, (GLfloat)width / (GLfloat)height,glZNear,glZFar); glMatrixMode (GL_MODELVIEW); } //マウスの動き void motion(int x, int y){ int xDisp, yDisp; xDisp = x - xBegin; yDisp = y - yBegin; switch (mButton) { case GLUT_LEFT_BUTTON: azimuth += (float) xDisp/2.0; elevation -= (float) yDisp/2.0; break; case GLUT_MIDDLE_BUTTON: cameraX -= (float) xDisp/40.0; cameraY += (float) yDisp/40.0; break; case GLUT_RIGHT_BUTTON: cameraDistance += (float) xDisp/40.0; break; } xBegin = x; yBegin = y; } //マウスの操作 void mouse(int button, int state, int x, int y){ if (state == GLUT_DOWN) { switch(button) { case GLUT_RIGHT_BUTTON: case GLUT_MIDDLE_BUTTON: case GLUT_LEFT_BUTTON: mButton = button; break; } xBegin = x; yBegin = y; } } //視点変更 void polarview(){ glTranslatef( cameraX, cameraY, cameraDistance); glRotatef( -twist, 0.0, 0.0, 1.0); glRotatef( -elevation, 1.0, 0.0, 0.0); glRotatef( -azimuth, 0.0, 1.0, 0.0); } //メイン int main(int argc, char *argv[]){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB); glutInitWindowSize(FormWidth, FormHeight); glutCreateWindow(argv[0]); //コールバック glutReshapeFunc (reshape); glutDisplayFunc(display); glutIdleFunc(idle); glutMouseFunc(mouse); glutMotionFunc(motion); init(); glutMainLoop(); context.Shutdown(); return 0; } //ポイントクラウド描画 void drawPointCloud(Mat &rgbImage,Mat &pointCloud_XYZ){ static int x,y; glPointSize(2); glBegin(GL_POINTS); uchar *p = rgbImage.data; Point3f *point = (Point3f*)pointCloud_XYZ.data; for(y = 0;y < KINECT_DEPTH_HEGIHT;y++){ for(x = 0;x < KINECT_DEPTH_WIDTH;x++,p += 3,point++){ if(point->z == 0) continue; glColor3ubv(p); glVertex3f(point->x,point->y,point->z); } } glEnd(); } //3次元ポイントクラウドのための座標変換 void retrievePointCloudMap(Mat &depth,Mat &pointCloud_XYZ){ static const int size = KINECT_DEPTH_HEGIHT * KINECT_DEPTH_WIDTH; static XnPoint3D proj[size] = {0}; static int x,y; XnPoint3D *p = proj; unsigned short* dp = (unsigned short*)depth.data; for(y = 0; y < KINECT_DEPTH_HEGIHT; y++ ){ for(x = 0; x < KINECT_DEPTH_WIDTH; x++, p++, dp++){ p->X = x; p->Y = y; p->Z = *dp * 0.001f; // from mm to meters } } //現実座標に変換 depthGenerator.ConvertProjectiveToRealWorld(size, proj, (XnPoint3D*)pointCloud_XYZ.data); } //人物の骨格を描画 void drawUserJoint(){ XnUserID aUsers[15]; XnUInt16 nUsers = 15; userGenerator.GetUsers(aUsers, nUsers); for (int i = 0; i < nUsers; ++i){ if (userGenerator.GetSkeletonCap().IsTracking(aUsers[i])){ //各関節に点を打つ glPointSize(5); glBegin(GL_POINTS); glColor4f(0,255,0, 1); for(int Joint = XN_SKEL_HEAD;Joint < XN_SKEL_RIGHT_FOOT + 1;Joint++) DrawJoint(aUsers[i],(XnSkeletonJoint)Joint); glEnd(); //各肢に線を書く glBegin(GL_LINES); glColor4f(255,0,0, 1); DrawLimb(aUsers[i], XN_SKEL_HEAD, XN_SKEL_NECK); DrawLimb(aUsers[i], XN_SKEL_NECK, XN_SKEL_LEFT_SHOULDER); DrawLimb(aUsers[i], XN_SKEL_LEFT_SHOULDER, XN_SKEL_LEFT_ELBOW); DrawLimb(aUsers[i], XN_SKEL_LEFT_ELBOW, XN_SKEL_LEFT_HAND); DrawLimb(aUsers[i], XN_SKEL_NECK, XN_SKEL_RIGHT_SHOULDER); DrawLimb(aUsers[i], XN_SKEL_RIGHT_SHOULDER, XN_SKEL_RIGHT_ELBOW); DrawLimb(aUsers[i], XN_SKEL_RIGHT_ELBOW, XN_SKEL_RIGHT_HAND); DrawLimb(aUsers[i], XN_SKEL_LEFT_SHOULDER, XN_SKEL_TORSO); DrawLimb(aUsers[i], XN_SKEL_RIGHT_SHOULDER, XN_SKEL_TORSO); DrawLimb(aUsers[i], XN_SKEL_TORSO, XN_SKEL_LEFT_HIP); DrawLimb(aUsers[i], XN_SKEL_LEFT_HIP, XN_SKEL_LEFT_KNEE); DrawLimb(aUsers[i], XN_SKEL_LEFT_KNEE, XN_SKEL_LEFT_FOOT); DrawLimb(aUsers[i], XN_SKEL_TORSO, XN_SKEL_RIGHT_HIP); DrawLimb(aUsers[i], XN_SKEL_RIGHT_HIP, XN_SKEL_RIGHT_KNEE); DrawLimb(aUsers[i], XN_SKEL_RIGHT_KNEE, XN_SKEL_RIGHT_FOOT); DrawLimb(aUsers[i], XN_SKEL_LEFT_HIP, XN_SKEL_RIGHT_HIP); glEnd(); } } } void DrawJoint(XnUserID player, XnSkeletonJoint eJoint){ XnSkeletonJointPosition joint; userGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint, joint); //信頼性の低い場合描画しない if (joint.fConfidence < 0.5) return; glVertex3f(joint.position.X* 0.001f, joint.position.Y* 0.001f, joint.position.Z* 0.001f); } void DrawLimb(XnUserID player, XnSkeletonJoint eJoint1, XnSkeletonJoint eJoint2){ XnSkeletonJointPosition joint1, joint2; userGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint1, joint1); userGenerator.GetSkeletonCap().GetSkeletonJointPosition(player, eJoint2, joint2); //信頼性の低い場合描画しない if (joint1.fConfidence < 0.5 || joint2.fConfidence < 0.5) return; glVertex3f(joint1.position.X* 0.001f, joint1.position.Y* 0.001f, joint1.position.Z* 0.001f); glVertex3f(joint2.position.X* 0.001f, joint2.position.Y* 0.001f, joint2.position.Z* 0.001f); } // ユーザー検出 void XN_CALLBACK_TYPE UserDetected( xn::UserGenerator& generator, XnUserID nId, void* pCookie ) { printf("ユーザID%d 検出 %d人目\n",nId,generator.GetNumberOfUsers()); generator.GetSkeletonCap().RequestCalibration(nId, TRUE); } // キャリブレーションの終了 void XN_CALLBACK_TYPE CalibrationEnd(xn::SkeletonCapability& capability, XnUserID nId, XnBool bSuccess, void* pCookie) { if ( bSuccess ) { printf("ユーザID%d キャリブレーション成功\n",nId); capability.StartTracking(nId); } else { printf("ユーザID%d キャリブレーション失敗\n",nId); } }