// If next step of path uses a ladder, prepare to traverse it void CCSBot::SetupLadderMovement() { if (m_pathIndex < 1 || m_pathLength == 0) return; const ConnectInfo *to = &m_path[m_pathIndex]; if (to->ladder) { m_spotEncounter = nullptr; m_areaEnteredTimestamp = gpGlobals->time; m_pathLadder = to->ladder; m_pathLadderTimestamp = gpGlobals->time; // to get to next area, we must traverse a ladder if (to->how == GO_LADDER_UP) { m_pathLadderState = APPROACH_ASCENDING_LADDER; m_pathLadderFaceIn = true; PrintIfWatched("APPROACH_ASCENDING_LADDER\n"); m_goalPosition = m_pathLadder->m_bottom; AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth * 2.0f); m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir)); } else { // try to mount ladder "face out" first m_goalPosition = m_pathLadder->m_top; AddDirectionVector(&m_goalPosition, OppositeDirection(m_pathLadder->m_dir), HalfHumanWidth * 2.0f); TraceResult result; Vector from = m_pathLadder->m_top; Vector to = m_goalPosition; UTIL_TraceLine(from, to, ignore_monsters, ENT(m_pathLadder->m_entity->pev), &result); if (result.flFraction == 1.0f) { PrintIfWatched("APPROACH_DESCENDING_LADDER (face out)\n"); m_pathLadderState = APPROACH_DESCENDING_LADDER; m_pathLadderFaceIn = false; m_lookAheadAngle = DirectionToAngle(m_pathLadder->m_dir); } else { PrintIfWatched("APPROACH_DESCENDING_LADDER (face in)\n"); m_pathLadderState = APPROACH_DESCENDING_LADDER; m_pathLadderFaceIn = true; m_lookAheadAngle = DirectionToAngle(OppositeDirection(m_pathLadder->m_dir)); m_goalPosition = m_pathLadder->m_top; AddDirectionVector(&m_goalPosition, m_pathLadder->m_dir, HalfHumanWidth); } } } }
void TankGameWidget::PaintRedeemer(const Redeemer& redeemer, QPainter& painter){ if (redeemer.visible || redeemer.explosion == SetInFlames || redeemer.detonate || redeemer.explosion == Burning){ ManualDraw(painter,m_redeemer,redeemer.paintPosition,DirectionToAngle(redeemer.moveDirection),false); ManualDraw(painter,m_redeemer_shadow,redeemer.paintPosition-QPointF(-0.3,-0.3),DirectionToAngle(redeemer.moveDirection),false); } }
void TankGameWidget::PaintMissile(const Missile& missile, QPainter& painter) { if (!missile.visible || missile.explosion == SetInFlames) { return; } ManualDraw(painter,m_missile,missile.paintPosition,DirectionToAngle(missile.moveDirection),false); ManualDraw(painter,m_missile_shadow,missile.paintPosition-QPointF(-0.1,-0.1),DirectionToAngle(missile.moveDirection),false); }
Warhead::Warhead(Point pos,Direction direction,float fSpeed, hgeSprite* spr,TEAM_ID team):DynamicObject(pos,fSpeed,direction),m_pSprite(spr) { m_TeamId = team; hgeRect a; m_Rectangle = Geometry::Rectangle(*(spr->GetBoundingBoxEx(m_Position.x,m_Position.y,DirectionToAngle(direction),1.0,1.0,&a))); this->Turn(direction); this->SetSpeedDirection(direction); }
void TankGameWidget::PaintTank(const Tank& tank, bool blueTank, QPainter& painter) { qreal rotation = 0; if(tank.moveDirection == Direction::None){ rotation = DirectionToAngle(tank.oldMoveDirection); }else{ rotation = DirectionToAngle(tank.moveDirection); tank.oldMoveDirection = tank.moveDirection; } if (tank.explosion==Destroyed){ ManualDraw(painter,m_tankWreck,tank.paintPosition,rotation,tank.isWrapping,tank.moveDirection); return; } const QPixmap& tankImage=blueTank ? m_tankBlue : m_tankRed; ManualDraw(painter,tankImage,tank.paintPosition,rotation,tank.isWrapping,tank.moveDirection); ManualDraw(painter,m_tankTower,tank.paintPosition,tank.paintTowerAngle,tank.isWrapping,tank.moveDirection); }
// Move actual view angles towards desired ones. // This is the only place v_angle is altered. // TODO: Make stiffness and turn rate constants timestep invariant. void CCSBot::UpdateLookAngles() { const float deltaT = g_flBotCommandInterval; float maxAccel; float stiffness; float damping; // springs are stiffer when attacking, so we can track and move between targets better if (IsAttacking()) { stiffness = 300.0f; damping = 30.0f; maxAccel = 3000.0f; } else { stiffness = 200.0f; damping = 25.0f; maxAccel = 3000.0f; } // these may be overridden by ladder logic float useYaw = m_lookYaw; float usePitch = m_lookPitch; // Ladders require precise movement, therefore we need to look at the // ladder as we approach and ascend/descend it. // If we are on a ladder, we need to look up or down to traverse it - override pitch in this case. // If we're trying to break something, though, we actually need to look at it before we can // look at the ladder if (IsUsingLadder()) { // set yaw to aim at ladder Vector to = m_pathLadder->m_top - pev->origin; float idealYaw = UTIL_VecToYaw(to); NavDirType faceDir = m_pathLadder->m_dir; if (m_pathLadderFaceIn) { faceDir = OppositeDirection(faceDir); } const float lookAlongLadderRange = 100.0f; const float ladderPitch = 60.0f; // adjust pitch to look up/down ladder as we ascend/descend switch (m_pathLadderState) { case APPROACH_ASCENDING_LADDER: { Vector to = m_goalPosition - pev->origin; useYaw = idealYaw; if (to.IsLengthLessThan(lookAlongLadderRange)) usePitch = -ladderPitch; break; } case APPROACH_DESCENDING_LADDER: { Vector to = m_goalPosition - pev->origin; useYaw = idealYaw; if (to.IsLengthLessThan(lookAlongLadderRange)) usePitch = ladderPitch; break; } case FACE_ASCENDING_LADDER: { useYaw = idealYaw; usePitch = -ladderPitch; break; } case FACE_DESCENDING_LADDER: { useYaw = idealYaw; usePitch = ladderPitch; break; } case MOUNT_ASCENDING_LADDER: case ASCEND_LADDER: { useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder); usePitch = -ladderPitch; break; } case MOUNT_DESCENDING_LADDER: case DESCEND_LADDER: { useYaw = DirectionToAngle(faceDir) + StayOnLadderLine(this, m_pathLadder); usePitch = ladderPitch; break; } case DISMOUNT_ASCENDING_LADDER: case DISMOUNT_DESCENDING_LADDER: { useYaw = DirectionToAngle(faceDir); break; } } } // Yaw float angleDiff = NormalizeAngle(useYaw - pev->v_angle.y); // if almost at target angle, snap to it const float onTargetTolerance = 1.0f; if (angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance) { m_lookYawVel = 0.0f; pev->v_angle.y = useYaw; } else { // simple angular spring/damper float accel = stiffness * angleDiff - damping * m_lookYawVel; // limit rate if (accel > maxAccel) accel = maxAccel; else if (accel < -maxAccel) accel = -maxAccel; m_lookYawVel += deltaT * accel; pev->v_angle.y += deltaT * m_lookYawVel; } // Pitch // Actually, this is negative pitch. angleDiff = usePitch - pev->v_angle.x; angleDiff = NormalizeAngle(angleDiff); if (false && angleDiff < onTargetTolerance && angleDiff > -onTargetTolerance) { m_lookPitchVel = 0.0f; pev->v_angle.x = usePitch; } else { // simple angular spring/damper // double the stiffness since pitch is only +/- 90 and yaw is +/- 180 float accel = 2.0f * stiffness * angleDiff - damping * m_lookPitchVel; // limit rate if (accel > maxAccel) accel = maxAccel; else if (accel < -maxAccel) accel = -maxAccel; m_lookPitchVel += deltaT * accel; pev->v_angle.x += deltaT * m_lookPitchVel; } // limit range - avoid gimbal lock if (pev->v_angle.x < -89.0f) pev->v_angle.x = -89.0f; else if (pev->v_angle.x > 89.0f) pev->v_angle.x = 89.0f; pev->v_angle.z = 0.0f; }