/// <summary> /// Performs a bounce collision (a collision which modifies velocity and acceleration), and separates the objects if so. /// </summary> /// <param name="sphere">The Sphere to perform collision against.</param> /// <param name="thisMass">The mass of this instance.</param> /// <param name="otherMass">Th e mass of the argument cube.</param> /// <param name="elasticity">The ratio of velocity to preserve.</param> /// <returns>Whether a collision occurred.</returns> public bool CollideAgainstBounce(Sphere sphere, float thisMass, float otherMass, float elasticity) { #if DEBUG if (thisMass == 0 && otherMass == 0) { throw new ArgumentException("Both masses cannot be 0. For equal masses pick a non-zero value"); } #endif if (CollideAgainstMove(sphere, thisMass, otherMass)) { // Get the relative velocity of this circle to the argument circle: Vector3 relativeVelocity = new Vector3( this.TopParent.XVelocity - sphere.TopParent.XVelocity, this.TopParent.YVelocity - sphere.TopParent.YVelocity, this.TopParent.ZVelocity - sphere.TopParent.ZVelocity); #if FRB_MDX float velocityNormalDotResult = Vector3.Dot(relativeVelocity, LastMoveCollisionReposition); #else float velocityNormalDotResult; Vector3.Dot(ref relativeVelocity, ref LastMoveCollisionReposition, out velocityNormalDotResult); #endif if (velocityNormalDotResult >= 0) { return(true); } #if FRB_MDX //Vector2 tangentVector = new Vector2((float)mLastCollisionTangent.X, (float)mLastCollisionTangent.Y); // Perform the bounce if the relative velocity and the tangent are the opposite direction. Vector3 reverseNormal = -Vector3.Normalize(LastMoveCollisionReposition); float length = Vector3.Dot(relativeVelocity, reverseNormal); Vector3 velocityOnNormal = Vector3.Multiply(reverseNormal, length); #else Vector3 reverseNormal = -LastMoveCollisionReposition; reverseNormal.Normalize(); float length = Vector3.Dot(relativeVelocity, reverseNormal); Vector3 velocityOnNormal; Vector3.Multiply(ref reverseNormal, length, out velocityOnNormal); #endif sphere.TopParent.Velocity.X += (1 + elasticity) * thisMass / (thisMass + otherMass) * velocityOnNormal.X; sphere.TopParent.Velocity.Y += (1 + elasticity) * thisMass / (thisMass + otherMass) * velocityOnNormal.Y; sphere.TopParent.Velocity.Z += (1 + elasticity) * thisMass / (thisMass + otherMass) * velocityOnNormal.Z; this.TopParent.Velocity.X -= (1 + elasticity) * otherMass / (thisMass + otherMass) * velocityOnNormal.X; this.TopParent.Velocity.Y -= (1 + elasticity) * otherMass / (thisMass + otherMass) * velocityOnNormal.Y; this.TopParent.Velocity.Z -= (1 + elasticity) * otherMass / (thisMass + otherMass) * velocityOnNormal.Z; return(true); } return(false); }
/// <summary> /// Collision method that returns whether collision has occurred and repositions this and the /// argument Sphere to prevent overlap. /// </summary> /// <param name="sphere">The other Sphere to collide against.</param> /// <param name="thisMass">The mass of the calling Sphere. This value is used relative to "otherMass". Both cannot be 0.</param> /// <param name="otherMass">The mass of the argument Sphere. This value is used relative to "thisMass". Both cannot be 0.</param> /// <returns>Whether the calling Sphere and the argument Sphere are touching.</returns> #endregion public bool CollideAgainstMove(Sphere sphere, float thisMass, float otherMass) { #if DEBUG if (thisMass == 0 && otherMass == 0) { throw new ArgumentException("Both masses cannot be 0. For equal masses pick a non-zero value"); } #endif if (mLastDependencyUpdate != TimeManager.CurrentTime) { UpdateDependencies(TimeManager.CurrentTime); } if (sphere.mLastDependencyUpdate != TimeManager.CurrentTime) { sphere.UpdateDependencies(TimeManager.CurrentTime); } float differenceX = sphere.Position.X - Position.X; float differenceY = sphere.Position.Y - Position.Y; float differenceZ = sphere.Position.Z - Position.Z; float differenceSquared = differenceX * differenceX + differenceY * differenceY + differenceZ * differenceZ; if (differenceSquared < (Radius + sphere.Radius) * (Radius + sphere.Radius)) { double distanceToMove = Radius + sphere.Radius - System.Math.Sqrt(differenceSquared); Vector3 moveVector = new Vector3(differenceX, differenceY, differenceZ); moveVector.Normalize(); float amountToMoveThis = otherMass / (thisMass + otherMass); LastMoveCollisionReposition = moveVector * (float)(-distanceToMove * amountToMoveThis); sphere.LastMoveCollisionReposition = moveVector * (float)(distanceToMove * (1 - amountToMoveThis)); if (mParent != null) { TopParent.Position += LastMoveCollisionReposition; ForceUpdateDependencies(); } else { Position += LastMoveCollisionReposition; } if (sphere.mParent != null) { sphere.TopParent.Position += sphere.LastMoveCollisionReposition; sphere.ForceUpdateDependencies(); } else { sphere.Position += sphere.LastMoveCollisionReposition; } return(true); } else { return(false); } }
/// <summary> /// Returns whether this instance overlaps the argument cube, and separates the two instances according to their relative masses. /// </summary> /// <param name="cube">The cube to perform collision against.</param> /// <param name="thisMass">The mass of this instance.</param> /// <param name="otherMass">The mass of the cube.</param> /// <returns>Whether the objects were overlapping before the reposition.</returns> public bool CollideAgainstMove(AxisAlignedCube cube, float thisMass, float otherMass) { #if DEBUG if (thisMass == 0 && otherMass == 0) { throw new ArgumentException("Both masses cannot be 0. For equal masses pick a non-zero value"); } #endif if (LastDependencyUpdate != TimeManager.CurrentTime) { UpdateDependencies(TimeManager.CurrentTime); } if (cube.LastDependencyUpdate != TimeManager.CurrentTime) { cube.UpdateDependencies(TimeManager.CurrentTime); } Vector3 relativeCenter = Position - cube.Position; if (System.Math.Abs(relativeCenter.X) - Radius > cube.ScaleX || System.Math.Abs(relativeCenter.Y) - Radius > cube.ScaleY || System.Math.Abs(relativeCenter.Z) - Radius > cube.ScaleZ) { return(false); } Vector3 nearest = GetNearestPoint(cube, relativeCenter); float distance = (nearest - relativeCenter).LengthSquared(); if (distance > Radius * Radius) { return(false); } double distanceToMove = Radius - System.Math.Sqrt((double)distance); Vector3 moveVector = relativeCenter - nearest; moveVector.Normalize(); float amountToMoveThis = otherMass / (thisMass + otherMass); LastMoveCollisionReposition = moveVector * (float)(distanceToMove * amountToMoveThis); Vector3 cubeReposition = moveVector * (float)(-distanceToMove * (1 - amountToMoveThis)); cube.mLastMoveCollisionReposition = cubeReposition; if (mParent != null) { TopParent.Position += LastMoveCollisionReposition; ForceUpdateDependencies(); } else { Position += LastMoveCollisionReposition; } if (cube.mParent != null) { cube.TopParent.Position += cube.LastMoveCollisionReposition; ForceUpdateDependencies(); } else { cube.Position += cube.LastMoveCollisionReposition; } return(true); }
public bool UpdateElementVisibility(HierarchyNode parentNode) { bool didChange = false; if (mCircleVisibleRepresentation != null) { mCircleVisibleRepresentation.Position = this.Position; } else { mSpriteVisibleRepresentation.Position = this.Position; } mText.Position = this.Position; #region Update the attachment visibility bool shouldConnectionBeVisible = parentNode != null; if (shouldConnectionBeVisible != mParentLine.Visible) { mParentLine.Visible = shouldConnectionBeVisible; mParentAttachmentPoint.Visible = mParentLine.Visible; didChange = true; } #endregion #region If visible, update the position of the line itself if (mParentLine.Visible) { Vector3 vectorToParent = this.Position - parentNode.Position; if (vectorToParent.X == 0 && vectorToParent.Y == 0 && vectorToParent.Z == 0) { return(didChange); } float radius = 0; if (mCircleVisibleRepresentation != null) { radius = mCircleVisibleRepresentation.Radius; } else { radius = mSpriteVisibleRepresentation.ScaleX; } vectorToParent.Normalize(); Vector3 endPoint1 = this.Position - vectorToParent * radius; Vector3 endPoint2 = parentNode.Position + vectorToParent * radius; if (mParentAttachmentPoint.Position != endPoint2) { didChange = true; } mParentAttachmentPoint.Position = endPoint2; mParentLine.SetFromAbsoluteEndpoints(endPoint1, endPoint2); } #endregion return(didChange); }