Esempio n. 1
0
void CTAAirMoveType::UpdateFlying()
{
    float3 &pos = owner->pos;
    float3 &speed = owner->speed;

    // Direction to where we would like to be
    float3 dir = goalPos - pos;
    owner->restTime = 0;

    // don't change direction for waypoints we just flew over and missed slightly
    if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()
            && dir != ZeroVector && dir.SqLength2D() < 10000.0f) {
        float3 ndir = dir;
        ndir = ndir.UnsafeANormalize();

        if (ndir.SqDistance(dir) < 1.0f) {
            dir = owner->frontdir;
        }
    }

    const float gHeight = UseSmoothMesh()?
                          std::max(smoothGround->GetHeight(pos.x, pos.z), ground->GetApproximateHeight(pos.x, pos.z)):
                          ground->GetHeightAboveWater(pos.x, pos.z);

    // are we there yet?
    bool closeToGoal =
        (dir.SqLength2D() < maxDrift * maxDrift) &&
        (fabs(gHeight - pos.y + wantedHeight) < maxDrift);

    if (flyState == FLY_ATTACKING) {
        closeToGoal = (dir.SqLength2D() < 400);
    }

    if (closeToGoal) {
        // pretty close
        switch (flyState) {
        case FLY_CRUISING: {
            bool trans = dynamic_cast<CTransportUnit*>(owner);
            bool noland = dontLand || !autoLand;
            // should CMD_LOAD_ONTO be here?
            bool hasLoadCmds = trans && !owner->commandAI->commandQue.empty()
                               && (owner->commandAI->commandQue.front().id == CMD_LOAD_ONTO
                                   || owner->commandAI->commandQue.front().id == CMD_LOAD_UNITS);
            if (noland || (trans && ++waitCounter < 55 && hasLoadCmds)) {
                // transport aircraft need some time to detect that they can pickup
                if (trans) {
                    wantedSpeed = ZeroVector;
                    SetState(AIRCRAFT_HOVERING);
                    if (waitCounter > 60) {
                        wantedHeight = orgWantedHeight;
                    }
                } else {
                    wantedSpeed = ZeroVector;
                    if (!owner->commandAI->HasMoreMoveCommands())
                        wantToStop = true;
                    SetState(AIRCRAFT_HOVERING);
                }
            } else {
                wantedHeight = orgWantedHeight;
                SetState(AIRCRAFT_LANDING);
            }
            return;
        }
        case FLY_CIRCLING:
            // break;
            waitCounter++;
            if (waitCounter > 100) {
                if (owner->unitDef->airStrafe) {
                    float3 relPos = pos - circlingPos;
                    if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
                        relPos.x = 0.0001f;
                    }
                    relPos.y = 0.0f;
                    relPos.Normalize();
                    static CMatrix44f rot(0.0f,fastmath::PI/4.0f,0.0f);
                    float3 newPos = rot.Mul(relPos);

                    // Make sure the point is on the circle
                    newPos = newPos * goalDistance;

                    // Go there in a straight line
                    goalPos = circlingPos + newPos;
                }
                waitCounter = 0;
            }
            break;
        case FLY_ATTACKING: {
            if (owner->unitDef->airStrafe) {
                float3 relPos = pos - circlingPos;
                if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
                    relPos.x = 0.0001f;
                }
                relPos.y = 0;
                relPos.Normalize();
                CMatrix44f rot;
                if (gs->randFloat() > 0.5f) {
                    rot.RotateY(0.6f + gs->randFloat() * 0.6f);
                } else {
                    rot.RotateY(-(0.6f + gs->randFloat() * 0.6f));
                }
                float3 newPos = rot.Mul(relPos);
                newPos = newPos * goalDistance;

                // Go there in a straight line
                goalPos = circlingPos + newPos;
            }
            break;
        }
        case FLY_LANDING: {
            break;
        }
        }
    }

    // not there yet, so keep going
    dir.y = 0;
    float realMax = maxSpeed;
    float dist = dir.Length() + 0.1f;

    // If we are close to our goal, we should go slow enough to be able to break in time
    // new additional rule: if in attack mode or if we have more move orders then this is
    // an intermediate waypoint, don't slow down (FIXME)
    if (flyState != FLY_ATTACKING && dist < brakeDistance) {
        realMax = dist / (speed.Length2D() + 0.01f) * decRate;
    }

    wantedSpeed = (dir / dist) * realMax;
    UpdateAirPhysics();

    // Point toward goal or forward - unless we just passed it to get to another goal
    if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
        dir = circlingPos - pos;
    } else if (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands() &&
                                           dist < 120) && (goalPos - pos).Normalize().SqDistance(dir) > 1) {
        dir = owner->frontdir;
    } else {
        dir = goalPos - pos;
    }

    if (dir.SqLength2D() > 1) {
        const int h = GetHeadingFromVector(dir.x, dir.z);
        wantedHeading = (h == 0)? wantedHeading : h;
    }
}
Esempio n. 2
0
void CTAAirMoveType::UpdateAirPhysics()
{
    float3& pos = owner->pos;
    float3& speed = owner->speed;

    if (!((gs->frameNum + owner->id) & 3)) {
        CheckForCollision();
    }

    const float yspeed = speed.y;
    speed.y = 0.0f;

    float3 delta = wantedSpeed - speed;
    const float deltaDotSpeed = (speed != ZeroVector)? delta.dot(speed): 1.0f;

    if (deltaDotSpeed == 0.0f) {
        // we have the wanted speed
    } else if (deltaDotSpeed > 0.0f) {
        // accelerate
        const float sqdl = delta.SqLength();
        if (sqdl < Square(accRate)) {
            speed = wantedSpeed;
        } else {
            speed += delta / math::sqrt(sqdl) * accRate;
        }
    } else {
        // break
        const float sqdl = delta.SqLength();
        if (sqdl < Square(decRate)) {
            speed = wantedSpeed;
        } else {
            speed += delta / math::sqrt(sqdl) * decRate;
        }
    }

    speed.y = yspeed;
    float h;

    if (UseSmoothMesh()) {
        h = pos.y - std::max(
                smoothGround->GetHeightAboveWater(pos.x, pos.z),
                smoothGround->GetHeightAboveWater(pos.x + speed.x * 20.0f, pos.z + speed.z * 20.0f));
    } else {
        h = pos.y - std::max(
                ground->GetHeightAboveWater(pos.x, pos.z),
                ground->GetHeightAboveWater(pos.x + speed.x * 40.0f, pos.z + speed.z * 40.0f));
    }

    if (h < 4.0f) {
        speed.x *= 0.95f;
        speed.z *= 0.95f;
    }

    float wh = wantedHeight;

    if (lastColWarningType == 2) {
        const float3 dir = lastColWarning->midPos - owner->midPos;
        const float3 sdir = lastColWarning->speed - speed;

        if (speed.dot(dir + sdir * 20.0f) < 0.0f) {
            if (lastColWarning->midPos.y > owner->pos.y) {
                wh -= 30.0f;
            } else {
                wh += 50.0f;
            }
        }
    }


    float ws = 0.0f;

    if (h < wh) {
        ws = altitudeRate;
        if (speed.y > 0.0001f && (wh - h) / speed.y * accRate * 1.5f < speed.y) {
            ws = 0.0f;
        }
    } else {
        ws = -altitudeRate;
        if (speed.y < -0.0001f && (wh - h) / speed.y * accRate * 0.7f < -speed.y) {
            ws = 0.0f;
        }
    }

    if (fabs(wh - h) > 2.0f) {
        if (speed.y > ws) {
            speed.y = std::max(ws, speed.y - accRate * 1.5f);
        } else if (!owner->beingBuilt) {
            // let them accelerate upward faster if close to ground
            speed.y = std::min(ws, speed.y + accRate * (h < 20.0f? 2.0f: 0.7f));
        }
    } else {
        speed.y = speed.y * 0.95;
    }

    if (modInfo.allowAirPlanesToLeaveMap || (pos+speed).CheckInBounds()) {
        pos += speed;
    }
}
Esempio n. 3
0
void CHoverAirMoveType::UpdateFlying()
{
	const float3& pos = owner->pos;
	// const float4& spd = owner->speed;

	// Direction to where we would like to be
	float3 goalVec = goalPos - pos;

	owner->restTime = 0;

	// don't change direction for waypoints we just flew over and missed slightly
	if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()) {
		float3 goalDir = goalVec;

		if ((goalDir != ZeroVector) && (goalVec.dot(goalDir.UnsafeANormalize()) < 1.0f)) {
			goalVec = owner->frontdir;
		}
	}

	const float goalDistSq2D = goalVec.SqLength2D();
	const float gHeight = UseSmoothMesh()?
		std::max(smoothGround->GetHeight(pos.x, pos.z), CGround::GetApproximateHeight(pos.x, pos.z)):
		CGround::GetHeightAboveWater(pos.x, pos.z);

	const bool closeToGoal = (flyState == FLY_ATTACKING)?
		(goalDistSq2D < (             400.0f)):
		(goalDistSq2D < (maxDrift * maxDrift)) && (math::fabs(gHeight + wantedHeight - pos.y) < maxDrift);

	if (closeToGoal) {
		switch (flyState) {
			case FLY_CRUISING: {
				// NOTE: should CMD_LOAD_ONTO be here?
				const bool isTransporter = (dynamic_cast<CTransportUnit*>(owner) != NULL);
				const bool hasLoadCmds = isTransporter &&
					!owner->commandAI->commandQue.empty() &&
					(owner->commandAI->commandQue.front().GetID() == CMD_LOAD_ONTO ||
					 owner->commandAI->commandQue.front().GetID() == CMD_LOAD_UNITS);
				// [?] transport aircraft need some time to detect that they can pickup
				const bool canLoad = isTransporter && (++waitCounter < ((GAME_SPEED << 1) - 5));
				const bool isBusy = IsUnitBusy(owner);

				if (!CanLand(isBusy) || (canLoad && hasLoadCmds)) {
					wantedSpeed = ZeroVector;

					if (isTransporter) {
						if (waitCounter > (GAME_SPEED << 1)) {
							wantedHeight = orgWantedHeight;
						}

						SetState(AIRCRAFT_HOVERING);
						return;
					} else {
						if (!isBusy) {
							wantToStop = true;

							// NOTE:
							//   this is not useful, next frame UpdateFlying()
							//   will change it to _LANDING because wantToStop
							//   is now true
							SetState(AIRCRAFT_HOVERING);
							return;
						}
					}
				} else {
					wantedHeight = orgWantedHeight;

					SetState(AIRCRAFT_LANDING);
					return;
				}
			} break;

			case FLY_CIRCLING: {
				if ((++waitCounter) > ((GAME_SPEED * 3) + 10)) {
					if (airStrafe) {
						float3 relPos = pos - circlingPos;

						if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
							relPos.x = 0.0001f;
						}

						static CMatrix44f rot(0.0f, fastmath::PI / 4.0f, 0.0f);

						// make sure the point is on the circle, go there in a straight line
						goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance);
					}
					waitCounter = 0;
				}
			} break;

			case FLY_ATTACKING: {
				if (airStrafe) {
					float3 relPos = pos - circlingPos;

					if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
						relPos.x = 0.0001f;
					}

					CMatrix44f rot;

					if (gs->randFloat() > 0.5f) {
						rot.RotateY(0.6f + gs->randFloat() * 0.6f);
					} else {
						rot.RotateY(-(0.6f + gs->randFloat() * 0.6f));
					}

					// Go there in a straight line
					goalPos = circlingPos + (rot.Mul(relPos.Normalize2D()) * goalDistance);
				}
			} break;

			case FLY_LANDING: {
			} break;
		}
	}

	// not "close" to goal yet, so keep going
	// use 2D math since goal is on the ground
	// but we are not
	goalVec.y = 0.0f;

	// if we are close to our goal, we should
	// adjust speed st. we never overshoot it
	// (by respecting current brake-distance)
	const float curSpeed = owner->speed.Length2D();
	const float brakeDist = (0.5f * curSpeed * curSpeed) / decRate;
	const float goalDist = goalVec.Length() + 0.1f;
	const float goalSpeed =
		(maxSpeed          ) * (goalDist >  brakeDist) +
		(curSpeed - decRate) * (goalDist <= brakeDist);

	if (goalDist > goalSpeed) {
		// update our velocity and heading so long as goal is still
		// further away than the distance we can cover in one frame
		// we must use a variable-size "dead zone" to avoid freezing
		// in mid-air or oscillation behavior at very close distances
		// NOTE:
		//   wantedSpeed is a vector, so even aircraft with turnRate=0
		//   are coincidentally able to reach any goal by side-strafing
		wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z);
		wantedSpeed = (goalVec / goalDist) * goalSpeed;
	} else {
		// switch to hovering (if !CanLand()))
		if (flyState != FLY_ATTACKING) {
			ExecuteStop();
		}
	}

	// redundant, done in Update()
	// UpdateHeading();
	UpdateAirPhysics();

	// Point toward goal or forward - unless we just passed it to get to another goal
	if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
		goalVec = circlingPos - pos;
	} else {
		const bool b0 = (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands()));
		const bool b1 = (goalDist < brakeDist && goalDist > 1.0f);

		if (b0 && b1) {
			goalVec = owner->frontdir;
		} else {
			goalVec = goalPos - pos;
		}
	}

	if (goalVec.SqLength2D() > 1.0f) {
		// update heading again in case goalVec changed
		wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z);
	}
}
Esempio n. 4
0
void CHoverAirMoveType::UpdateAirPhysics()
{
	const float3& pos = owner->pos;
	const float4& spd = owner->speed;

	// copy vertical speed
	const float yspeed = spd.y;

	if (((gs->frameNum + owner->id) & 3) == 0) {
		CheckForCollision();
	}

	// cancel out vertical speed, acc and dec are applied in xz-plane
	owner->SetVelocity(spd * XZVector);

	const float3 deltaSpeed = wantedSpeed - spd;
	const float deltaDotSpeed = deltaSpeed.dot(spd);
	const float deltaSpeedSq = deltaSpeed.SqLength();

	if (deltaDotSpeed >= 0.0f) {
		// accelerate
		if (deltaSpeedSq < Square(accRate)) {
			owner->SetVelocity(wantedSpeed);
		} else {
			if (deltaSpeedSq > 0.0f) {
				owner->SetVelocity(spd + (deltaSpeed / math::sqrt(deltaSpeedSq) * accRate));
			}
		}
	} else {
		// deccelerate
		if (deltaSpeedSq < Square(decRate)) {
			owner->SetVelocity(wantedSpeed);
		} else {
			if (deltaSpeedSq > 0.0f) {
				owner->SetVelocity(spd + (deltaSpeed / math::sqrt(deltaSpeedSq) * decRate));
			}
		}
	}

	// absolute and relative ground height at (pos.x, pos.z)
	// if this aircraft uses the smoothmesh, these values are
	// calculated with respect to that (for changing vertical
	// speed, but not for ground collision)
	float curAbsHeight = owner->unitDef->canSubmerge?
		CGround::GetHeightReal(pos.x, pos.z):
		CGround::GetHeightAboveWater(pos.x, pos.z);

	// always stay above the actual terrain (therefore either the value of
	// <midPos.y - radius> or pos.y must never become smaller than the real
	// ground height)
	// note: unlike StrafeAirMoveType, UpdateTakeoff and UpdateLanding call
	// UpdateAirPhysics() so we ignore terrain while we are in those states
	if (modInfo.allowAircraftToHitGround) {
		const bool groundContact = (curAbsHeight > (owner->midPos.y - owner->radius));
		const bool handleContact = (aircraftState != AIRCRAFT_LANDED && aircraftState != AIRCRAFT_TAKEOFF && padStatus == PAD_STATUS_FLYING);

		if (groundContact && handleContact) {
			owner->Move(UpVector * (curAbsHeight - (owner->midPos.y - owner->radius) + 0.01f), true);
		}
	}

	if (UseSmoothMesh()) {
		curAbsHeight = owner->unitDef->canSubmerge?
			smoothGround->GetHeight(pos.x, pos.z):
			smoothGround->GetHeightAboveWater(pos.x, pos.z);
	}

	// restore original vertical speed, then compute new
	UpdateVerticalSpeed(spd, pos.y - curAbsHeight, yspeed);

	if (modInfo.allowAircraftToLeaveMap || (pos + spd).IsInBounds()) {
		owner->Move(spd, true);
	}
}
Esempio n. 5
0
void CHoverAirMoveType::UpdateAirPhysics()
{
	const float3& pos = owner->pos;
	      float3& speed = owner->speed;

	if (!((gs->frameNum + owner->id) & 3)) {
		CheckForCollision();
	}

	const float yspeed = speed.y; speed.y = 0.0f;

	const float3 deltaSpeed = wantedSpeed - speed;
	const float deltaDotSpeed = (speed != ZeroVector)? deltaSpeed.dot(speed): 1.0f;

	if (deltaDotSpeed == 0.0f) {
		// we have the wanted speed
	} else if (deltaDotSpeed > 0.0f) {
		// accelerate
		const float sqdl = deltaSpeed.SqLength();

		if (sqdl < Square(accRate)) {
			speed = wantedSpeed;
		} else {
			speed += (deltaSpeed / math::sqrt(sqdl) * accRate);
		}
	} else {
		// break
		const float sqdl = deltaSpeed.SqLength();

		if (sqdl < Square(decRate)) {
			speed = wantedSpeed;
		} else {
			speed += (deltaSpeed / math::sqrt(sqdl) * decRate);
		}
	}

	// absolute and relative ground height at (pos.x, pos.z)
	// if this aircraft uses the smoothmes, these values are
	// calculated with respect to that for changing vertical
	// speed, but not for ground collision
	float curAbsHeight = owner->unitDef->canSubmerge?
		ground->GetHeightReal(pos.x, pos.z):
		ground->GetHeightAboveWater(pos.x, pos.z);
	float curRelHeight = 0.0f;

	float wh = wantedHeight; // wanted RELATIVE height (altitude)
	float ws = 0.0f;         // wanted vertical speed

	// always stay above the actual terrain (therefore either the value of
	// <midPos.y - radius> or pos.y must never become smaller than the real
	// ground height)
	// note: unlike StrafeAirMoveType, UpdateTakeoff calls UpdateAirPhysics
	// so we ignore terrain while we are in the takeoff state to avoid jumps
	if (modInfo.allowAircraftToHitGround) {
		const bool groundContact = (curAbsHeight > (owner->midPos.y - owner->radius));
		const bool handleContact = (aircraftState != AIRCRAFT_LANDED && aircraftState != AIRCRAFT_TAKEOFF);

		if (groundContact && handleContact) {
			owner->Move1D(curAbsHeight - (owner->midPos.y - owner->radius) + 0.01f, 1, true);
		}
	}

	if (UseSmoothMesh()) {
		curAbsHeight = owner->unitDef->canSubmerge?
			smoothGround->GetHeight(pos.x, pos.z):
			smoothGround->GetHeightAboveWater(pos.x, pos.z);
	}

	speed.y = yspeed;
	curRelHeight = pos.y - curAbsHeight;

	if (lastColWarningType == 2) {
		const float3 dir = lastColWarning->midPos - owner->midPos;
		const float3 sdir = lastColWarning->speed - speed;

		if (speed.dot(dir + sdir * 20.0f) < 0.0f) {
			if (lastColWarning->midPos.y > owner->pos.y) {
				wh -= 30.0f;
			} else {
				wh += 50.0f;
			}
		}
	}



	if (curRelHeight < wh) {
		ws = altitudeRate;

		if ((speed.y > 0.0001f) && (((wh - curRelHeight) / speed.y) * accRate * 1.5f) < speed.y) {
			ws = 0.0f;
		}
	} else {
		ws = -altitudeRate;

		if ((speed.y < -0.0001f) && (((wh - curRelHeight) / speed.y) * accRate * 0.7f) < -speed.y) {
			ws = 0.0f;
		}
	}

	if (!owner->beingBuilt) {
		if (math::fabs(wh - curRelHeight) > 2.0f) {
			if (speed.y > ws) {
				speed.y = std::max(ws, speed.y - accRate * 1.5f);
			} else {
				// accelerate upward faster if close to ground
				speed.y = std::min(ws, speed.y + accRate * ((curRelHeight < 20.0f)? 2.0f: 0.7f));
			}
		} else {
			speed.y *= 0.95;
		}
	}


	if (modInfo.allowAircraftToLeaveMap || (pos + speed).IsInBounds()) {
		owner->Move3D(speed, true);
	}
}
Esempio n. 6
0
void CHoverAirMoveType::UpdateFlying()
{
	const float3& pos = owner->pos;
	const float3& speed = owner->speed;

	// Direction to where we would like to be
	float3 goalVec = goalPos - pos;

	owner->restTime = 0;

	// don't change direction for waypoints we just flew over and missed slightly
	if (flyState != FLY_LANDING && owner->commandAI->HasMoreMoveCommands()) {
		float3 goalDir = goalVec;

		if ((goalDir != ZeroVector) && (goalDir.UnsafeANormalize()).SqDistance(goalVec) < 1.0f) {
			goalVec = owner->frontdir;
		}
	}

	const float goalDistSq2D = goalVec.SqLength2D();
	const float gHeight = UseSmoothMesh()?
		std::max(smoothGround->GetHeight(pos.x, pos.z), ground->GetApproximateHeight(pos.x, pos.z)):
		ground->GetHeightAboveWater(pos.x, pos.z);

	const bool closeToGoal = (flyState == FLY_ATTACKING)?
		(goalDistSq2D < (             400.0f)):
		(goalDistSq2D < (maxDrift * maxDrift)) && (math::fabs(gHeight - pos.y + wantedHeight) < maxDrift);

	if (closeToGoal) {
		switch (flyState) {
			case FLY_CRUISING: {
				const bool hasMoreMoveCmds = owner->commandAI->HasMoreMoveCommands();
				const bool noland = dontLand || !autoLand || hasMoreMoveCmds;

				// NOTE: should CMD_LOAD_ONTO be here?
				const bool trans = (dynamic_cast<CTransportUnit*>(owner) != NULL);
				const bool hasLoadCmds = trans &&
					!owner->commandAI->commandQue.empty() &&
					(owner->commandAI->commandQue.front().GetID() == CMD_LOAD_ONTO ||
					 owner->commandAI->commandQue.front().GetID() == CMD_LOAD_UNITS);
				// [?] transport aircraft need some time to detect that they can pickup
				const bool canLoad = trans && (++waitCounter < ((GAME_SPEED << 1) - 5));

				if (noland || (canLoad && hasLoadCmds)) {
					if (trans) {
						wantedSpeed = ZeroVector;
						SetState(AIRCRAFT_HOVERING);
						if (waitCounter > (GAME_SPEED << 1)) {
							wantedHeight = orgWantedHeight;
						}
					} else {
						wantedSpeed = ZeroVector;
						if (!hasMoreMoveCmds) {
							wantToStop = true;
							SetState(AIRCRAFT_HOVERING);
						}
					}
				} else {
					wantedHeight = orgWantedHeight;
					SetState(AIRCRAFT_LANDING);
				}
				return;
			}
			case FLY_CIRCLING:
				// break;
				if ((++waitCounter) > ((GAME_SPEED * 3) + 10)) {
					if (airStrafe) {
						float3 relPos = pos - circlingPos;
						if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
							relPos.x = 0.0001f;
						}
						relPos.y = 0.0f;
						relPos.Normalize();
						static CMatrix44f rot(0.0f,fastmath::PI/4.0f,0.0f);
						float3 newPos = rot.Mul(relPos);

						// Make sure the point is on the circle
						newPos = newPos * goalDistance;

						// Go there in a straight line
						goalPos = circlingPos + newPos;
					}
					waitCounter = 0;
				}
				break;
			case FLY_ATTACKING: {
				if (airStrafe) {
					float3 relPos = pos - circlingPos;
					if (relPos.x < 0.0001f && relPos.x > -0.0001f) {
						relPos.x = 0.0001f;
					}
					relPos.y = 0;
					relPos.Normalize();
					CMatrix44f rot;
					if (gs->randFloat() > 0.5f) {
						rot.RotateY(0.6f + gs->randFloat() * 0.6f);
					} else {
						rot.RotateY(-(0.6f + gs->randFloat() * 0.6f));
					}
					float3 newPos = rot.Mul(relPos);
					newPos = newPos * goalDistance;

					// Go there in a straight line
					goalPos = circlingPos + newPos;
				}
				break;
			}
			case FLY_LANDING: {
				break;
			}
		}
	}

	// not there yet, so keep going
	goalVec.y = 0.0f;

	// if we are close to our goal and not in attack mode,
	// we should go slow enough to be able to break in time
	const float goalDist = goalVec.Length() + 0.1f;
	const float approachSpeed =
		(flyState != FLY_ATTACKING && goalDist < brakeDistance)?
		(goalDist / (speed.Length2D() + 0.01f) * decRate):
		maxSpeed;

	wantedSpeed = (goalVec / goalDist) * approachSpeed;

	UpdateAirPhysics();

	// Point toward goal or forward - unless we just passed it to get to another goal
	if ((flyState == FLY_ATTACKING) || (flyState == FLY_CIRCLING)) {
		goalVec = circlingPos - pos;
	} else {
		const bool b0 = (flyState != FLY_LANDING && (owner->commandAI->HasMoreMoveCommands()));
		const bool b1 = (goalDist < 120.0f) && ((goalVec.SafeNormalize()).SqDistance(goalVec) > 1.0f);

		if (b0 && b1) {
			goalVec = owner->frontdir;
		} else {
			goalVec = goalPos - pos;
		}
	}

	if (goalVec.SqLength2D() > 1.0f) {
		wantedHeading = GetHeadingFromVector(goalVec.x, goalVec.z);
	}
}
Esempio n. 7
0
void CHoverAirMoveType::UpdateAirPhysics()
{
	const float3& pos = owner->pos;
	const float4& spd = owner->speed;

	// copy vertical speed
	const float yspeed = spd.y;

	if (((gs->frameNum + owner->id) & 3) == 0) {
		CheckForCollision();
	}

	owner->SetVelocity(spd * XZVector);

	const float3 deltaSpeed = wantedSpeed - spd;
	const float deltaDotSpeed = deltaSpeed.dot(spd);
	const float deltaSpeedSq = deltaSpeed.SqLength();

	if (deltaDotSpeed >= 0.0f) {
		// accelerate
		if (deltaSpeedSq < Square(accRate)) {
			owner->SetVelocity(wantedSpeed);
		} else {
			if (deltaSpeedSq > 0.0f) {
				owner->SetVelocity(spd + (deltaSpeed / math::sqrt(deltaSpeedSq) * accRate));
			}
		}
	} else {
		// deccelerate
		if (deltaSpeedSq < Square(decRate)) {
			owner->SetVelocity(wantedSpeed);
		} else {
			if (deltaSpeedSq > 0.0f) {
				owner->SetVelocity(spd + (deltaSpeed / math::sqrt(deltaSpeedSq) * decRate));
			}
		}
	}

	// absolute and relative ground height at (pos.x, pos.z)
	// if this aircraft uses the smoothmesh, these values are
	// calculated with respect to that (for changing vertical
	// speed, but not for ground collision)
	float curAbsHeight = owner->unitDef->canSubmerge?
		ground->GetHeightReal(pos.x, pos.z):
		ground->GetHeightAboveWater(pos.x, pos.z);
	float curRelHeight = 0.0f;

	float wh = wantedHeight; // wanted RELATIVE height (altitude)
	float ws = 0.0f;         // wanted vertical speed

	// always stay above the actual terrain (therefore either the value of
	// <midPos.y - radius> or pos.y must never become smaller than the real
	// ground height)
	// note: unlike StrafeAirMoveType, UpdateTakeoff and UpdateLanding call
	// UpdateAirPhysics() so we ignore terrain while we are in those states
	if (modInfo.allowAircraftToHitGround) {
		const bool groundContact = (curAbsHeight > (owner->midPos.y - owner->radius));
		const bool handleContact = (aircraftState != AIRCRAFT_LANDED && aircraftState != AIRCRAFT_TAKEOFF && padStatus == PAD_STATUS_FLYING);

		if (groundContact && handleContact) {
			owner->Move(UpVector * (curAbsHeight - (owner->midPos.y - owner->radius) + 0.01f), true);
		}
	}

	if (UseSmoothMesh()) {
		curAbsHeight = owner->unitDef->canSubmerge?
			smoothGround->GetHeight(pos.x, pos.z):
			smoothGround->GetHeightAboveWater(pos.x, pos.z);
	}

	// restore original vertical speed
	owner->SetVelocity((spd * XZVector) + (UpVector * yspeed));

	if (lastColWarningType == 2) {
		const float3 dir = lastColWarning->midPos - owner->midPos;
		const float3 sdir = lastColWarning->speed - spd;

		if (spd.dot(dir + sdir * 20.0f) < 0.0f) {
			if (lastColWarning->midPos.y > owner->pos.y) {
				wh -= 30.0f;
			} else {
				wh += 50.0f;
			}
		}
	}

	curRelHeight = pos.y - curAbsHeight;

	if (curRelHeight < wh) {
		ws = altitudeRate;

		if ((spd.y > 0.0001f) && (((wh - curRelHeight) / spd.y) * accRate * 1.5f) < spd.y) {
			ws = 0.0f;
		}
	} else {
		ws = -altitudeRate;

		if ((spd.y < -0.0001f) && (((wh - curRelHeight) / spd.y) * accRate * 0.7f) < -spd.y) {
			ws = 0.0f;
		}
	}

	if (!owner->beingBuilt) {
		if (math::fabs(wh - curRelHeight) > 2.0f) {
			if (spd.y > ws) {
				owner->SetVelocity((spd * XZVector) + (UpVector * std::max(ws, spd.y - accRate * 1.5f)));
			} else {
				// accelerate upward faster if close to ground
				owner->SetVelocity((spd * XZVector) + (UpVector * std::min(ws, spd.y + accRate * ((curRelHeight < 20.0f)? 2.0f: 0.7f))));
			}
		} else {
			owner->SetVelocity((spd * XZVector) + (UpVector * spd.y * 0.95f));
		}
	}

	owner->SetSpeed(spd);

	if (modInfo.allowAircraftToLeaveMap || (pos + spd).IsInBounds()) {
		owner->Move(spd, true);
	}
}
Esempio n. 8
0
void CAirMoveType::UpdateFlying(float wantedHeight, float engine)
{
	float3& pos = owner->pos;
	SyncedFloat3& rightdir = owner->rightdir;
	SyncedFloat3& frontdir = owner->frontdir;
	SyncedFloat3& updir = owner->updir;
	float3& speed = owner->speed;

	float speedf = speed.Length();
	float3 goalDir = (goalPos - pos);
	float goalLength = std::max(0.001f, goalDir.Length2D());
	goalDir /= goalLength;

	float3 adjustedGoalDir = float3(goalPos.x, 0, goalPos.z) - float3(pos.x, 0, pos.z);
	adjustedGoalDir.SafeANormalize();

	float aileron = 0.0f;
	float rudder = 0.0f;
	float elevator = 0.0f;
	// do not check if the plane can be submerged here, since it'll cause
	// ground collisions later on
	float gHeight;
	if (UseSmoothMesh())
		gHeight = std::max(smoothGround->GetHeight(pos.x, pos.z), ground->GetApproximateHeight(pos.x, pos.z));
	else
		gHeight = ground->GetHeight(pos.x, pos.z);

	if (!((gs->frameNum + owner->id) & 3))
		CheckForCollision();

	float otherThreat = 0.0f;
	float3 otherDir;
	if (lastColWarning) {
		float3 otherDif = lastColWarning->pos - pos;
		float otherLength = otherDif.Length();

		otherDir =
			(otherLength > 0.0f)?
			(otherDif / otherLength):
			ZeroVector;
		otherThreat =
			(otherLength > 0.0f)?
			std::max(1200.0f, goalLength) / otherLength * 0.036f:
			0.0f;
	}

	float goalDotRight = rightdir.dot(adjustedGoalDir);
	float goalDotFront = adjustedGoalDir.dot(frontdir) * 0.5f + 0.501f;

	if (goalDotFront > 0.01f) {
		goalDotRight /= goalDotFront;
	}


	if (adjustedGoalDir.dot(frontdir) < -0.1f && goalLength < turnRadius && (!owner->directControl || owner->directControl->mouse2))
		goalDotRight = -goalDotRight;
	if (lastColWarning) {
		goalDotRight -= otherDir.dot(rightdir) * otherThreat;
	}

	// roll
	if (speedf > 1.5f && pos.y + speed.y * 10 > gHeight + wantedHeight * 0.6f) {
		float goalBankDif = goalDotRight + rightdir.y * 0.5f;
		if (goalBankDif > maxAileron*speedf * 4 && rightdir.y > -maxBank) {
			aileron = 1;
		} else if (goalBankDif < -maxAileron * speedf * 4 && rightdir.y < maxBank) {
			aileron = -1;
		} else {
			if (fabs(rightdir.y) < maxBank) {
				aileron = goalBankDif / (maxAileron * speedf * 4);
			} else {
				if (rightdir.y < 0.0f && goalBankDif < 0.0f) {
					aileron = -1;
				} else if (rightdir.y > 0.0f && goalBankDif > 0.0f) {
					aileron = 1;
				}
			}
		}
	} else {
		if (rightdir.y > 0.01f) {
			aileron = 1;
		} else if (rightdir.y < -0.01f) {
			aileron = -1;
		}
	}

	// yaw
	if (pos.y > gHeight + 15) {
		if (goalDotRight < -maxRudder * speedf * 2) {
			rudder = -1;
		} else if (goalDotRight > maxRudder * speedf * 2) {
			rudder = 1;
		} else {
			if (speedf > 0.0f && maxRudder > 0.0f) {
				rudder = goalDotRight / (maxRudder * speedf * 2);
			} else {
				rudder = 0;
			}
		}
	}

	// pitch
	if (speedf > 0.8f) {
		bool notColliding = true;
		if (lastColWarningType == 2) {
			const float3 dir = lastColWarning->midPos - owner->midPos;
			const float3 sdir = lastColWarning->speed - owner->speed;
			if (frontdir.dot(dir + sdir * 20) < 0) {
				elevator = updir.dot(dir) > 0 ? -1 : 1;
				notColliding = false;
			}
		}
		if (notColliding) {
			float gHeight2 = ground->GetHeight(pos.x + speed.x * 40, pos.z + speed.z * 40);
			float hdif = std::max(gHeight, gHeight2) + wantedHeight - pos.y - frontdir.y * speedf * 20;
			if (hdif < -(maxElevator * speedf * speedf * 20) && frontdir.y > -maxPitch) {
				elevator = -1;
			} else if (hdif > (maxElevator * speedf * speedf * 20) && frontdir.y < maxPitch) {
				elevator = 1;
			} else {
				if (fabs(frontdir.y) < maxPitch)
					elevator = hdif / (maxElevator * speedf * speedf * 20);
			}
		}
	}
	else {
		if (frontdir.y < -0.1f) {
			elevator = 1;
		} else if (frontdir.y > 0.15f) {
			elevator = -1;
		}
	}

	UpdateAirPhysics(rudder, aileron, elevator, engine, owner->frontdir);
}
void CHoverAirMoveType::UpdateAirPhysics()
{
	const float3& pos = owner->pos;
	      float3& speed = owner->speed;

	if (!((gs->frameNum + owner->id) & 3)) {
		CheckForCollision();
	}

	const float yspeed = speed.y; speed.y = 0.0f;

	const float3 deltaSpeed = wantedSpeed - speed;
	const float deltaDotSpeed = (speed != ZeroVector)? deltaSpeed.dot(speed): 1.0f;

	if (deltaDotSpeed == 0.0f) {
		// we have the wanted speed
	} else if (deltaDotSpeed > 0.0f) {
		// accelerate
		const float sqdl = deltaSpeed.SqLength();

		if (sqdl < Square(accRate)) {
			speed = wantedSpeed;
		} else {
			speed += (deltaSpeed / math::sqrt(sqdl) * accRate);
		}
	} else {
		// break
		const float sqdl = deltaSpeed.SqLength();

		if (sqdl < Square(decRate)) {
			speed = wantedSpeed;
		} else {
			speed += (deltaSpeed / math::sqrt(sqdl) * decRate);
		}
	}

	float minHeight = 0.0f;  // absolute ground height at (pos.x, pos.z)
	float curHeight = 0.0f;  // relative ground height at (pos.x, pos.z) == pos.y - minHeight (altitude)

	float wh = wantedHeight; // wanted RELATIVE height (altitude)
	float ws = 0.0f;         // wanted vertical speed

	if (UseSmoothMesh()) {
		minHeight = owner->unitDef->canSubmerge?
			smoothGround->GetHeight(pos.x, pos.z):
			smoothGround->GetHeightAboveWater(pos.x, pos.z);
	} else {
		minHeight = owner->unitDef->canSubmerge?
			ground->GetHeightReal(pos.x, pos.z):
			ground->GetHeightAboveWater(pos.x, pos.z);
	}

	// [?] aircraft should never be able to end up below terrain
	// if (pos.y < minHeight)
	//     owner->Move1D(std::min(minHeight - pos.y, altitudeRate), 1, true);

	speed.y = yspeed;
	curHeight = pos.y - minHeight;

	if (curHeight < 4.0f) {
		speed.x *= 0.95f;
		speed.z *= 0.95f;
	}

	if (lastColWarningType == 2) {
		const float3 dir = lastColWarning->midPos - owner->midPos;
		const float3 sdir = lastColWarning->speed - speed;

		if (speed.dot(dir + sdir * 20.0f) < 0.0f) {
			if (lastColWarning->midPos.y > owner->pos.y) {
				wh -= 30.0f;
			} else {
				wh += 50.0f;
			}
		}
	}



	if (curHeight < wh) {
		ws = altitudeRate;

		if ((speed.y > 0.0001f) && (((wh - curHeight) / speed.y) * accRate * 1.5f) < speed.y) {
			ws = 0.0f;
		}
	} else {
		ws = -altitudeRate;

		if ((speed.y < -0.0001f) && (((wh - curHeight) / speed.y) * accRate * 0.7f) < -speed.y) {
			ws = 0.0f;
		}
	}

	if (!owner->beingBuilt) {
		if (math::fabs(wh - curHeight) > 2.0f) {
			if (speed.y > ws) {
				speed.y = std::max(ws, speed.y - accRate * 1.5f);
			} else {
				// accelerate upward faster if close to ground
				speed.y = std::min(ws, speed.y + accRate * ((curHeight < 20.0f)? 2.0f: 0.7f));
			}
		} else {
			speed.y *= 0.95;
		}
	}


	if (modInfo.allowAircraftToLeaveMap || (pos + speed).IsInBounds()) {
		owner->Move3D(speed, true);
	}
}