// 壁との当たり判定 bool Collision::CheckWall( iexMesh* org, const Vector3& pos, Vector3& p_move ) { //org->Update(); const float DIST = 2.0f; // 壁との距離 Vector3 p_pos = Vector3(pos.x, pos.y + 1.0f, pos.z); Vector3 vec = Vector3(p_move.x, 0.0f, p_move.z); vec.Normalize(); Vector3 takePos; float dist = 100.0f; // オブジェクトの逆行列を算出 if ( org->RayPick( &takePos, &p_pos, &vec, &dist ) != -1 ){ float disToWall = Vector3( Vector3( takePos.x, 0.0f, takePos.z ) - Vector3( p_pos.x, 0.0f, p_pos.z ) ).Length(); if ( disToWall <= DIST ) { // 移動量 float move = Vector3( p_move.x, 0.0f, p_move.z ).Length(); // プレイヤーからレイの交差点へのベクトル Vector3 vPtoWall( takePos - p_pos ); vPtoWall.y = 0.0f; vPtoWall.Normalize(); vec.y = 0.0f; vec.Normalize(); // 法線の上方向(?)を求める Vector3 vCrossUp; Vector3Cross( vCrossUp, vec, vPtoWall ); vCrossUp.Normalize(); // 法線の上方向(?)と法線の外積から滑る方向を計算 Vector3 vCrossSide; Vector3Cross( vCrossSide, vCrossUp, vec ); vCrossSide.Normalize(); // 法線とプレーヤーからレイの交差点へのベクトルの内積 float dotNP = Vector3Dot( vec, vPtoWall ); // 移動量の調整 p_move.x = vCrossSide.x * move * ( dotNP + 1.0f ); p_move.z = vCrossSide.z * move * ( dotNP + 1.0f ); return true; } } return false; }
// 線分と線分の距離の平方を返す(カプセル用) float Collision::DistanceSegmentSegmentSq( const Vector3& l1p1, const Vector3& l1p2, const Vector3& l2p1, const Vector3& l2p2 ) { // ねじれの位置の判定 Vector3 v1 = l1p2 - l1p1; Vector3 v2 = l2p2 - l2p1; Vector3 n; Vector3Cross( n, v1, v2 ); float nn = n.LengthSq(); if ( nn ) { // 平行ではない Vector3 v12 = l2p1 - l1p1; float nv12 = Vector3Dot( n, v12 ); Vector3 vd = n * ( nv12 / nn ); Vector3 q1 = l2p1 - vd; Vector3 q2 = l2p2 - vd; Vector3 p1q1 = q1 - l1p1; Vector3 p1q2 = q2 - l1p1; Vector3 r1, r2; Vector3Cross( r1, v1, p1q1 ); Vector3Cross( r2, v1, p1q2 ); if ( Vector3Dot( r1, r2 ) < 0 ) { Vector3 v3 = q2 - q1; Vector3 q1p1 = l1p1 - q1; Vector3 q1p2 = l1p2 - q1; Vector3Cross( r1, v3, q1p1 ); Vector3Cross( r2, v3, q1p2 ); if (Vector3Dot( r1, r2 ) < 0 ) { // ねじれの位置 return nv12 * nv12 / nn; } } } // ねじれじゃない位置 return min( min( DistancePointSegmentSq( l1p1, l2p1, l2p2 ), DistancePointSegmentSq( l1p2, l2p1, l2p2 ) ), min(DistancePointSegmentSq( l2p1, l1p1, l1p2 ), DistancePointSegmentSq( l2p2, l1p1, l1p2 ) ) ); }
// ハイパーアーツ bool Thief::HyperArts(void) { //空中で発動しても停止する move = Vector3(0, -GRAVITY, 0); if ( !initflag ) { sound->PlaySE( SE::HYPER_ATTACK ); sound->PlaySE( SE::KAITO_HYPER ); initflag = true; } attackInfo.power = OFFENSIVE_POWER::HYPER; attackInfo.dropPower = DROP_POWER::HYPER; attackInfo.coinDropType = DROP_TYPE::SUCTION; SetParameterState(PARAMETER_STATE::UNRIVALED); move = Vector3(0, 0 - GRAVITY, 0); //撃ってる間は静止させる SetMotion(THIEF::MOTION_DATA::HYPERARTS); // 行列から情報取得 Vector3 front = GetFront(); Vector3 right = GetRight(); Vector3 p_pos = GetPos(); SetMove(Vector3(0.0f, move.y, 0.0f)); if (obj->GetFrame() >= THIEF::MOTION_FRAME::HYPERARTS_ATTACKSTART/* && obj->GetFrame() < THIEF::MOTION_FRAME::HYPERARTS_ATTACKEND*/) { float t = GetBezier(ePrm_t::eRapid_Lv5, ePrm_t::eSlow_Lv1, attackInfo.t); Vector3 f = front * (2.0f * sinf(D3DX_PI * t)); Vector3 r = -right * (2.0f * cosf(D3DX_PI * t)); attackInfo.bottom = p_pos + f + r; switch (HyperStep) { case 0: // あたり判定のパラメータを与える attackInfo.top = attackInfo.bottom + r * HyperRate; attackInfo.r = 2.5f; HyperRate += 1.0; if (HyperRate > 20.0f) HyperStep++; break; case 1: // パラメータ加算 attackInfo.top = attackInfo.bottom + f * HyperRate + r * HyperRate; attackInfo.t += 0.03f; if (attackInfo.t >= 1.0f) { HyperStep++; } break; case 2: //attackInfo.top = attackInfo.bottom + r * rate; attackInfo.t = 0.0f; HyperRate -= 1.0f; break; } armRenderflag = true; } Vector3 v1, v2; v1 = front; v2 = attackInfo.top - attackInfo.bottom; v1.Normalize(); v2.Normalize(); float armAngle = GetAngle(v1, v2); Vector3 cross; Vector3Cross(cross, v1, v2); if (cross.y < 0) armAngle = -armAngle; arm->SetPos(pos); arm->SetAngle(angle.y + armAngle); arm->SetScale(Vector3(0.03f, 0.03f, HyperRate * 0.01f)); arm->Update(); if (HyperRate < 0) { HyperStep = 0; HyperRate = 0; armRenderflag = false; initflag = false; return true; } return false; }
// 追加した関数 void iexMesh::NearestPoint( NearestPointOut *out, const Vector3 &inPos ) { // 情報取得 u32 fvf = lpMesh->GetFVF(); // 頂点サイズ計算 int vertexSize = D3DXGetFVFVertexSize( fvf ) / sizeof( float ); // バッファロック float *pVertices; u16 *pIndices; u32 numIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY, ( void** ) &pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY, ( void** ) &pIndices ); struct { Vector3 vertex[3]; Vector3 normal; Vector3 line[3]; // 頂点情報から残りの情報を計算 inline void ComputeFromVertex() { line[1] = vertex[2] - vertex[1]; line[2] = vertex[3] - vertex[2]; line[3] = vertex[1] - vertex[3]; Vector3Cross( normal, line[1], line[2] ); normal.Normalize(); } }triangle; // 三角ポリゴン out->length = FLT_MAX; for( u32 j = 0; j < numIndices; j++ ) { // 面頂点取得 { int index = pIndices[j * 3 + 0] * vertexSize; triangle.vertex[1].x = pVertices[index]; triangle.vertex[1].y = pVertices[index + 1]; triangle.vertex[1].z = pVertices[index + 2]; index = pIndices[j * 3 + 1] * vertexSize; triangle.vertex[2].x = pVertices[index]; triangle.vertex[2].y = pVertices[index + 1]; triangle.vertex[2].z = pVertices[index + 2]; index = pIndices[j * 3 + 2] * vertexSize; triangle.vertex[3].x = pVertices[index]; triangle.vertex[3].y = pVertices[index + 1]; triangle.vertex[3].z = pVertices[index + 2]; } // 法線と辺計算 triangle.ComputeFromVertex(); // 法線方向に距離計算 FLOAT lengthNormal( 0 ); lengthNormal = Vector3Dot( ( inPos - triangle.vertex[1] ), triangle.normal ); // ポリゴンが裏向き if( lengthNormal <= 0 ) continue; // 遠い if( lengthNormal > out->length ) continue; Vector3 nearestPos( 0, 0, 0 ); // とりあえず無限平面上で nearestPos = inPos - ( triangle.normal * lengthNormal ); Vector3 decisionVector( 0, 0, 0 ); // 内点判定 for( unsigned int i = 0; i < 3; i++ ) { Vector3Cross( decisionVector, ( triangle.vertex[i] - nearestPos ), triangle.line[i] ); // 外にあった場合 if( Vector3Dot( decisionVector, triangle.normal ) < 0 ) { // nearestPosを辺上の最接近点へ移動 float t = triangle.line[i].LengthSq(); if( t != 0 ) // 辺上へ t = Vector3Dot( ( nearestPos - triangle.vertex[i] ), triangle.line[i] ) / t; // 頂点へ if( t < 0 ) t = 0; else if( t > 1 )t = 1; // 移動 nearestPos = triangle.vertex[i] + triangle.line[i] * t; } } // 距離判定 float length = ( nearestPos - inPos ).Length(); if( length > out->length ) continue; out->length = length; out->Normal = triangle.normal; out->Pos = nearestPos; } // バッファアンロック lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); }
//------------------------------------------------------ // 上下最適化 //------------------------------------------------------ int iexMesh::RayPickUD( Vector3* out, Vector3* pos, Vector3* vec, float *Dist ) { float t, neart; float vy; int ret = -1; int VertexSize; Vector3 p = *pos; vy = vec->y; neart = *Dist; // 情報取得 int fvf = lpMesh->GetFVF(); // 頂点サイズ計算 VertexSize = D3DXGetFVFVertexSize(fvf) / sizeof(float); // バッファロック float *pVertices; u16 *pIndices; int NumIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY , (void**)&pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY , (void**)&pIndices ); Vector l1, l2, l3; Vector p1, p2, p3; Vector v[3]; Vector n; for( int j=0 ; j<NumIndices ; j++ ) { // 面頂点取得 int a = pIndices[j*3+0] * VertexSize; int b = pIndices[j*3+1] * VertexSize; int c = pIndices[j*3+2] * VertexSize; v[0].x = pVertices[a]; v[1].x = pVertices[b]; v[2].x = pVertices[c]; if( v[0].x > p.x && v[1].x > p.x && v[2].x > p.x ) continue; v[0].z = pVertices[a+2]; v[1].z = pVertices[b+2]; v[2].z = pVertices[c+2]; if( v[0].z > p.z && v[1].z > p.z && v[2].z > p.z ) continue; v[0].y = pVertices[a+1]; v[1].y = pVertices[b+1]; v[2].y = pVertices[c+1]; // 内点判定(全外積がマイナス) l1.x = v[1].x - v[0].x; l1.z = v[1].z - v[0].z; p1.x = v[0].x - p.x; p1.z = v[0].z - p.z; if( (p1.x*l1.z - p1.z*l1.x)*vy < 0 ) continue; l2.x = v[2].x - v[1].x; l2.z = v[2].z - v[1].z; p2.x = v[1].x - p.x; p2.z = v[1].z - p.z; if( (p2.x*l2.z - p2.z*l2.x)*vy < 0 ) continue; l3.x = v[0].x - v[2].x; l3.z = v[0].z - v[2].z; p3.x = v[2].x - p.x; p3.z = v[2].z - p.z; if( (p3.x*l3.z - p3.z*l3.x)*vy < 0 ) continue; // 外積による法線算出 l1.y = v[1].y - v[0].y; l2.y = v[2].y - v[1].y; Vector3Cross( n, l1, l2 ); // 表裏判定 if( vy*n.y >= 0 ) continue; // 交点算出 p1.y = v[0].y - p.y; t = Vector3Dot( n, p1 ) / (n.y*vy); if( t < .0f || t > neart ) continue; *vec = n; ret = j; neart = t; } lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); out->y = neart*vy + p.y; out->x = pos->x; out->z = pos->z; *Dist = neart; return ret; }
//************************************************************************************************** // // レイピック // //************************************************************************************************** //------------------------------------------------------ // レイピック //------------------------------------------------------ int iexMesh::RayPick( Vector3* out, Vector3* pos, Vector3* vec, float *Dist ) { int ret = -1; if( vec->x == .0f && vec->z == .0f ) return RayPickUD( out, pos, vec, Dist ); Vector3 p = *pos; Vector3 vv = *vec; float neart = *Dist; float dist = *Dist; dist = dist*dist; *out = p; // 情報取得 u32 fvf = lpMesh->GetFVF(); // 頂点サイズ計算 int VertexSize = D3DXGetFVFVertexSize(fvf) / sizeof(float); // バッファロック float *pVertices; u16 *pIndices; u32 NumIndices = lpMesh->GetNumFaces(); lpMesh->LockVertexBuffer( D3DLOCK_READONLY, (void**)&pVertices ); lpMesh->LockIndexBuffer( D3DLOCK_READONLY, (void**)&pIndices ); Vector3 v1, v2, v3; Vector3 n; Vector3 l1, l2, l3; Vector3 temp; Vector3 cp; Vector3 p1, p2, p3; for( u32 j=0 ; j<NumIndices ; j++ ) { // 面頂点取得 int a = pIndices[j*3+0] * VertexSize; v1.x = pVertices[a]; v1.y = pVertices[a+1]; v1.z = pVertices[a+2]; int b = pIndices[j*3+1] * VertexSize; v2.x = pVertices[b]; v2.y = pVertices[b+1]; v2.z = pVertices[b+2]; int c = pIndices[j*3+2] * VertexSize; v3.x = pVertices[c]; v3.y = pVertices[c+1]; v3.z = pVertices[c+2]; // 距離判定 //Vector3 ss = (v1 + v2 + v3) / 3.0f - p; //if( ss.LengthSq() > dist ) continue; l1.x = v2.x - v1.x; l1.y = v2.y - v1.y; l1.z = v2.z - v1.z; l2.x = v3.x - v2.x; l2.y = v3.y - v2.y; l2.z = v3.z - v2.z; // 外積による法線算出 Vector3Cross( n, l1, l2 ); // 内積の結果がプラスならば裏向き float dot = Vector3Dot( vv, n ); if( dot >= 0 ) continue; // 交点算出 p1.x = v1.x - p.x; p1.y = v1.y - p.y; p1.z = v1.z - p.z; float t = Vector3Dot( n, p1 ) / dot; if( t < .0f || t > neart ) continue; cp.x = vv.x*t + p.x; cp.y = vv.y*t + p.y; cp.z = vv.z*t + p.z; // 内点判定 p1.x = v1.x - cp.x; p1.y = v1.y - cp.y; p1.z = v1.z - cp.z; Vector3Cross( temp, p1, l1 ); if( Vector3Dot(temp, n) < .0f ) continue; p2.x = v2.x - cp.x; p2.y = v2.y - cp.y; p2.z = v2.z - cp.z; Vector3Cross( temp, p2, l2 ); if( Vector3Dot(temp, n) < .0f ) continue; l3.x = v1.x - v3.x; l3.y = v1.y - v3.y; l3.z = v1.z - v3.z; p3.x = v3.x - cp.x; p3.y = v3.y - cp.y; p3.z = v3.z - cp.z; Vector3Cross( temp, p3, l3 ); if( Vector3Dot(temp, n) < .0f ) continue; *out = cp; *vec = n; ret = j; neart = t; } lpMesh->UnlockVertexBuffer(); lpMesh->UnlockIndexBuffer(); *Dist = neart; return ret; }