public void Draw(Graphics graphics, Camera camera, IMassiveBody parentBody) { var poweredTrails = new List <RectangleF>(); var coastTrails = new List <RectangleF>(); for (int i = 0; i < _trailAngles.Count; i++) { double angle = _trailAngles[i] + parentBody.Pitch; double distance = _trailDistances[i]; DVector2 worldPoint = DVector2.FromAngle(angle) * distance + parentBody.Position; if (camera.Contains(worldPoint)) { PointF localPoint = RenderUtils.WorldToScreen(worldPoint, camera.Bounds); if (_trailPowered[i]) { poweredTrails.Add(new RectangleF(localPoint.X, localPoint.Y, 2, 2)); } else { coastTrails.Add(new RectangleF(localPoint.X, localPoint.Y, 2, 2)); } } } RenderUtils.DrawRectangles(graphics, poweredTrails, Color.Red); RenderUtils.DrawRectangles(graphics, coastTrails, Color.White); }
protected virtual void RenderAbove(Graphics graphics, Camera camera) { if (EntryFlame != null) { EntryFlame.Draw(graphics, camera); } // Only show the vectors when it's requested and the craft is not parented if (_showDisplayVectors && Parent == null) { // The length of the vector is based on the width of the camera bounds float lengthFactor = (float)(camera.Bounds.Width * 0.1); PointF start = RenderUtils.WorldToScreen(Position, camera.Bounds); DVector2 relativeVelocity = GetRelativeVelocity(); // Only draw the velocity vector when it can be normalized if (relativeVelocity.Length() > 0) { relativeVelocity.Normalize(); PointF velocityEnd = RenderUtils.WorldToScreen(Position + relativeVelocity * lengthFactor, camera.Bounds); graphics.DrawLine(Pens.White, start, velocityEnd); } DVector2 pitchVector = DVector2.FromAngle(Pitch); pitchVector.Normalize(); PointF pitchEnd = RenderUtils.WorldToScreen(Position + pitchVector * lengthFactor, camera.Bounds); graphics.DrawLine(Pens.Red, start, pitchEnd); } }
/// <summary> /// Stages the spacecraft according to its mounted angle by applying a normal force. /// </summary> public void Stage() { if (Children.Count > 0) { ISpaceCraft[] children = Children.ToArray(); foreach (ISpaceCraft child in children) { child.Stage(); } } else if (Parent != null) { Parent.RemoveChild(this); Parent = null; // Simulate simple staging mechanism double sAngle = StageOffset.Angle(); DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Math.PI * 0.5); _stagingForce = stagingNormal * Mass * 0.005; _requiresStaging = true; } }
public void Update(TimeStep timeStep, DVector2 enginePosition, DVector2 shipVelocity, double rotation, double throttle, double ispMultiplier, double angle = 0) { if (angle != 0) { _angle = angle; } double retrograde = rotation + Math.PI + _angle; int particles = (int)((throttle * _particleRate) / timeStep.UpdateLoops); // Interpolate between spreads based on ISP double spreadMultiplier = (1.0 - ispMultiplier) * _minSpread + ispMultiplier * _maxSpread; double throttleMultiplier = Math.Max(throttle, 0.3) * 0.01; // Add new particles if nessecary for (int i = 0; i < particles; i++) { if (_availableParticles.Count > 0) { double velocityFactor = _random.Next(200, 300) * throttleMultiplier; double spread = _random.NextDouble() - 0.5; DVector2 velocity = DVector2.FromAngle(retrograde + spread * spreadMultiplier); int id = _availableParticles.Dequeue(); Particle particle = _particles[id]; particle.IsActive = true; particle.Age = 0; particle.MaxAge = _random.NextDouble() * 0.05 + _maxAge; particle.Position = enginePosition.Clone(); particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor; } } // Update the particles for (int i = 0; i < _particles.Length; i++) { Particle particle = _particles[i]; if (particle.IsActive) { particle.Position += particle.Velocity * timeStep.Dt; particle.Age += timeStep.Dt; if (particle.Age > particle.MaxAge) { particle.IsActive = false; _availableParticles.Enqueue(i); } } } }
public void RenderGdi(Graphics graphics, Camera camera) { // Update position and rotation given the parent's motion double currentRotation = (_parent.Pitch - _initialRotation) + _rotationOffset; DVector2 rotationNormal = DVector2.FromAngle(currentRotation); Position = _parent.Position + rotationNormal * _initialDistance; var bounds = new RectangleD(Position.X - Width * 0.5, Position.Y - Height * 0.5, Width, Height); // Not in range easy return if (!camera.Intersects(bounds)) { return; } RectangleF screenBounds = RenderUtils.ComputeBoundingBox(Position, camera.Bounds, Width, Height); // Saftey if (screenBounds.Width > RenderUtils.ScreenWidth * 500) { return; } double drawingRotation = currentRotation + Constants.PiOverTwo; var offset = new PointF(screenBounds.X + screenBounds.Width * 0.5f, screenBounds.Y + screenBounds.Height * 0.5f); camera.ApplyScreenRotation(graphics); camera.ApplyRotationMatrix(graphics, offset, drawingRotation); graphics.DrawImage(_texture, screenBounds.X, screenBounds.Y, screenBounds.Width, screenBounds.Height); graphics.ResetTransform(); double visibility = Visibility(camera.Bounds); if (visibility < 1) { PointF iconPoint = RenderUtils.WorldToScreen(Position, camera.Bounds); var iconBounds = new RectangleF(iconPoint.X - 5, iconPoint.Y - 5, 10, 10); var iconColor = Color.FromArgb((int)((1 - visibility) * 255), IconColor.R, IconColor.G, IconColor.B); camera.ApplyScreenRotation(graphics); graphics.FillEllipse(new SolidBrush(iconColor), iconBounds); graphics.ResetTransform(); } }
public void Update(TimeStep timeStep, DVector2 shipPosition, DVector2 shipVelocity, double pitch, double heatingRate) { double rotation = pitch - _offsetAngle; DVector2 offset = new DVector2(Math.Cos(rotation), Math.Sin(rotation)) * _offsetLength; DVector2 shockPosition = shipPosition - offset; double normalizedHeating = Math.Max((heatingRate - 500000) * 0.0005, 0); int particles = (int)(normalizedHeating * _particleRate) / timeStep.UpdateLoops; // Add new particles if nessecary for (int i = 0; i < particles; i++) { if (_availableParticles.Count > 0) { double velocityFactor = _random.Next(50, 200); double spread = _random.NextDouble() * 2.5 - 1.25; DVector2 velocity = DVector2.FromAngle(rotation + spread); int id = _availableParticles.Dequeue(); Particle particle = _particles[id]; particle.IsActive = true; particle.Age = 0; particle.MaxAge = _random.NextDouble() * 0.01 + 0.02; particle.Position = shockPosition.Clone(); particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor; } } // Update the particles for (int i = 0; i < _particles.Length; i++) { Particle particle = _particles[i]; if (particle.IsActive) { particle.Position += particle.Velocity * timeStep.Dt; particle.Age += timeStep.Dt; if (particle.Age > particle.MaxAge) { particle.IsActive = false; _availableParticles.Enqueue(i); } } } }
void TickUpdate() { ComSat.Trace(this, "TickUpdate"); if(sabotageTime > 0) { sabotageTime -= ComSat.tickRate; } if (buildQueue.Any()) { var buildMe = buildQueue.Peek(); var prefab = prefabs[buildMe.what]; if(delay > 0) { var advance = ComSat.tickRate; if(sabotageTime > 0) { advance /= sabotageTimeMultiplier; } if(!powerSink.Powered()) { advance /= 2; } var completion = advance / prefab.buildTime; var totalRemaining = prefab.buildCost - usedResources; partialMetalUnit += DReal.Min(completion * prefab.buildCost.Metal, totalRemaining.Metal); partialSmokeUnit += DReal.Min(completion * prefab.buildCost.MagicSmoke, totalRemaining.MagicSmoke); var rs = new ResourceSet { Metal = (int)partialMetalUnit, MagicSmoke = (int)partialSmokeUnit }; if (resourceMan.TakeResources(entity.team, rs)) { usedResources += rs; partialMetalUnit %= 1; partialSmokeUnit %= 1; delay -= advance; } else { partialMetalUnit -= completion * prefab.buildCost.Metal; partialSmokeUnit -= completion * prefab.buildCost.MagicSmoke; } } if(delay <= 0) { if (!resourceMan.TakeResources(entity.team, prefab.buildCost - usedResources)) return; // Timer expired and we're building something. print("Build new " + prefab); var prefabSize = (DReal)prefab.collisionRadiusNumerator / prefab.collisionRadiusDenominator; var wiggle = ((ComSat.RandomValue() % 5) / 5) * ((ComSat.RandomValue() % 2 == 0) ? 1 : -1); var position = prefab.buildAtPoint ? buildMe.position : (entity.position + DVector2.FromAngle(entity.rotation + wiggle) * (entity.collisionRadius + prefabSize + 2 + wiggle)); ComSat.SpawnEntity(entity, prefab.gameObject, position, 0); if(buildMe.buildCollider != null) { buildMan.RemovePendingBuild(buildMe.buildCollider); } if (!buildMe.repeat) buildQueue.Dequeue(); ResetBuildTime(); } } }
public override void UpdateAnimations(TimeStep timeStep) { DVector2 retrogradeVelocity = GetRelativeVelocity(); retrogradeVelocity.Negate(); DVector2 engineBase = Position - DVector2.FromAngle(Pitch) * Height * 0.5; double altitude = GetRelativeAltitude(); double atmosphericDensity = GravitationalParent.GetAtmosphericDensity(altitude); _engineSmoke.Update(timeStep, engineBase, Velocity, retrogradeVelocity, atmosphericDensity, _sootRatio); base.UpdateAnimations(timeStep); }
public void Update(TimeStep timeStep, DVector2 enginePosition, DVector2 shipVelocity, double rotation, double throttle) { double retrograde = rotation + Math.PI; int particles = (int)((throttle * _particleRate) / timeStep.UpdateLoops); // Add new particles if nessecary for (int i = 0; i < particles; i++) { if (_availableParticles.Count > 0) { double velocityFactor = _random.Next(150, 250); double spread = _random.NextDouble() - 0.5; DVector2 velocity = DVector2.FromAngle(retrograde + spread * _spreadFactor); int id = _availableParticles.Dequeue(); Particle particle = _particles[id]; particle.IsActive = true; particle.Age = 0; particle.MaxAge = _random.NextDouble() * 0.1 + 0.05; particle.Position = enginePosition.Clone(); particle.Velocity = shipVelocity.Clone() + velocity * velocityFactor; } } // Update the particles for (int i = 0; i < _particles.Length; i++) { Particle particle = _particles[i]; if (particle.IsActive) { particle.Position += particle.Velocity * timeStep.Dt; particle.Age += timeStep.Dt; if (particle.Age > particle.MaxAge) { particle.IsActive = false; _availableParticles.Enqueue(i); } } } }
void TickUpdate() { ComSat.Trace(this, "TickUpdate"); if (ComSat.EntityExists(target)) { var dir = target.position - entity.position; // also vector to dest. var targetAngle = DVector2.ToAngle(dir); var baseAngle = Utility.CalculateNewAngle(entity.rotation, targetAngle, DReal.Radians(turnSpeed)); entity.rotation = baseAngle; } entity.velocity = DVector2.FromAngle(entity.rotation) * speed; DVector2 newPosition = entity.position + entity.velocity * ComSat.tickRate; // FIXME: this should do something to account for hitting fast-moving projectiles. DVector2 hitPosition; Entity hit = ComSat.LineCast(entity.position, newPosition, out hitPosition, entity.team); if (hit != null && (!hit.hitOnlyIfTargetted || hit == target)) { hit.Damage((int)ComputeDamage()); var position = new Vector3((float)hitPosition.y, 0, (float)hitPosition.x); var rotation = Quaternion.AngleAxis((float)entity.rotation, Vector3.up); if (impactPrefab != null && ComSat.RateLimit()) { ObjectPool.Instantiate(impactPrefab, position, rotation); } //if(trail) { // trail.transform.parent = null; // trail.autodestruct = true; // trail = null; //} if (!penetrates || speed < minPenetrationSpeed) { ComSat.DestroyEntity(entity, DestroyReason.HitTarget); return; } else { speed -= penetrationSpeedReduction; } } }
// This could be smarter. If dest is too close & perpendicular, then the tank // can end up circling around. public void MoveTowards(DVector2 dest) { ComSat.Trace(this, "MoveTowards"); var dir = dest - entity.position; // also vector to dest. var targetAngle = DVector2.ToAngle(dir); var baseAngle = Utility.CalculateNewAngle(entity.rotation, targetAngle, DReal.Radians(turnSpeed)); entity.rotation = baseAngle; // Move along current heading. Ramp speed up as the angle gets closer. // Augh. // [-pi,pi] => [0,2pi] if (targetAngle < 0) { targetAngle += DReal.TwoPI; } // Get targetAngle within +/- pi of baseAngle. if (targetAngle < baseAngle - DReal.PI) { targetAngle += DReal.TwoPI; } else if (targetAngle > baseAngle + DReal.PI) { targetAngle -= DReal.TwoPI; } var diff = DReal.Abs(baseAngle - targetAngle); if (canMoveWithoutTurning || diff < maxMoveAngle) { var distance = dir.magnitude; //print("Distance: " + distance + " speed is: " + tickSpeed); var speed = minSpeed + (maxSpeed - minSpeed) * (1 - (diff / DReal.PI)); if (distance < speed) { speed = DReal.Max(minSpeed, distance); } entity.velocity = canMoveWithoutTurning ? dir.normalized * speed : DVector2.FromAngle(baseAngle) * speed; } else { Stop(); } }
/// <summary> /// Stages the spacecraft according to its mounted angle by applying a normal force. /// </summary> public void Stage() { if (Children.Count > 0) { ISpaceCraft[] children = Children.ToArray(); foreach (ISpaceCraft child in children) { child.Stage(); } } else if (Parent != null) { Parent.RemoveChild(this); Parent = null; // Simulate simple staging mechanism double sAngle = StageOffset.Angle(); DVector2 stagingVector = DVector2.FromAngle(Rotation + sAngle + Math.PI * 0.5); AccelerationN += stagingVector * 1000; } }
public void Stop() { ComSat.Trace(this, "Stop"); entity.velocity = DVector2.FromAngle(entity.rotation) * minSpeed; }
/// <summary> /// Updates the spacecraft and it's children. /// </summary> public override void Update(double dt) { ComputeCachedProperties(); double altitude = GetRelativeAltitude(); if (GravitationalParent == null) { IspMultiplier = 1; } else { IspMultiplier = GravitationalParent.GetIspMultiplier(altitude); } if (Parent == null) { UpdateEngines(dt); if (Thrust > 0 && _isReleased) { var thrustVector = new DVector2(Math.Cos(Pitch) * Math.Cos(Yaw), Math.Sin(Pitch) * Math.Cos(Yaw)); var yawVector = new DVector2(Math.Cos(Pitch) * Math.Sin(Yaw), Math.Sin(Pitch) * Math.Sin(Yaw)); AccelerationN += (thrustVector * Thrust) / Mass; AccelerationY += (yawVector * Thrust) / Mass; } if (_requiresStaging) { // Simulate simple staging mechanism double sAngle = StageOffset.Angle(); DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Constants.PiOverTwo); AccelerationN += stagingNormal * StagingForce; _requiresStaging = false; } if (_isReleased) { // Integrate acceleration Velocity += AccelerationG * dt; Velocity += AccelerationD * dt; Velocity += AccelerationL * dt; Velocity += AccelerationN * dt; LateralVelocity += AccelerationY * dt; LateralPosition += LateralVelocity * dt; } // Re-normalize FTL scenarios if (Velocity.LengthSquared() > Constants.SpeedLightSquared) { Velocity.Normalize(); Velocity *= Constants.SpeedOfLight; } // If the craft is on the ground with high time warpd don't update the position as normal. // Instead just keep putting the ship at the correct spot on it's gravitational body based on rotation. if (OnGround && dt > 5) { DVector2 parentOffset = GravitationalParent.Position - Position; parentOffset.Normalize(); Position = GravitationalParent.Position + parentOffset * GravitationalParent.SurfaceRadius; } else { // Integrate velocity Position += Velocity * dt; } MachNumber = GetRelativeVelocity().Length() * 0.0029411764; foreach (ISpaceCraft child in Children) { child.UpdateChildren(Position, Velocity); } _trailTimer += dt; // Somewhat arbitrary conditions for launch trails if (dt < 0.1666666666 && !InOrbit && !OnGround && _cachedAltitude > 50 && _cachedAltitude < GravitationalParent.AtmosphereHeight * 2 && _trailTimer > 1) { string parentName = GravitationalParent.ToString(); if (!_launchTrails.ContainsKey(parentName)) { _launchTrails.Add(parentName, new LaunchTrail()); } _launchTrails[parentName].AddPoint(Position, GravitationalParent, Throttle > 0); _trailTimer = 0; } } }
/// <summary> /// Updates the spacecraft and it's children. /// </summary> public override void Update(double dt) { ComputeCachedProperties(); double altitude = GetRelativeAltitude(); IspMultiplier = GravitationalParent.GetIspMultiplier(altitude); if (Parent == null) { UpdateEngines(dt); if (Thrust > 0) { var thrustVector = new DVector2(Math.Cos(Pitch), Math.Sin(Pitch)); AccelerationN += (thrustVector * Thrust) / Mass; } if (_requiresStaging) { // Simulate simple staging mechanism double sAngle = StageOffset.Angle(); DVector2 stagingNormal = DVector2.FromAngle(Pitch + sAngle + Math.PI * 0.5); AccelerationN += stagingNormal * StagingForce; _requiresStaging = false; } // Integrate acceleration Velocity += (AccelerationG * dt); Velocity += (AccelerationD * dt); Velocity += (AccelerationN * dt); Velocity += (AccelerationL * dt); // Re-normalize FTL scenarios if (Velocity.LengthSquared() > Constants.SpeedLightSquared) { Velocity.Normalize(); Velocity *= Constants.SpeedOfLight; } // Integrate velocity Position += (Velocity * dt); MachNumber = GetRelativeVelocity().Length() * 0.0029411764; foreach (ISpaceCraft child in Children) { child.UpdateChildren(Position, Velocity); } _trailTimer += dt; // Somewhat arbitrary conditions for launch trails if (dt < 0.1666666666 && !InOrbit && _cachedAltitude > 50 && _cachedAltitude < GravitationalParent.AtmosphereHeight * 2 && _trailTimer > 1) { string parentName = GravitationalParent.ToString(); if (!_launchTrails.ContainsKey(parentName)) { _launchTrails.Add(parentName, new LaunchTrail()); } _launchTrails[parentName].AddPoint(Position, GravitationalParent, Throttle > 0); _trailTimer = 0; } } }
public static int Prev(int currentIndex, IList <IGravitationalBody> bodies, Camera camera) { DVector2 cameraNormal = DVector2.FromAngle(Math.PI - camera.Rotation); return(Iterate(currentIndex, bodies, cameraNormal)); }