// Wall2D의 노말벡터가 블럭의 바깥을 바라보게 한다 void CBlock::CalculateNormal() { // 중점을 구한다 Vector2D center(0,0); list<Wall2D*>::iterator itor = m_WallList.begin(); while (itor != m_WallList.end()) { center += (*itor)->From(); ++itor; } center /= (float)m_WallList.size(); // 중점과 노말벡터가 마주본다면 반전시킨다 itor = m_WallList.begin(); while (itor != m_WallList.end()) { Vector2D line = (*itor)->From() + (*itor)->To(); line /= 2.f; const Vector2D centerToLine = line - center; const double dot = centerToLine.Dot((*itor)->Normal()); if (dot <= 0.f) { Vector2D to = (*itor)->To(); (*itor)->SetTo((*itor)->From()); (*itor)->SetFrom(to); } ++itor; } }
//------------------------------ Pursuit --------------------------------- // // this behavior creates a force that steers the agent towards the // evader //------------------------------------------------------------------------ Vector2D SteeringBehavior::Pursuit(const Vehicle* evader) { //if the evader is ahead and facing the agent then we can just seek //for the evader's current position. Vector2D ToEvader = evader->Pos() - m_pVehicle->Pos(); double RelativeHeading = m_pVehicle->Heading().Dot(evader->Heading()); if ((ToEvader.Dot(m_pVehicle->Heading()) > 0) && (RelativeHeading < -0.95)) //acos(0.95)=18 degs { return Seek(evader->Pos()); } //Not considered ahead so we predict where the evader will be. //the lookahead time is propotional to the distance between the evader //and the pursuer; and is inversely proportional to the sum of the //agent's velocities double LookAheadTime = ToEvader.Length() / (m_pVehicle->MaxSpeed() + evader->Speed()); //now seek to the predicted future position of the evader return Seek(evader->Pos() + evader->Velocity() * LookAheadTime); }
Vector2D Vector2D::Reflect(const Vector2D & v, const Vector2D &a) { Vector2D n = Normal(a); float co = -2 * ((float)v.Dot(n) / (n.Magnitude() * n.Magnitude())); Vector2D r = {}; r.x = v.x + co * n.x; r.y = r.y + co * n.y; return r; }
//------------------------- WithinFieldOfView --------------------------- // // returns true if subject is within field of view of this player //----------------------------------------------------------------------- bool PlayerBase::PositionInFrontOfPlayer(Vector2D position)const { Vector2D ToSubject = position - Pos(); if (ToSubject.Dot(Heading()) > 0) return true; else return false; }
Vector2D B020612E_Steering::PointToLocalSpace(const Vector2D &point, Vector2D &AgentHeading, Vector2D &AgentSide, Vector2D &AgentPosition) { //make a copy of the point Vector2D TransPoint = point; //create a transformation matrix C2DMatrix matTransform; double Tx = -AgentPosition.Dot(AgentHeading); double Ty = -AgentPosition.Dot(AgentSide); //create the transformation matrix matTransform._11(AgentHeading.x); matTransform._12(AgentSide.x); matTransform._21(AgentHeading.y); matTransform._22(AgentSide.y); matTransform._31(Tx); matTransform._32(Ty); //now transform the vertices matTransform.TransformVector2Ds(TransPoint); return TransPoint; }
Vector2D B020612E_Steering::Pursuit(Vector2D target, Vector2D velocity) { Vector2D targetPos = _pTank->mTargetPosition; double relative = _pTank->GetHeading().Dot(_pTank->mEnHeading); if ((targetPos.Dot(_pTank->GetHeading()) > 0) && (relative < -0.95)) return Seek(targetPos); else { double lookAheadTime = targetPos.Length() / (_pTank->GetMaxSpeed() + _pTank->mEnSpeed); return Seek(targetPos + _pTank->mEnVel * lookAheadTime); } }
void DumbTank::Update(float deltaTime, SDL_Event e) { //This is a dumb tank. Do NOT copy this approach. //Did we see a tank? if(mTanksICanSee.size() == 0) { ChangeState(TANKSTATE_IDLE); //If there are no visible tanks, then keep moving. //Check if we reached position before turning. if(mPosition.y < mPosition1.y && mHeading.y != -1.0f) { mHeading = Vector2D(0.0f, -1.0f); mRotationAngle = 180.0f; mVelocity = Vector2D(); return; } else if(mPosition.y > mPosition2.y && mHeading.y != 1.0f) { mHeading = Vector2D(0.0f, 1.0f); mRotationAngle = 0.0f; mVelocity = Vector2D(); return; } else { //Move if we are facing the correct direction. mCurrentSpeed -= kSpeedIncrement*deltaTime; if(mCurrentSpeed < -GetMaxSpeed()) mCurrentSpeed = -GetMaxSpeed(); } } else { //Rotate man to face enemy tank. Vector2D toTarget = mTanksICanSee[0]->GetCentralPosition()-GetCentralPosition(); toTarget.Normalize(); double dot = toTarget.Dot(mManFireDirection); if(dot < 0.95f) RotateManByRadian(kManTurnRate, -1, deltaTime); //Otherwise stop moving and fire at the visible tank. mVelocity = Vector2D(); ChangeState(TANKSTATE_MANFIRE); } BaseTank::Update(deltaTime, e); }
double YawStrafeMaxAngle(PlayerData& player, const MovementVars& vars, bool onground, double wishspeed, const StrafeButtons& strafeButtons, bool useGivenButtons, Button& usedButton, double vel_yaw, double yaw) { bool safeguard_yaw; double theta = MaxAngleTheta(player, vars, onground, wishspeed, safeguard_yaw); if (!player.Velocity.AsVector2D().IsZero(0.0f)) vel_yaw = Atan2(player.Velocity[1], player.Velocity[0]); Vector2D newvel; double resulting_yaw; SideStrafeGeneral(player, vars, onground, wishspeed, strafeButtons, useGivenButtons, usedButton, vel_yaw, theta, (NormalizeRad(yaw - vel_yaw) < 0), newvel, resulting_yaw); if (safeguard_yaw) { Vector2D test_vel1, test_vel2; double test_yaw1, test_yaw2; SideStrafeGeneral(player, vars, onground, wishspeed, strafeButtons, useGivenButtons, usedButton, vel_yaw, min(theta - SAFEGUARD_THETA_DIFFERENCE_RAD, 0.0), (NormalizeRad(yaw - vel_yaw) < 0), test_vel1, test_yaw1); SideStrafeGeneral(player, vars, onground, wishspeed, strafeButtons, useGivenButtons, usedButton, vel_yaw, std::max(theta + SAFEGUARD_THETA_DIFFERENCE_RAD, 0.0), (NormalizeRad(yaw - vel_yaw) < 0), test_vel2, test_yaw2); double cos_test1 = test_vel1.Dot(player.Velocity.AsVector2D()) / (player.Velocity.Length2D() * test_vel1.Length()); double cos_test2 = test_vel2.Dot(player.Velocity.AsVector2D()) / (player.Velocity.Length2D() * test_vel2.Length()); double cos_newvel = newvel.Dot(player.Velocity.AsVector2D()) / (player.Velocity.Length2D() * newvel.Length()); //DevMsg("cos_newvel = %.8f; cos_test1 = %.8f; cos_test2 = %.8f\n", cos_newvel, cos_test1, cos_test2); if (cos_test1 < cos_newvel) { if (cos_test2 < cos_test1) { newvel = test_vel2; resulting_yaw = test_yaw2; cos_newvel = cos_test2; } else { newvel = test_vel1; resulting_yaw = test_yaw1; cos_newvel = cos_test1; } } else if (cos_test2 < cos_newvel) { newvel = test_vel2; resulting_yaw = test_yaw2; cos_newvel = cos_test2; } } else { //DevMsg("theta = %.08f, yaw = %.08f, vel_yaw = %.08f, speed = %.08f\n", theta, yaw, vel_yaw, player.Velocity.Length2D()); } player.Velocity.AsVector2D() = newvel; return resulting_yaw; }
Vector2D S013010C_Aaron_Smith_Steering::Pursuing() { Vector2D enemyTankPos = mTank->GetTarget(); double relativeHeading = mTank->GetHeading().Dot(mTank->GetEnemyHeading()); if (enemyTankPos.Dot(mTank->GetHeading()) > 0 && (relativeHeading < -0.95)) return Seek(enemyTankPos); else { //not ahead of player so need to predict enemy position double lookAheadTime = enemyTankPos.Length() / (mTank->GetMaxSpeed() + mTank->GetEnemySpeed()); return Seek(enemyTankPos + mTank->GetEnemyVelocity() * lookAheadTime); } }
float CAI_PlaneSolver::AdjustRegulationWeight( CBaseEntity *pEntity, float weight ) { if ( pEntity->MyNPCPointer() != NULL ) { // @TODO (toml 10-03-02): How to do this with non-NPC entities. Should be using intended solve velocity... Vector2D velOwner = GetNpc()->GetMotor()->GetCurVel().AsVector2D(); Vector2D velBlocker = ((CAI_BaseNPC *)pEntity)->GetMotor()->GetCurVel().AsVector2D(); Vector2D velOwnerNorm = velOwner; Vector2D velBlockerNorm = velBlocker; float speedOwner = Vector2DNormalize( velOwnerNorm ); float speedBlocker = Vector2DNormalize( velBlockerNorm ); float dot = velOwnerNorm.Dot( velBlockerNorm ); if ( speedBlocker > 0 ) { if ( dot > 0 && speedBlocker >= speedOwner * 0.9 ) { if ( dot > 0.86 ) { // @Note (toml 10-10-02): Even in the case of no obstacle, we generate // a suggestion in because we still want to continue sweeping the // search weight = 0; } else if ( dot > 0.7 ) { weight *= sq( weight ); } else weight *= weight; } } } return weight; }
int HitOutline::Raycast(Point2D p, Vector2D v, Scalar maxTime, Hit* hitArr, int hitArrSize, Scalar sense) { //local data: Bart Hit localHitArr[100]; int localHitArrSize=100; int hitCount = 0; // TODO: Currently very slow, brute force! int lineVertexCount = m_Lines.size(); int quadVertexCount = m_Quads.size(); Scalar epsilon = 1e-6; Point2D p1 = p; Point2D p2 = p+v; Point2D orig(0,0); Scalar vDv = v.Dot(v); Vector2D n = v.Orthogonal(); // Line-line intersections. if( lineVertexCount > 0 ) { Point2D* lines = &m_Lines[0]; for( int i=0; i<lineVertexCount && hitCount<localHitArrSize; i += 2 ) { Point2D q1 = lines[i+0]; Point2D q2 = lines[i+1]; Vector2D ortho = (q2-q1).Orthogonal(); if( (dot(ortho, v) * sense < 0) || sense==0) { Scalar time1; Scalar time2; if( IntersectLines(p1, p2, q1, q2, time1, time2) ) { if( time1 >= 0 && time1 < maxTime && time2 >= 0 && time2 <= 1 ) { Hit hit; hit.Time = time1; hit.Point = p + time1 * v; hit.Normal = ortho.Normalized(); localHitArr[hitCount++] = hit; } } } } } // Line-quadratic intersections. if( quadVertexCount > 0 ) { Point2D* quads = &m_Quads[0]; for( int i=0; i<quadVertexCount && hitCount<localHitArrSize; i += 3 ) { Vector2D q0 = quads[i+0] - p; Vector2D q1 = quads[i+1] - p; Vector2D q2 = quads[i+2] - p; // Hit only possible if: // (1) not all points are on same side of ray, // // (2) and some points are in front of ray (currently not checked, handled by abc formula) Scalar dot_n_q0 = dot(n,q0); Scalar dot_n_q1 = dot(n,q1); Scalar dot_n_q2 = dot(n,q2); if( dot_n_q0 <= 0 && dot_n_q1 <= 0 && dot_n_q2 <= 0 ) continue; if( dot_n_q0 >= 0 && dot_n_q1 >= 0 && dot_n_q2 >= 0 ) continue; Scalar ts[2]; Scalar a = 2*dot_n_q1-dot_n_q0-dot_n_q2; Scalar b = 2*dot_n_q0-2*dot_n_q1; Scalar c = -dot_n_q0; int n = solveQuadratic(a,b,c,ts); for( int j=0; j<n && hitCount < localHitArrSize; ++j ) { Scalar t = ts[j]; if( t >= 0 && t <= 1 ) { Vector2D diff = (2*(q2-q1)+2*(q0-q1))*t+2*(q1-q0); Vector2D ortho = diff.Orthogonal(); if( (dot(ortho, v) * sense < 0) || sense==0) { Vector2D h = lerp( lerp(q0,q1,t), lerp(q1,q2,t), t); Scalar time = h.Dot(v) / vDv; //time >= -maxTime if( time >= 0 && time < maxTime ) { Hit hit; hit.Point = p+h; hit.Time = time; hit.Normal = ortho.Normalized(); localHitArr[hitCount++] = hit; } } } } } } std::sort(localHitArr, localHitArr+hitCount, sortHitOnTime); //Bart for( int i=0; i<hitCount && i < hitArrSize; ++i ) { hitArr[i]=localHitArr[i]; } return hitCount; }