/// <summary> /// This is the overload you use when you call the constructor with the physics body /// </summary> public void Update() { if (_physicsBody == null) { throw new InvalidOperationException("This overload of update (no params) can't be called when there is no physics body"); } Update(_physicsBody.PositionToWorld(_physicsBody.CenterOfMass), _physicsBody.VelocityCached, _showAcceleration ? _physicsBody.AccelerationCached : new Vector3D(0, 0, 0)); // only request acceleration if needed (the body has to do math if it's requested) }
private void Body_ApplyForce(Body sender, BodyForceEventArgs e) { ConvexBody3D senderCast = sender as ConvexBody3D; if (senderCast == null) { return; } #region Boundry Force Vector3D positionWorld = senderCast.PositionToWorld(senderCast.CenterOfMass).ToVector(); // Just using one property from boundry assumes the boundry is square, and max is positive double boundryMax = _boundryMax.X; double maxDistance = _boundryMax.X * .85d; if (positionWorld.LengthSquared > maxDistance * maxDistance) { // Get the distance from the max distance double distFromMax = positionWorld.Length - maxDistance; // wait till now to do the expensive operation. // I want an acceleration of zero when distFromMax is 1, but an accel of 10 when it's boundryMax //NOTE: _boundryMax.X is to the edge of the box. If they are in the corner the distance will be greater, so the accel will be greater double accel = UtilityCore.GetScaledValue(0, 30, 0, boundryMax - maxDistance, distFromMax); // Apply a force Vector3D force = positionWorld; force.Normalize(); force *= accel * senderCast.Mass * -1d; e.AddForce(force); } #endregion #region Gravity if (_hasGravity) { //TODO: Attract all other objects to the asteroids if (senderCast.MaterialGroupID == _materialManager.AsteroidMaterialID && _asteroidGravityForces.ContainsKey(senderCast)) { e.AddForce(_asteroidGravityForces[senderCast]); } else if (senderCast.MaterialGroupID == _materialManager.ShipMaterialID && _asteroidGravityForces.Keys.Count > 0) // the asteroids only attract every few frames. If I attract every frame, the forces are unbalanced, and the ship ends up propelling the asteroid around { #region Ship to asteroids Point3D shipPos = senderCast.PositionToWorld(senderCast.CenterOfMass); double shipMass = senderCast.Mass; Vector3D gravityForce = new Vector3D(0, 0, 0); foreach (Asteroid asteroid in _asteroids) { #region Apply Gravity Vector3D gravityLink = shipPos - asteroid.PositionWorld; double force = GRAVITATIONALCONSTANT * (asteroid.Mass * shipMass) / gravityLink.LengthSquared; gravityLink.Normalize(); gravityLink *= force; //_asteroidGravityForces[_asteroids[innerCntr].PhysicsBody] += gravityLink; gravityForce -= gravityLink; #endregion } e.AddForce(gravityForce); #endregion } } #endregion #region Set Velocities if (_setVelocityArgs != null) { _hasSetVelocities = true; // See if the velocity should be set for this type of object bool shouldSetVelocity = false; if (_setVelocityArgs.Asteroids && senderCast.MaterialGroupID == _materialManager.AsteroidMaterialID) { shouldSetVelocity = true; } else if (_setVelocityArgs.Minerals && senderCast.MaterialGroupID == _materialManager.MineralMaterialID) { shouldSetVelocity = true; } if (shouldSetVelocity) { // Figure out the velocity Vector3D velocity = new Vector3D(0, 0, 0); Vector3D angularVelocity = new Vector3D(0, 0, 0); if (_setVelocityArgs.Speed > 0d) { velocity = Math3D.GetRandomVector_Spherical(_setVelocityArgs.Speed); angularVelocity = Math3D.GetRandomVector_Spherical(_setVelocityArgs.Speed / 10d); if (_setVelocityArgs.IsRandom) { double halfSpeed = _setVelocityArgs.Speed / 2d; if (velocity.Length < halfSpeed) { // It's going too slow, choose a new speed between half and full velocity.Normalize(); double newSpeed = halfSpeed + (StaticRandom.NextDouble() * halfSpeed); velocity *= newSpeed; } } else { // GetRandomVectorSpherical returns random, but this should be fixed velocity.Normalize(); velocity *= _setVelocityArgs.Speed; } } // Set it (and clear rotation) senderCast.Omega = angularVelocity; senderCast.Velocity = velocity; } } #endregion }
public void WorldUpdating(double elapsedTime) { #region Visuals foreach (ModelVisual3D model in _visuals) { if (model == _physicsModel) { // The physics engine already transformed this one to world continue; } // By setting this transform, is will render wherever the physics body is model.Transform = _physicsBody.Transform; } #endregion #region Thrust Lines Transform3D transform = _physicsBody.Transform; // I just don't want to keep hitting the property foreach (List <ThrustLine> thrusts in _thrustLines.Values) { foreach (ThrustLine thrust in thrusts) { thrust.DrawVisual(1d, transform); } } #endregion #region Swarmbots for (int cntr = 0; cntr < _swarmBots.Count; cntr++) { #region Swarm Bot Set //TODO: Let the chase points rotate more loosely than the ship // Figure out the chase point Point3D chasePoint = _physicsBody.PositionToWorld(_swarmbotChasePoints[cntr]); Vector3D chasePointVelocity = this.VelocityWorld; Vector3D chasePointAcceleration = _physicsBody.AccelerationCached; _swarmbotChasePointSprites[cntr].Update(chasePoint, chasePointVelocity, chasePointAcceleration); foreach (SwarmBot2 bot in _swarmBots[cntr]) { bot.ChasePoint = chasePoint; bot.ChasePointVelocity = chasePointVelocity; bot.WorldUpdating(); } #endregion } #endregion // Progress bars _progressBarFuel.Value = _fuelTank.QuantityCurrent; // I don't want to change the mass every frame (lots of calculations need to be made), so only do it if there is a // greater than 3% difference in mass //NOTE: Currently only fuel is the variable mass, but there could be others in the future double totalMass = this.TotalMass; if (_lastSetMass == null || Math.Abs(totalMass - _lastSetMass.Value) > totalMass * .03d) { _physicsBody.Mass = Convert.ToSingle(totalMass); _lastSetMass = totalMass; } }