bool ZActor::CanAttackMelee(ZObject* pTarget, ZSkillDesc *pSkillDesc) { if (pSkillDesc == NULL) { float dist = Magnitude(pTarget->m_Position - m_Position); if (dist < m_pNPCInfo->fAttackRange) { if (CanSee(pTarget)) return true; } } else { rvector Pos = GetPosition(); rvector Dir = GetDirection(); Dir.z=0; Normalize(Dir); float fDist = Magnitude(Pos - pTarget->GetPosition()); float fColMinRange = pSkillDesc->fEffectAreaMin * 100.0f; float fColMaxRange = pSkillDesc->fEffectArea * 100.0f; if ((fDist < fColMaxRange + pTarget->GetCollRadius()) && (fDist >= fColMinRange)) { rvector vTargetDir = pTarget->GetPosition() - GetPosition(); rvector vBodyDir = GetDirection(); vBodyDir.z = vTargetDir.z = 0.0f; float angle = fabs(GetAngleOfVectors(vTargetDir, vBodyDir)); if (angle <= pSkillDesc->fEffectAngle) return true; } } return false; }
ZTaskResult ZTask_RotateToDir::OnRun(float fDelta) { rvector dir = m_TargetDir; if (!m_bRotated) { rmatrix mat; rvector vBodyDir = m_pParent->GetDirection(); float fAngle=GetAngleOfVectors(dir, vBodyDir); float fRotAngle = m_pParent->GetNPCInfo()->fRotateSpeed * (fDelta / 1.0f); if (fAngle > 0.0f) fRotAngle = -fRotAngle; if (fabs(fRotAngle) > fabs(fAngle)) { fRotAngle = -fAngle; m_bRotated = true; return ZTR_COMPLETED; } mat = RGetRotZ(ToDegree(fRotAngle)); m_pParent->RotateTo(vBodyDir * mat); } else { return ZTR_COMPLETED; } return ZTR_RUNNING; }
bool ZActor::CanSee(ZObject* pTarget) { rvector vTargetDir = pTarget->GetPosition() - GetPosition(); rvector vBodyDir = GetDirection(); vBodyDir.z = vTargetDir.z = 0.0f; float angle = fabs(GetAngleOfVectors(vTargetDir, vBodyDir)); if (angle <= m_pNPCInfo->fViewAngle) return true; return false; }
void ZCamera::Update(float fElapsed) { if (!g_pGame) { assert(false); return; } if (isnan(m_fAngleX) || isnan(m_fAngleZ)) { DMLog("Camera angle is NaN!\n"); m_fAngleX = CAMERA_DEFAULT_ANGLEX; m_fAngleZ = CAMERA_DEFAULT_ANGLEZ; } ZCombatInterface* pCombatInterface = ZGetGameInterface()->GetCombatInterface(); ZCharacter* pTargetCharacter = g_pGame->m_pMyCharacter; if (TargetCharacterOverride) { pTargetCharacter = TargetCharacterOverride; } v3 PlayerPosition{ pTargetCharacter->m_Position }; v3 PlayerDirection{ pTargetCharacter->CameraDir }; bool Observing = false; auto&& Observer = *pCombatInterface->GetObserver(); if (TargetCharacterOverride) { Observing = true; pTargetCharacter->GetHistory(&PlayerPosition, nullptr, g_pGame->GetTime(), &PlayerDirection); } else if (pCombatInterface->GetObserver()->IsVisible()) { auto&& ObserverTarget = Observer.GetTargetCharacter(); if (ObserverTarget) { pTargetCharacter = ObserverTarget; Observing = pTargetCharacter != nullptr; } if (pTargetCharacter) pTargetCharacter->GetHistory(&PlayerPosition, nullptr, g_pGame->GetTime() - Observer.GetDelay(), &PlayerDirection); } if (!pTargetCharacter) return; m_Target = PlayerPosition + GetTargetOffset(PlayerDirection, pTargetCharacter->GetScale()); v3 dir; if (Observing && GetLookMode() == ZCAMERA_DEFAULT) { // If we're spectating someone, set the direction to their direction. dir = PlayerDirection; m_fAngleX = acosf(dir.z); v3 HorizontalDir{ dir.x, dir.y, 0.f }; m_fAngleZ = GetAngleOfVectors(rvector(1, 0, 0), HorizontalDir); } else dir = GetCurrentDir(); v3 shockoffset{ 0, 0, 0 }; if (m_bShocked) { float fA = RANDOMFLOAT * 2 * PI_FLOAT; float fB = RANDOMFLOAT * 2 * PI_FLOAT; auto velocity = v3(sin(fA)*sin(fB), cos(fA)*sin(fB), cos(fB)); float fPower = (g_pGame->GetTime() - m_fShockStartTime) / m_fShockDuration; if (fPower > 1.f) { StopShock(); } else { fPower = 1.f - fPower; const float FFMAX_POWER = 300.f; float ffPower = fPower * m_fShockPower / FFMAX_POWER; ffPower = std::min(ffPower, 1.0f); ZGetInput()->SetDeviceForcesXY(ffPower, ffPower); fPower = pow(fPower, 1.5f); auto ShockVelocity = RANDOMFLOAT * m_fShockPower * velocity; shockoffset = fPower * fElapsed * ShockVelocity; } } float fRealDist = m_fDist; rvector pos = m_CurrentTarget - dir*m_fDist; RBSPPICKINFO bpi; if (ZGetGame()->GetWorld()->GetBsp()->Pick(m_Target, -dir, &bpi) && Magnitude(m_Target - bpi.PickPos) < Magnitude(m_Target - pos)) { float fColDist = Magnitude(bpi.PickPos - pos); float fTargetDist = Magnitude(m_Target - pos); pos = bpi.PickPos + dir; fRealDist = Magnitude(m_Target - pos) - 10.f; } if (pTargetCharacter && pTargetCharacter->GetScale() != 1.0f) fRealDist *= pTargetCharacter->GetScale(); m_CurrentTarget = m_Target; bool bCollisionWall = CheckCollisionWall(fRealDist, pos, dir); float fAddedZ = 0.0f; CalcMaxPayneCameraZ(fRealDist, fAddedZ, m_fAngleX); if (bCollisionWall) { m_fCurrentDist += CAMERA_WALL_TRACKSPEED*(fRealDist - m_fCurrentDist); } else { m_fCurrentDist += CAMERA_TRACKSPEED*(fRealDist - m_fCurrentDist); } if (GetLookMode() == ZCAMERA_DEFAULT || GetLookMode() == ZCAMERA_FREEANGLE) { m_Position = m_CurrentTarget - dir*m_fCurrentDist; m_Position.z += fAddedZ; // Lock the camera height if the player has fallen into the abyss if (m_Position.z <= DIE_CRITICAL_LINE) { rvector campos = pTargetCharacter->GetCenterPos() - pTargetCharacter->GetDirection() * 20.0f; m_Position.x = campos.x; m_Position.y = campos.y; m_Position.z = DIE_CRITICAL_LINE; if (GetLookMode() == ZCAMERA_DEFAULT) { rvector tar = pTargetCharacter->GetCenterPos(); if (tar.z < (DIE_CRITICAL_LINE - 1000.0f)) tar.z = DIE_CRITICAL_LINE - 1000.0f; dir = tar - m_Position; Normalize(dir); } } } v3 up{ 0, 0, 1 }; if (m_bShocked) { rvector CameraPos = m_Position + shockoffset; RSetCamera(CameraPos, CameraPos + dir, up); } else { RSetCamera(m_Position, m_Position + dir, up); } if (GetLookMode() == ZCAMERA_FREELOOK) { if (!_isnan(RCameraDirection.x) && !_isnan(RCameraDirection.y) && !_isnan(RCameraDirection.z)) { ZGetGameInterface()->GetCombatInterface()->GetObserver()->SetFreeLookTarget(RCameraDirection); } } }
bool ZCamera::CheckCollisionWall(float &fRealDist, rvector& pos, rvector& dir) { RBSPPICKINFO bpi; float fNearZ = DEFAULT_NEAR_Z; rvector pos2 = pos; // camera pos rvector tarpos = pos2 + (dir * fNearZ); // near pos rvector up2, right2; up2 = rvector(0.0f, 0.0f, 1.0f); right2 = Normalized(CrossProduct(dir, up2)); up2 = Normalized(CrossProduct(right2, dir)); right2 = Normalized(CrossProduct(dir, up2)); float fov = GetFOV(); float e = 1 / (tanf(fov / 2)); float fAspect = (float)RGetScreenWidth() / (float)RGetScreenHeight(); float fPV = (fAspect * fNearZ / e); float fPH = (fNearZ / e); bool bCollisionWall = false; pos2 = pos; rvector tar = tarpos + (up2 * fPV); rvector dir2; dir2 = tar - pos2; Normalize(dir2); // NOTE: This was using dir as at??? Figure out why auto matView = ViewMatrix(pos2, Normalized(dir - pos2), up2); if (ZGetGame()->GetWorld()->GetBsp()->Pick(pos2, dir2, &bpi)) { if (Magnitude(tar - bpi.PickPos) < Magnitude(tar - pos2)) { rvector v1, v2, v3; v1 = bpi.PickPos; v3 = tar; if (ZGetGame()->GetWorld()->GetBsp()->Pick(tarpos, up2, &bpi)) { v2 = bpi.PickPos; float fD = Magnitude(tarpos - v2); if (fD < fPH) { rvector vv1 = v1 - v2, vv2 = v2 - v3; D3DXVECTOR4 rV4; vv1 = Transform(vv1, matView); v2 = Transform(vv2, matView); float fAng = GetAngleOfVectors(vv1, vv2); if (fAng < 0.0f) fAng = -fAng; if (fAng < PI_FLOAT) { bCollisionWall = true; float fX = fPV - fD; float fY = fX * tanf(fAng); float fMyRealDist = fRealDist - fY; fRealDist = min(fMyRealDist, fRealDist); } } } } } pos2 = pos; tar = tarpos + (right2 * fPH); dir2 = Normalized(tar - pos2); if (ZGetGame()->GetWorld()->GetBsp()->Pick(pos2, dir2, &bpi)) { if (Magnitude(tar - bpi.PickPos) < Magnitude(tar - pos2)) { rvector v1, v2, v3; v1 = bpi.PickPos; v3 = tar; if (ZGetGame()->GetWorld()->GetBsp()->Pick(tarpos, right2, &bpi)) { v2 = bpi.PickPos; float fD = Magnitude(tarpos - v2); if (fD < fPH) { rvector vv1 = v1 - v2, vv2 = v2 - v3; float fAng = GetAngleOfVectors(vv1, vv2); if (fAng < 0.0f) fAng = -fAng; if (fAng < (PI_FLOAT / 2)) { bCollisionWall = true; float fX = fPH - fD; float fY = fX * tanf(fAng); float fMyRealDist = fRealDist - fY; fRealDist = min(fMyRealDist, fRealDist); } } } } } pos2 = pos; tar = tarpos - (up2 * fPV); dir2 = Normalized(tar - pos2); matView = ViewMatrix(pos2, Normalized(dir2 - pos2), up2); if (ZGetGame()->GetWorld()->GetBsp()->Pick(pos2, dir2, &bpi)) { if (Magnitude(tar - bpi.PickPos) < Magnitude(tar - pos2)) { rvector v1, v2, v3; v1 = bpi.PickPos; v3 = tar; if (ZGetGame()->GetWorld()->GetBsp()->Pick(tarpos, -up2, &bpi)) { v2 = bpi.PickPos; float fD = Magnitude(tarpos - v2); if (fD < fPH) { bCollisionWall = true; rvector vv1 = v1 - v2, vv2 = v2 - v3; vv1 = Transform(vv1, matView); vv2 = Transform(vv2, matView); float fAng = GetAngleOfVectors(vv1, vv2); if (fAng < 0.0f) fAng = -fAng; if (fAng < (PI_FLOAT / 2)) { float fX = fPV - fD; float fY = fX * tanf(fAng); float fMyRealDist = fRealDist - fY; fRealDist = min(fMyRealDist, fRealDist); } } } } } pos2 = pos; tar = tarpos - (right2 * fPH); dir2 = Normalized(tar - pos2); if (ZGetGame()->GetWorld()->GetBsp()->Pick(pos2, dir2, &bpi)) { if (Magnitude(tar - bpi.PickPos) < Magnitude(tar - pos2)) { rvector v1, v2, v3; v1 = bpi.PickPos; v3 = tar; if (ZGetGame()->GetWorld()->GetBsp()->Pick(tarpos, -right2, &bpi)) { v2 = bpi.PickPos; float fD = Magnitude(tarpos - v2); if (fD < fPH) { bCollisionWall = true; rvector vv1 = v1 - v2, vv2 = v2 - v3; float fAng = GetAngleOfVectors(vv1, vv2); if (fAng < 0.0f) fAng = -fAng; if (fAng < (PI_FLOAT / 2)) { float fX = fPH - fD; float fY = fX * tanf(fAng); float fMyRealDist = fRealDist - fY; fRealDist = min(fMyRealDist, fRealDist); } } } } } if (fRealDist < 0) fRealDist = 0.0f; return bCollisionWall; }
bool MPathTracer::ProcMove(rvector* pNewPos, rvector* pNewDir, rvector* pNewVelocity, rvector* pDir, rvector& Distance, rvector& RealDistance, bool bSmoothArrival) { //if(Velocity.x==0.0f && Velocity.y==0.0f && Velocity.z==0.0f) return true; // 같은 위치면 도착 float fDistance = Distance.GetMagnitude(); rvector TargetDir2D(m_Dir); if(Distance.x!=0.0f || Distance.y!=0.0f || Distance.z!=0.0f) { TargetDir2D = Distance; TargetDir2D.z = 0; TargetDir2D.Normalize(); } if(pDir!=NULL) { _ASSERT(pDir->z==0.0f); // 방향 설정은 보정된 Distance가 아닌 RealDistance에 의존한다. float fRealDistance = RealDistance.GetMagnitude(); if(fRealDistance<=m_Property.fMaxVelocity*m_fDirectionSettingConstant) { float fDirectionWeightConstant = max(min((1-fRealDistance/(m_Property.fMaxVelocity*m_fDirectionSettingConstant)), 1), 0); TargetDir2D = Normalize(InterpolatedVector(TargetDir2D, Normalize(*pDir), fDirectionWeightConstant)); } } // 회전 //////////////////////////////////////////////////////////// float fDiffAngle = GetAngleOfVectors(TargetDir2D, m_Dir); float fRotateAngle = fDiffAngle; float fRotatePercent = 1.0f; // 회전 가/감속 if(fDiffAngle>0) { m_fAngularVelocity = min(m_Property.fMaxRotationVelocity, m_fAngularVelocity + m_Property.fRotationAcceleration); if(fabs(fDiffAngle)<m_Property.fMaxRotationVelocity*m_nAgularDecelerationConstant) { m_fAngularVelocity = min(m_fAngularVelocity, fDiffAngle/m_nAgularDecelerationConstant); } } else if(fDiffAngle<0) { m_fAngularVelocity = max(-m_Property.fMaxRotationVelocity, m_fAngularVelocity - m_Property.fRotationAcceleration); if(fabs(fDiffAngle)<m_Property.fMaxRotationVelocity*m_nAgularDecelerationConstant) { m_fAngularVelocity = max(m_fAngularVelocity, fDiffAngle/m_nAgularDecelerationConstant); } } if(fDiffAngle!=0.0f) fRotatePercent = m_fAngularVelocity/fDiffAngle; rvector NewDir = Normalize(InterpolatedVector(m_Dir, Normalize(TargetDir2D), fRotatePercent)); // 결과 값 //m_fResultRotatePercent = fRotateAngle / m_Property.fMaxRotationVelocity; m_fResultRotatePercent = GetAngleOfVectors(NewDir, m_Dir) / m_Property.fMaxRotationVelocity; // 버그로 인해 실제 계산값을 입력 bool bArriveAngle = false; if(fRotatePercent==1.0f) bArriveAngle = true; // 가속 & 이동 //////////////////////////////////////////////////////////// // 현재 가능 가속도 계산 rvector Acceleration = Clip(Distance-m_Velocity, m_Property.fAcceleration); //rvector Acceleration = NewDir*m_Property.fAcceleration; float fAcceleration = Acceleration.GetMagnitude(); if(fAcceleration>=0.0f) { if(m_bDirectionSpeed==true) { // 방향에 따른 가감속 fAcceleration -= (fAcceleration*max(min((float)fabs(fDiffAngle)/pi, 1), 0)*m_nDirectionalSpeedContant); Acceleration = Normalize(Acceleration)*fAcceleration; } } // 현재 가능 속도 계산 rvector NewVelocity = m_Velocity + Acceleration; //float fNewVelocity = NewVelocity.GetMagnitude(); Clip(&NewVelocity, m_Property.fMaxVelocity); // Clip bool bArrive = false; // 거리에 따른 속도 조절 float fNewVelocity = NewVelocity.GetMagnitude(); if(bSmoothArrival==true && fDistance<=m_Property.fMaxVelocity*m_nDecelerationConstant) { float t = fDistance/(m_Property.fMaxVelocity*m_nDecelerationConstant); //_ASSERT(m_nDecelerationCurveConstant>=1.0f); fNewVelocity = min(fNewVelocity, m_Property.fMaxVelocity*(float)pow((t), m_nDecelerationCurveConstant)); NewVelocity = Normalize(NewVelocity)*fNewVelocity; if(fNewVelocity<=m_Property.fMaxVelocity*m_fArrivalConstant) bArrive = true; } else if(fNewVelocity>=fDistance) bArrive = true; // New Values *pNewVelocity = NewVelocity; *pNewDir = NewDir; *pNewPos = m_Pos+NewVelocity; return bArrive; }