public static float ShotDistanceSq(DynamicTransform2 shooter, GunData gun, DynamicPosition2 target) { Vector2 shotPosition = shooter.Position; Vector2 shotVelocity = gun.ShotSpeed * shooter.Orientation.Facing + shooter.Velocity; DynamicPosition2 initialProjectileState = new DynamicPosition2(shotPosition, shotVelocity); return(ShotDistanceSq(initialProjectileState, target)); }
public static DynamicPosition2 CreateProjectileState(DynamicTransform2 shooterDynamicState, GunMount gunMount, int firingBarrel, float deltaTime) { Vector2 gunLocalOffset = gunMount.LocalMountOffsets[firingBarrel]; Vector2 shotPosition = shooterDynamicState.Position + shooterDynamicState.Orientation.LocalToGlobal(gunLocalOffset); Vector2 shotVelocity = gunMount.MountedGun.ShotSpeed * shooterDynamicState.Orientation.Facing + shooterDynamicState.Velocity; DynamicPosition2 projectileState = new DynamicPosition2(shotPosition + deltaTime * shotVelocity, shotVelocity); return(projectileState); }
private static DynamicTransform2 ProcessCollision(DynamicTransform2 newDynamicTransform, VehiclePrototype prototype, SimulationData simulationData) { float penetration; Vector2 collisionAxis; if (simulationData.CollisionWithArenaBounds(prototype.VehicleSize, newDynamicTransform.Position, out penetration, out collisionAxis)) { const float kBounce = 2f; //2 is rigid bounce, 1 is no bounce Vector2 newPosition = newDynamicTransform.Position + kBounce * penetration * collisionAxis; Vector2 newVelocity = newDynamicTransform.Velocity - kBounce * Vector2.Dot(newDynamicTransform.Velocity, collisionAxis) * collisionAxis; DynamicPosition2 newDynamicPosition = new DynamicPosition2(newPosition, newVelocity); newDynamicTransform = new DynamicTransform2(newDynamicPosition, newDynamicTransform.DynamicOrientation); } return(newDynamicTransform); }
private static DynamicTransform2 ProcessState(AsteroidsControlData data, DynamicTransform2 state, VehicleDriveControls controls, float deltaTime) { float appliedRotationalThrust; if (controls.Axis1 != 0f) { appliedRotationalThrust = -data.RotationAcceleration * controls.Axis1; } else { appliedRotationalThrust = -state.AngularVelocity / deltaTime; } float originalRotationalVelocity = state.AngularVelocity; float newRotationalVelocity = originalRotationalVelocity + appliedRotationalThrust * deltaTime; if (Math.Abs(newRotationalVelocity) > data.MaxRotationSpeed) { newRotationalVelocity = Math.Sign(newRotationalVelocity) * data.MaxRotationSpeed; appliedRotationalThrust = (newRotationalVelocity - originalRotationalVelocity) / deltaTime; } float rotatedAmount = deltaTime * originalRotationalVelocity + 0.5f * (deltaTime * deltaTime) * appliedRotationalThrust; Orientation2 currentOrientation = state.Orientation; Orientation2 resultingOrientation = currentOrientation.RotatedBy(rotatedAmount); DynamicOrientation2 resultingDynamicOrientation = new DynamicOrientation2(resultingOrientation, newRotationalVelocity); //Use new orientation so that rotating and accelerating rsults in different outputs than just accelerating! Vector2 thrustDirection = resultingDynamicOrientation.Orientation.Facing; Vector2 appliedThrust = data.Acceleration * controls.Axis2 * thrustDirection; Vector2 originalVelocity = state.Velocity; Vector2 newVelocity = originalVelocity + deltaTime * appliedThrust; float intendedSpeedSq = newVelocity.LengthSquared(); if (intendedSpeedSq > (data.MaxSpeed * data.MaxSpeed)) { //NOTE: This is not the most accurate approach, but it is somewhat simpler newVelocity.Normalize(); newVelocity = data.MaxSpeed * newVelocity; appliedThrust = (newVelocity - originalVelocity) / deltaTime; } Vector2 positionDelta = deltaTime * originalVelocity + 0.5f * (deltaTime * deltaTime) * appliedThrust; Vector2 newPosition = state.Position + positionDelta; DynamicPosition2 resultingDynamicPosition = new DynamicPosition2(newPosition, newVelocity); return(new DynamicTransform2(resultingDynamicPosition, resultingDynamicOrientation)); }
public static float ShotDistanceSq(DynamicPosition2 projectile, DynamicPosition2 target, out float timeToClosest) { Vector2 shooterToTarget = target.Position - projectile.Position; float currentDistanceSq = shooterToTarget.LengthSquared(); Vector2 relativeVelocities = target.Velocity - projectile.Velocity; float dot = Vector2.Dot(shooterToTarget, relativeVelocities); float relativeVelocityModuleSq = relativeVelocities.LengthSquared(); timeToClosest = -dot / relativeVelocityModuleSq; if (timeToClosest < 0f) { //TODO: Makes sense, but I wonder how smooth the resulting function is. I'd like to analyze this //Penalize by how far in the past the projectile would need to back track to hit return(currentDistanceSq + (timeToClosest * timeToClosest) * relativeVelocityModuleSq); } //Squared distance to shot! float shotDistanceSq = currentDistanceSq + timeToClosest * ((2f * dot) + (timeToClosest * relativeVelocityModuleSq)); Debug.Assert(!float.IsInfinity(shotDistanceSq)); return(shotDistanceSq); }
public static bool ProjectileHitsVehicle(DynamicTransform2 vehicleTransformState, VehiclePrototype prototype, DynamicPosition2 projectileState, float deltaTime) { Vector2 projectileToVehicle = vehicleTransformState.Position - projectileState.Position; float currentDistanceSq = projectileToVehicle.LengthSquared(); Vector2 relativeVelocities = vehicleTransformState.Velocity - projectileState.Velocity; float dot = Vector2.Dot(projectileToVehicle, relativeVelocities); if (dot >= 0f) { return(currentDistanceSq <= prototype.VehicleSize * prototype.VehicleSize); } float relativeVelocityModuleSq = relativeVelocities.LengthSquared(); float timeToClosest = Math.Min(-dot / relativeVelocityModuleSq, deltaTime); float closestDistanceSq = currentDistanceSq + timeToClosest * ((2f * dot) + (timeToClosest * relativeVelocityModuleSq)); return(closestDistanceSq <= prototype.VehicleSize * prototype.VehicleSize); }
public static void SpawnProjectile(int index, SimulationState state, DynamicPosition2 projectileState) { state.Projectiles[index].Add(projectileState); }
//Player input gets processed into a ControlState, and AI will provide a control state public static SimulationState ProcessState(SimulationState state, SimulationData simulationData, Dictionary <uint, VehicleControls> controllerInputs, float deltaTime) { int currentVehicleCount = state.Vehicles.Length; SimulationState nextSimState = new SimulationState(currentVehicleCount); int totalProjectileCount = 0; for (int i = 0; i < state.Projectiles.Length; ++i) { var projectiles = state.Projectiles[i]; int localCount = 0; if (projectiles != null) { localCount = projectiles.Count; } totalProjectileCount += localCount; nextSimState.SetProjectileCount(state.IndexToID[i], localCount + 1); } for (int vehicleIndex = 0; vehicleIndex < state.Vehicles.Length; ++vehicleIndex) { uint controllerID = state.IndexToID[vehicleIndex]; Debug.Assert(controllerInputs.ContainsKey(controllerID)); VehiclePrototype prototype = simulationData.GetVehiclePrototype(controllerID); VehicleControls inputControlState = controllerInputs[controllerID]; VehicleState currentVehicleState = state.Vehicles[vehicleIndex]; DynamicTransform2 newDynamicTransform = ProcessVehicleDrive(currentVehicleState.DynamicTransform, prototype, inputControlState.DriveControls, deltaTime); newDynamicTransform = ProcessCollision(newDynamicTransform, prototype, simulationData); GunState currentGunState = currentVehicleState.GunState; GunMount gunMount = prototype.Guns; bool projectileFired; GunState nextGunState = ProcessGunstate(gunMount, currentGunState, inputControlState.GunTriggerDown, deltaTime, out projectileFired); if (projectileFired) { DynamicPosition2 projectileState = CreateProjectileState(newDynamicTransform, gunMount, currentGunState.NextGunToFire, deltaTime); SpawnProjectile(vehicleIndex, nextSimState, projectileState); } VehicleState newVehicleState = new VehicleState(newDynamicTransform, inputControlState.DriveControls, nextGunState); nextSimState.AddVehicle(controllerID, newVehicleState); } //TODO: The above resulting transforms can be put in a collection ready for collision detection below! for (int projectileIndex = 0; projectileIndex < state.Projectiles.Length; ++projectileIndex) { var projectiles = state.Projectiles[projectileIndex]; if (projectiles != null) { foreach (var projectile in projectiles) { bool hit = false; for (int targetVehicleIndex = 0; targetVehicleIndex < state.Vehicles.Length; ++targetVehicleIndex) { if (targetVehicleIndex != projectileIndex) { VehicleState vehicleToHit = state.Vehicles[targetVehicleIndex]; if (ProjectileHitsVehicle(vehicleToHit.DynamicTransform, simulationData.GetVehiclePrototype(state.IndexToID[targetVehicleIndex]), projectile, deltaTime)) { hit = true; break; } } } if (!hit) { Vector2 nextPosition = projectile.Position + deltaTime * projectile.Velocity; if (simulationData.InsideArena(nextPosition)) { DynamicPosition2 nextProjectileState = new DynamicPosition2(nextPosition, projectile.Velocity); nextSimState.Projectiles[projectileIndex].Add(nextProjectileState); } } else { RegisterHit(nextSimState, projectileIndex); } } } } return(nextSimState); }
public DynamicTransform2(DynamicPosition2 dynamicPosition, DynamicOrientation2 dynamicOrientation) { DynamicPosition = dynamicPosition; DynamicOrientation = dynamicOrientation; }
public static float ShotDistanceSq(DynamicPosition2 projectile, DynamicPosition2 target) { float unusedTime; return(ShotDistanceSq(projectile, target, out unusedTime)); }