void WBCompEldAnchor::SetAnchor() { EldritchWorld* const pWorld = GetWorld(); ASSERT( pWorld ); WBEntity* const pEntity = GetEntity(); DEVASSERT( pEntity ); WBCompEldTransform* const pTransform = pEntity->GetTransformComponent<WBCompEldTransform>(); DEVASSERT( pTransform ); const Angles Orientation = pTransform->GetOrientation(); const Matrix RotationMatrix = Orientation.ToMatrix(); const Vector AnchorVector = m_AnchorDirection * RotationMatrix; const Vector StartLocation = pTransform->GetLocation(); const Ray TraceRay = Ray( StartLocation, AnchorVector ); CollisionInfo Info; Info.m_CollideWorld = true; Info.m_CollideEntities = true; Info.m_CollidingEntity = pEntity; Info.m_UserFlags = EECF_CollideAsEntity | EECF_CollideStaticEntities; if( pWorld->Trace( TraceRay, Info ) ) { m_AnchorPoint = Info.m_Intersection + AnchorVector * 0.1f; ASSERT( pWorld->PointCheck( m_AnchorPoint, Info ) ); // Since hard-coded 0.1 might break for thin surfaces. m_IsAnchored = true; } }
/*virtual*/ void WBCompEldMesh::Tick(float DeltaTime) { XTRACE_FUNCTION; UpdateMesh(DeltaTime); // Add pseudo root motion. Hack from Couriers. if (m_Mesh && m_Mesh->IsAnimated()) { Vector AnimationVelocity; Angles AnimationRotationalVelocity; GetAnimationVelocity(AnimationVelocity, AnimationRotationalVelocity); if (AnimationVelocity.LengthSquared() > 0.0f || !AnimationRotationalVelocity.IsZero()) { WBCompEldTransform* pTransform = GetEntity()->GetTransformComponent<WBCompEldTransform>(); DEVASSERT(pTransform); // Kill velocity in direction of movement. if (AnimationVelocity.LengthSquared() > 0.0f) { Plane MovementPlane(AnimationVelocity.GetNormalized(), 0.0f); pTransform->SetVelocity( MovementPlane.ProjectVector(pTransform->GetVelocity())); } pTransform->ApplyImpulse(AnimationVelocity); pTransform->ApplyRotationalImpulse(AnimationRotationalVelocity); } } }
float PolarDiagram::getGybeAngle(const float & speed){ if(!contains(speed)){ if(debug) qDebug() << Q_FUNC_INFO << QString("(%1): speed not found").arg(QString::number(speed)); int i = 0; // List of all the speeds available in the diagram // given in ASC order QList<float> speeds = diagram.keys(); while(speeds[i] < speed && i < speeds.size() - 1) ++i; float maxang; // input speed is bigger than any available if(i == speeds.size() - 1) maxang = getGybeAngle(speeds.last()); // input speed is smaller than any available else if (i == 0) maxang = getGybeAngle(speeds.first()); // input speed is between other available speeds else maxang = (getGybeAngle(speeds[i-1]) + getGybeAngle(speeds[i])) / 2; return maxang; } // input speed is contained in our diagram Angles aux = getAngles(speed); // List of available angles for this speed // List is in ASC order QList<float> angles = aux.keys(); float maxta = 0, maxang = 0, ta, ang; bool on_gybe = true; for(int i = angles.size() - 1; on_gybe && i >= 0; --i){ ang = angles[i]; ta = aux.value(ang); if(ang < MIN_ANGLE_CONSIDERED_GYBE) on_gybe = false; else if(ta > maxta){ maxta = ta; maxang = ang; } } if(debug) qDebug() << Q_FUNC_INFO << QString("(%1): %2").arg(QString::number(speed), QString::number(maxang)); return maxang; }
void PolarDiagram::addLine( const float &speed, const float &angle, const float &TA){ if(debug) qDebug() << Q_FUNC_INFO; Angles aux; aux.insert(angle, TA); // setAngles() will take care if the speed already exists setAngles(speed, aux); }
void PolarDiagram::setAngles(const float &speed, const Angles &angles){ if(debug) qDebug() << Q_FUNC_INFO; if(contains(speed)){ Angles merge = angles; Angles aux = getAngles(speed); Angles::const_iterator i = aux.constBegin(); while(i != aux.constEnd()){ merge.insert(i.key(), i.value()); ++i; } diagram.insert(speed, merge); } else diagram.insert( speed, angles); }
void WBActionEldRemoveBlock::TraceFromSourceEntity( WBEntity* const pSourceEntity ) const { if( !pSourceEntity ) { return; } WBCompEldTransform* const pTransform = pSourceEntity->GetTransformComponent<WBCompEldTransform>(); if( !pTransform ) { return; } // TODO: If I reuse this stuff a lot in weapons and powers, wrap it up. WBCompEldCamera* const pCamera = GET_WBCOMP( pSourceEntity, EldCamera ); EldritchWorld* const pWorld = EldritchFramework::GetInstance()->GetWorld(); ASSERT( pWorld ); Vector EyeLoc = pTransform->GetLocation(); Angles EyeRot = pTransform->GetOrientation(); if( pCamera ) { EyeLoc += pCamera->GetViewTranslationOffset( WBCompEldCamera::EVM_All ); EyeRot += pCamera->GetViewOrientationOffset( WBCompEldCamera::EVM_All ); } const Vector EyeDir = EyeRot.ToVector(); const Ray TraceRay( EyeLoc, EyeDir ); CollisionInfo Info; Info.m_CollideWorld = true; Info.m_CollideEntities = true; Info.m_CollidingEntity = pSourceEntity; Info.m_UserFlags = EECF_Trace; if( pWorld->Trace( TraceRay, Info ) ) { const Vector HitLoc = Info.m_Intersection - Info.m_Plane.m_Normal * 0.1f; pWorld->RemoveVoxelAt( HitLoc ); } }
void EldritchFramework::CreateMinimapView() { PRINTF("EldritchFramework::CreateMinimapView\n"); SafeDelete(m_MinimapView); STATICHASH(EldMinimap); STATICHASH(MinimapRTWidth); const float fMinimapRTWidth = ConfigManager::GetFloat(sMinimapRTWidth, 0.0f, sEldMinimap); STATICHASH(MinimapRTHeight); const float fMinimapRTHeight = ConfigManager::GetFloat(sMinimapRTHeight, 0.0f, sEldMinimap); STATICHASH(MinimapViewDistance); const float ViewDistance = ConfigManager::GetFloat(sMinimapViewDistance, 0.0f, sEldMinimap); STATICHASH(MinimapViewPitch); const float ViewPitch = DEGREES_TO_RADIANS( ConfigManager::GetFloat(sMinimapViewPitch, 0.0f, sEldMinimap)); STATICHASH(MinimapViewFOV); const float FOV = ConfigManager::GetFloat(sMinimapViewFOV, 0.0f, sEldMinimap); STATICHASH(MinimapViewNearClip); const float NearClip = ConfigManager::GetFloat(sMinimapViewNearClip, 0.0f, sEldMinimap); STATICHASH(MinimapViewFarClip); const float FarClip = ConfigManager::GetFloat(sMinimapViewFarClip, 0.0f, sEldMinimap); const Angles EyeOrientation = Angles(ViewPitch, 0.0f, 0.0f); const Vector EyeDirection = EyeOrientation.ToVector(); const Vector EyePosition = -EyeDirection * ViewDistance; const float AspectRatio = fMinimapRTWidth / fMinimapRTHeight; m_MinimapView = new View(EyePosition, EyeOrientation, FOV, AspectRatio, NearClip, FarClip); }
UP_ERROR PolarDiagram::check(){ if(debug) qDebug() << Q_FUNC_INFO; if(name.isEmpty()) return ERROR_PD_NAME; if(diagram.size() == 0) return ERROR_PD_SIZE; QList<float> speeds = diagram.keys(); for(int i = 0; i < speeds.size(); i++){ // for each speed we check the list of angles-ta // very simple not in deep check of the diagram Angles aux = getAngles(speeds[i]); QList<float> angles = aux.keys(); bool a_gybe_angle = false; bool a_beat_angle = false; float ang, ta; for(int j = 0; j < angles.size(); j++){ ang = angles[j]; ta = aux.value(ang); if(ang < MAX_ANGLE_CONSIDERED_BEAT) a_beat_angle = true; else if(ang > MIN_ANGLE_CONSIDERED_GYBE) a_gybe_angle = true; // just check if TA is a reasonable value if(ta < MIN_TA_ALLOWED || ta > MAX_TA_ALLOWED) return ERROR_PD_TA; } // at least one beat angle and one gybe angle // is required in each list of angles-ta if(!a_beat_angle || !a_gybe_angle) return ERROR_PD_ANG; } return ERROR_NONE; }
bool WBCompEldMesh::UpdateMeshTransform() { ASSERT(m_Mesh); WBCompEldTransform* pTransform = GetEntity()->GetTransformComponent<WBCompEldTransform>(); DEVASSERT(pTransform); // Makes no sense to have a mesh and no transform const Vector EntityLocation = pTransform->GetLocation(); const Vector CurrentLocation = EntityLocation + m_Offset; m_Mesh->m_Location = CurrentLocation; const Angles EntityOrientation = pTransform->GetOrientation(); m_Mesh->m_Rotation = EntityOrientation; // Optimization, avoid the matrix and AABB calcs if nothing has changed if (m_OldTransform_Location != m_Mesh->m_Location || m_OldTransform_Rotation != m_Mesh->m_Rotation || m_OldTransform_Scale != m_Mesh->m_Scale || m_ForceUpdateTransform) { m_OldTransform_Location = m_Mesh->m_Location; m_OldTransform_Rotation = m_Mesh->m_Rotation; m_OldTransform_Scale = m_Mesh->m_Scale; m_ForceUpdateTransform = false; // Seems like maybe this AABB stuff should be done routinely in the Mesh. :/ const Matrix ScaleMatrix = Matrix::CreateScale(m_Mesh->m_Scale); const Matrix RotationMatrix = EntityOrientation.ToMatrix(); const Matrix TranslationMatrix = Matrix::CreateTranslation(CurrentLocation); const Matrix AABBTransform = ScaleMatrix * RotationMatrix * TranslationMatrix; m_Mesh->m_AABB = m_MeshOriginalAABB.GetTransformedBound(AABBTransform); return true; } else { return false; } }
float PolarDiagram::getTA(const float & speed, const float & angle){ if(!contains(speed)){ int i = 0; // List of ALL the speeds avilable in de diagram // given in ASC order QList<float> speeds = diagram.keys(); while(speeds.at(i) < speed && i < speeds.size() - 1) ++i; float ta; // input speed is bigger than any available if(i == speeds.size() - 1) ta = getTA(speeds.last(), angle); // input speed is smaller than any available else if(i == 0) ta = getTA(speeds.first(), angle); // input speed is between other available speeds else ta = (getTA(speeds.at(i - 1), angle) + getTA(speeds.at(i), angle)) / 2; return ta; } // input speed is contained in our diagram Angles aux = getAngles(speed); // List of available angles for this speed // List is in ASC order QList<float> angles = aux.keys(); int i = 0; while(angles.at(i) < angle && i < angles.size() - 1) ++i; // input angle is bigger than any available if(i == angles.size() - 1) return aux.value(angles.last()); // input angle is smaller than any available else if(i == 0) return aux.value(angles.first()); // input angle is between other available angles else return (aux.value(angles.at(i - 1)) + aux.value(angles.at(i))) / 2; }
/*virtual*/ void WBActionEldCheckLine::Execute() { WBAction::Execute(); STATIC_HASHED_STRING( EventOwner ); WBEntity* const pEntity = GetEntity(); WBEntity* const pOwnerEntity = GetOwner(); EldritchWorld* const pWorld = EldritchFramework::GetInstance()->GetWorld(); WBEventManager* const pEventManager = WBWorld::GetInstance()->GetEventManager(); Vector LineStart; Angles LineOrientation; GetLineTransform( LineStart, LineOrientation ); const Vector LineDirection = LineOrientation.ToVector(); CollisionInfo Info; Info.m_CollideWorld = true; Info.m_CollideEntities = true; Info.m_CollidingEntity = pOwnerEntity; Info.m_UserFlags = EECF_Trace; if( m_LineLength > 0.0f ) { const Vector LineEnd = LineStart + LineDirection * m_LineLength; const Segment TraceSegment = Segment( LineStart, LineEnd ); if( !pWorld->Trace( TraceSegment, Info ) ) { return; } } else { const Ray TraceRay = Ray( LineStart, LineDirection ); if( !pWorld->Trace( TraceRay, Info ) ) { return; } } const Vector HitLocation = Info.m_Intersection; const Vector HitNormal = Info.m_Plane.m_Normal; // Notify this entity that the line check hit that entity. if( Info.m_HitEntity ) { WB_MAKE_EVENT( OnLineCheck, pEntity ); WB_SET_AUTO( OnLineCheck, Hash, CheckTag, m_CheckTag ); WB_SET_AUTO( OnLineCheck, Entity, Checked, static_cast<WBEntity*>( Info.m_HitEntity ) ); WB_SET_AUTO( OnLineCheck, Vector, LineDirection, LineDirection ); WB_SET_AUTO( OnLineCheck, Vector, HitLocation, HitLocation ); WB_SET_AUTO( OnLineCheck, Vector, HitNormal, HitNormal ); WB_DISPATCH_EVENT( pEventManager, OnLineCheck, pEntity ); } else { const Vector HalfHitNormal = 0.5f * Info.m_Plane.m_Normal; const Vector HitVoxel = pWorld->GetVoxelCenter( HitLocation - HalfHitNormal ); WB_MAKE_EVENT( OnLineCheckMissed, pEntity ); WB_SET_AUTO( OnLineCheckMissed, Hash, CheckTag, m_CheckTag ); WB_SET_AUTO( OnLineCheckMissed, Vector, LineDirection, LineDirection ); WB_SET_AUTO( OnLineCheckMissed, Vector, HitLocation, HitLocation ); WB_SET_AUTO( OnLineCheckMissed, Vector, HitNormal, HitNormal ); WB_SET_AUTO( OnLineCheckMissed, Vector, HitVoxel, HitVoxel ); WB_DISPATCH_EVENT( pEventManager, OnLineCheckMissed, pEntity ); } }
void Sound3DListener::SetRotation( const Angles& Rotation ) { Vector DummyUp; Rotation.GetAxes( m_Right, m_Forward, DummyUp ); }
void WBCompEldWatson::TickPrimed() { if( !EldritchGame::IsPlayerAlive() ) { // Player can't cause Watson to teleport and attack when dead return; } if( !EldritchGame::IsPlayerVisible() ) { // Player can't cause Watson to teleport and attack when invisible return; } if( !IsPlayerVulnerable( true ) ) { // Do nothing, can't attack until player is vulnerable return; } WBEntity* const pEntity = GetEntity(); DEVASSERT( pEntity ); WBEntity* const pPlayer = EldritchGame::GetPlayer(); ASSERT( pPlayer ); WBCompEldTransform* const pTransform = pEntity->GetTransformComponent<WBCompEldTransform>(); DEVASSERT( pTransform ); WBCompEldTransform* const pPlayerTransform = pPlayer->GetTransformComponent<WBCompEldTransform>(); ASSERT( pPlayerTransform ); const Vector PlayerLocation = pPlayerTransform->GetLocation(); const Angles PlayerOrientation = pPlayerTransform->GetOrientation(); EldritchWorld* const pWorld = GetWorld(); ASSERT( pWorld ); const Angles PlayerOrientation2D = Angles( 0.0f, 0.0f, PlayerOrientation.Yaw ); const Vector PlayerFacing2D = PlayerOrientation2D.ToVector(); WBCompEldCollision* const pCollision = GET_WBCOMP( pEntity, EldCollision ); const Vector Extents = pCollision->GetExtents(); Vector TeleportLocation = PlayerLocation - ( PlayerFacing2D * m_TeleportDist ); CollisionInfo FindSpotInfo; FindSpotInfo.m_CollideWorld = true; FindSpotInfo.m_CollideEntities = true; FindSpotInfo.m_UserFlags = EECF_EntityCollision; FindSpotInfo.m_CollidingEntity = pEntity; if( pCollision->MatchesAllCollisionFlags( EECF_BlocksEntities ) ) { // HACK: Test against all entities, since Watson is a blocking entity. FindSpotInfo.m_UserFlags |= EECF_CollideAllEntities; } if( !pWorld->FindSpot( TeleportLocation, Extents, FindSpotInfo ) ) { // Do nothing, we don't fit behind player return; } const Vector NewToPlayer2D = ( PlayerLocation - TeleportLocation ).Get2D(); const Angles NewOrientation = NewToPlayer2D.ToAngles(); pTransform->SetLocation( TeleportLocation ); pTransform->SetOrientation( NewOrientation ); WB_MAKE_EVENT( OnWatsonTeleported, GetEntity() ); WB_DISPATCH_EVENT( GetEventManager(), OnWatsonTeleported, GetEntity() ); // Need to prime again before we can do another teleport m_Primed = false; }
bool WBCompEldWatson::IsPlayerVulnerable( const bool CheckMinDistance ) const { WBEntity* const pEntity = GetEntity(); DEVASSERT( pEntity ); WBEntity* const pPlayer = EldritchGame::GetPlayer(); ASSERT( pPlayer ); WBCompEldTransform* const pTransform = pEntity->GetTransformComponent<WBCompEldTransform>(); DEVASSERT( pTransform ); WBCompEldTransform* const pPlayerTransform = pPlayer->GetTransformComponent<WBCompEldTransform>(); ASSERT( pPlayerTransform ); const Vector EyeLocation = pTransform->GetLocation() + Vector( 0.0f, 0.0f, m_EyeOffsetZ ); const Vector PlayerLocation = pPlayerTransform->GetLocation(); const Vector PlayerViewLocation = EldritchGame::GetPlayerViewLocation(); const Vector ToPlayer = PlayerViewLocation - EyeLocation; const float DistanceSq = ToPlayer.LengthSquared(); if( CheckMinDistance && DistanceSq < m_MinAttackDistSq ) { // Do nothing, we're already close to player. return false; } if( DistanceSq > m_MaxAttackDistSq ) { // Do nothing, we're too far from the player return false; } // Do both a 3D and 2D check. 3D check is necessary so Watson doesn't teleport // when player is looking up or down at it, and 2D is necessary so Watson doesn't // teleport when player is looking up or down *away* from it. const Angles PlayerOrientation = pPlayerTransform->GetOrientation(); const Angles PlayerOrientation2D = Angles( 0.0f, 0.0f, PlayerOrientation.Yaw ); const Vector PlayerFacing = PlayerOrientation.ToVector(); const Vector PlayerFacing2D = PlayerOrientation2D.ToVector(); const Vector ToPlayer2D = ToPlayer.Get2D(); const float CosPlayerAngle = PlayerFacing.Dot( ToPlayer ); const float CosPlayerAngle2D = PlayerFacing2D.Dot( ToPlayer2D ); if( CosPlayerAngle < 0.0f || CosPlayerAngle2D < 0.0f ) { // Do nothing, player is facing us. return false; } EldritchWorld* const pWorld = GetWorld(); ASSERT( pWorld ); CollisionInfo OcclusionInfo; OcclusionInfo.m_CollideWorld = true; OcclusionInfo.m_CollideEntities = true; OcclusionInfo.m_UserFlags = EECF_Occlusion; OcclusionInfo.m_StopAtAnyCollision = true; if( pWorld->LineCheck( EyeLocation, PlayerViewLocation, OcclusionInfo ) ) { // Do nothing, player is occluded. return false; } return true; }
void Pose::to_angles(Angles &into) const { assert(skeleton); into.clear(skeleton->frame_size, skeleton); skeleton->get_angles(*this, &into.angles[0]); }
void Matrix3::fromAngles(const Angles& angles) { angles.toVectors(&m[0], &m[1], &m[2]); }