private void glControl_Load(object sender, EventArgs e) { glControl.MakeCurrent(); GL.Enable(EnableCap.DepthTest); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Disable(EnableCap.CullFace); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.ClearColor(0.5f, 0.5f, 1.0f, 1.0f); plane = new Physics.Plane(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0, 1, 0)); rigidBody = new RigidBody(); rigidBody.m_fMass = 1.0f; rigidBody.m_v3Position = new Vector3(0, 6.0f, 0); rigidBody.m_fGravity = new Vector3(0, -9.81f, 0); rigidBody.m_fRestitution = 0.0f; rigidBody.m_fFriction = 1.0f; rigidBody.m_fLinearDamping = 0.5f; rigidBody.m_fAngularDamping = 0.5f; rigidBody.m_v3Rotate = new Vector3(ToRadian(30.0f), 0, ToRadian(20.0f)); rigidBody.m_listPoints.Add(new Vector3(-2.0f, -1.0f, -1.5f)); rigidBody.m_listPoints.Add(new Vector3(+2.0f, -1.0f, -1.5f)); rigidBody.m_listPoints.Add(new Vector3(-2.0f, +1.0f, -1.5f)); rigidBody.m_listPoints.Add(new Vector3(+2.0f, +1.0f, -1.5f)); rigidBody.m_listPoints.Add(new Vector3(-2.0f, -1.0f, +1.5f)); rigidBody.m_listPoints.Add(new Vector3(+2.0f, -1.0f, +1.5f)); rigidBody.m_listPoints.Add(new Vector3(-2.0f, +1.0f, +1.5f)); rigidBody.m_listPoints.Add(new Vector3(+2.0f, +1.0f, +1.5f)); // back rigidBody.m_listIndices.AddRange(new int[] { 3, 1, 0 }); rigidBody.m_listIndices.AddRange(new int[] { 0, 2, 3 }); // front rigidBody.m_listIndices.AddRange(new int[] { 4, 5, 7 }); rigidBody.m_listIndices.AddRange(new int[] { 7, 6, 4 }); // left rigidBody.m_listIndices.AddRange(new int[] { 6, 2, 0 }); rigidBody.m_listIndices.AddRange(new int[] { 0, 4, 6 }); // right rigidBody.m_listIndices.AddRange(new int[] { 1, 3, 7 }); rigidBody.m_listIndices.AddRange(new int[] { 7, 5, 1 }); // bottom rigidBody.m_listIndices.AddRange(new int[] { 0, 1, 5 }); rigidBody.m_listIndices.AddRange(new int[] { 5, 4, 0 }); // top rigidBody.m_listIndices.AddRange(new int[] { 7, 3, 2 }); rigidBody.m_listIndices.AddRange(new int[] { 2, 6, 7 }); rigidBody.Create(); DispatcherTimer timer = new DispatcherTimer(); timer.Tick += Timer_Tick; timer.Interval = TimeSpan.FromSeconds(0); timer.Start(); }
/// <summary> /// Calcula la fuerza y la aplica al cuerpo especificado /// </summary> /// <param name="body">Cuerpo</param> /// <param name="duration">Duración</param> public override void UpdateForce(ref RigidBody body, float duration) { // Detectar la fase de la explosión en la que estamos if (m_TimePassed <= ImplosionDuration) { // Fase de implosión float distance = Vector3.Distance(body.Position, this.DetonationCenter); if (distance > this.ImplosionMinRadius && distance <= this.ImplosionMaxRadius) { // El cuerpo está en el área de implosión. Aplicar las fuerzas float max = this.ImplosionMaxRadius - this.ImplosionMinRadius; float curr = distance - this.ImplosionMinRadius; float forceMagnitude = curr / max; Vector3 force = Vector3.Normalize(this.DetonationCenter - body.Position) * this.ImplosionForce * forceMagnitude; body.AddForce(force); } } else if (m_TimePassed <= (ImplosionDuration + ConcussionDuration)) { // Honda expansiva // Intervalo actual de máxima acción de la honda float min = this.ShockwaveSpeed * m_TimePassed; float max = this.ShockwaveSpeed * (m_TimePassed + duration); // Distancia al centro del objeto float distance = Vector3.Distance(body.Position, this.DetonationCenter); float totalDuration = this.ConcussionDuration + this.ImplosionDuration; float maxDuration = this.ConcussionDuration; float maxDistance = (this.ShockwaveSpeed * maxDuration) + this.ShockwaveThickness; float forceMagnitude = 0f; if (distance >= min && distance <= max) { // En plena honda expansiva. Se aplican las fuerzas atenuadas sólo por la duración float relativeTime = 0f; if (m_TimePassed < totalDuration) { relativeTime = 1f - (m_TimePassed / totalDuration); } forceMagnitude = this.PeakConcussionForce * relativeTime; } else if (distance < min) { // El objeto ha sido sobrepasado por la honda expansiva. Fuerza mínimamente atenuada float relativeTime = 0f; if (m_TimePassed < totalDuration) { relativeTime = 1f - (m_TimePassed / totalDuration); } forceMagnitude = this.PeakConcussionForce * relativeTime; } else if (distance > max && distance <= maxDistance) { // El objeto no ha sido alcanzado por la honda expansiva. Fuerza atenuada por el tiempo y la distancia float relativeDistance = 0f; if (distance < maxDistance) { relativeDistance = 1f - (distance / maxDistance); } float relativeTime = 0f; if (m_TimePassed < totalDuration) { relativeTime = 1f - (m_TimePassed / totalDuration); } forceMagnitude = this.PeakConcussionForce * relativeDistance * relativeTime; } if (forceMagnitude > 0f) { Vector3 force = Vector3.Normalize(body.Position - this.DetonationCenter) * forceMagnitude; body.AddForce(force); } } else { // Fin de la explosión m_ExplosionActive = false; } m_TimePassed += duration; }
private void glControl_Load(object sender, EventArgs e) { glControl.MakeCurrent(); GL.Enable(EnableCap.DepthTest); GL.Disable(EnableCap.Lighting); GL.Disable(EnableCap.Texture2D); GL.Disable(EnableCap.CullFace); GL.PolygonMode(MaterialFace.FrontAndBack, PolygonMode.Fill); GL.ClearColor(0.5f, 0.5f, 1.0f, 1.0f); plane = new Physics.Plane(new Vector3(0.0f, 0.0f, 0.0f), new Vector3(0, 1, 0)); rigidBody1 = new RigidBody(); loader = new OBJLoader(); loader.LoadFromFile("", "henger.obj"); Vector3 v3Gravity = new Vector3(0, -9.81f, 0); rigidBody1.m_fMass = 1.0f; rigidBody1.m_v3Position = new Vector3(0f, 5.0f, 0); rigidBody1.m_fGravity = v3Gravity; rigidBody1.m_fRestitution = 0.0f; rigidBody1.m_fFriction = 1.0f; rigidBody1.m_v3Rotate = new Vector3(ToRadian(0.0f), 0, ToRadian(60.0f)); rigidBody1.m_fLinearDamping = 0.2f; rigidBody1.m_fAngularDamping = 0.2f; float scale = 0.1f; foreach (Vector3 v in loader.vertices) { rigidBody1.m_listPoints.Add(new Vector3(v.X * scale, v.Y * scale, v.Z * scale)); } foreach (OBJLoader.Material mat in loader.materials) { for (int i = 0; i < mat.indices.Count; i += 3) { int i0 = mat.indices[i + 0].id_vertex; int i1 = mat.indices[i + 1].id_vertex; int i2 = mat.indices[i + 2].id_vertex; rigidBody1.m_listIndices.AddRange(new int[] { i0, i1, i2 }); } } rigidBody1.Create(); loader = new OBJLoader(); loader.LoadFromFile("", "sphere.obj"); rigidBody2 = new RigidBody(); rigidBody2.m_fMass = 1.0f; rigidBody2.m_v3Position = new Vector3(2f, 10.0f, 2); rigidBody2.m_fGravity = v3Gravity; rigidBody2.m_fRestitution = 0.0f; rigidBody2.m_fFriction = 1.0f; rigidBody2.m_v3Rotate = new Vector3(ToRadian(0.0f), 0, ToRadian(-15.0f)); rigidBody2.m_fLinearDamping = 0.2f; rigidBody2.m_fAngularDamping = 0.2f; foreach (Vector3 v in loader.vertices) { rigidBody2.m_listPoints.Add(new Vector3(v.X * scale, v.Y * scale, v.Z * scale)); } foreach (OBJLoader.Material mat in loader.materials) { for (int i = 0; i < mat.indices.Count; i += 3) { int i0 = mat.indices[i + 0].id_vertex; int i1 = mat.indices[i + 1].id_vertex; int i2 = mat.indices[i + 2].id_vertex; rigidBody2.m_listIndices.AddRange(new int[] { i0, i1, i2 }); } } rigidBody2.Create(); DispatcherTimer timer = new DispatcherTimer(); timer.Tick += Timer_Tick;; timer.Interval = TimeSpan.FromSeconds(0); timer.Start(); }
//Get the coordinates of the specified jump arc where it lines up with one of the edges of a given rigidbody public Tuple <Tuple <Vector2D, Vector2D, Vector2D, Vector2D>, Tuple <Vector2D, Vector2D, Vector2D, Vector2D> > GetBoxCollisionPoints(RigidBody RB, Vector2D source, float accelerationTime, float totalJumpTime, Vector2D gravity) { if (float.IsNaN(accelerationTime)) { return(null); } //force acceleration time to be positive (negative times are not valid) int sign = (int)(accelerationTime / (float)Math.Abs(accelerationTime)); accelerationTime *= sign; //calculate the possible collision locations during acceleration Vector2D acceleration = new Vector2D(GetHorizontalAcceleration() * sign, gravity.Y); Vector2D velocity = new Vector2D(playerBody.LinearVelocity.X, jumpInitialVelocity); Vector2D initialPosition = new Vector2D(source); Tuple <Vector2D, Vector2D, Vector2D, Vector2D> resultsDuringAcc = UsefulMathsFunctions.GetArcPosAtBoxEdges(RB, initialPosition, velocity, acceleration, accelerationTime); //calculate the possible collision locations after acceleration float YatAccEnd = SuvatEquations.SfromUAT(velocity.Y, acceleration.Y, accelerationTime); float XatAccEnd = SuvatEquations.SfromUAT(velocity.X, acceleration.X, accelerationTime); initialPosition.Y += YatAccEnd; initialPosition.X += XatAccEnd; velocity.X = SuvatEquations.VfromUAT(velocity.X, acceleration.X, accelerationTime); velocity.Y = SuvatEquations.VfromUAT(velocity.Y, acceleration.Y, accelerationTime); acceleration.X = 0; Tuple <Vector2D, Vector2D, Vector2D, Vector2D> resultsAftergAcc = UsefulMathsFunctions.GetArcPosAtBoxEdges(RB, initialPosition, velocity, acceleration, totalJumpTime - accelerationTime); //return the two sets of coordinates return(new Tuple <Tuple <Vector2D, Vector2D, Vector2D, Vector2D>, Tuple <Vector2D, Vector2D, Vector2D, Vector2D> >(resultsDuringAcc, resultsAftergAcc)); }
//Checks to see if a fall from an input coordinate TO an input coordinate would collide with a given rigidbody public bool FallCollidesWithRB(RigidBody RB, Vector2D source, Vector2D destination, Vector2D gravity) { //Return false if the rigid body is outside the widest possible fall range if (source.Y - playerRadius > RB.Shape.ComputeAABB().MAX.Y + RB.Position.Y) { return(false); } if (Math.Max(source.Y, destination.Y) + playerRadius < RB.Position.Y + RB.Shape.ComputeAABB().MIN.Y) { return(false); } if (RB.Shape.ComputeAABB().MAX.X + RB.Position.X < Math.Min(source.X, destination.X) - playerRadius) { return(false); } if (Math.Max(source.X, destination.X) + playerRadius < RB.Position.X + RB.Shape.ComputeAABB().MIN.X) { return(false); } Vector2D displacement = destination - source; //calculate the fall time (return no collision if the fall time was invalid) Tuple <float, float> timeToFall = SuvatEquations.TfromSUA(displacement.Y, 0.0f, gravity.Y); if (float.IsNaN(timeToFall.Item1) || timeToFall.Item1 < 0) { return(false); } //calculate the average horizontal acceleration needed to fall to the destination float acceleration = SuvatEquations.AfromSUT(displacement.X, 0.0f, Math.Max(timeToFall.Item1, timeToFall.Item2)); //calculate the four points where the path defined by acceleration could potentially collide with the rigidbody Tuple <float, float> timeToReach; //obtain the X positions of the sides of the rigidbody float leftmostX = (RB.Position.X + RB.Shape.ComputeAABB().MIN.X) - source.X; float righttmostX = (RB.Position.X + RB.Shape.ComputeAABB().MAX.X) - source.X; //obtain the Y positions of the top and bottom of the rigidbody float topY = (RB.Position.Y + RB.Shape.ComputeAABB().MIN.Y) - source.Y; float bottomY = (RB.Position.Y + RB.Shape.ComputeAABB().MAX.Y) - source.Y; //these coords will be estimated from the above coords float leftmostY; float righttmostY; float topX; float bottomX; Shape temp = new Circle(playerRadius); //calculate the time to reach the left side of the rigidbody timeToReach = Physics.SuvatEquations.TfromSUA(leftmostX, 0.0f, acceleration); //calculate the first Y position, check it for collision, calculate the second, check for collision leftmostY = Physics.SuvatEquations.SfromUAT(0.0f, 98, timeToReach.Item1); if (!float.IsNaN(leftmostY) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(leftmostX, leftmostY) + source)) { return(true); } leftmostY = Physics.SuvatEquations.SfromUAT(0.0f, 98, timeToReach.Item2); if (!float.IsNaN(leftmostY) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(leftmostX, leftmostY) + source)) { return(true); } //calculate the time to reach the right side of the rigidbody timeToReach = Physics.SuvatEquations.TfromSUA(righttmostX, 0.0f, acceleration); //calculate the first Y position, check it for collision, calculate the second, check for collision righttmostY = Physics.SuvatEquations.SfromUAT(0.0f, 98, timeToReach.Item1); if (!float.IsNaN(righttmostY) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(righttmostX, righttmostY) + source)) { return(true); } righttmostY = Physics.SuvatEquations.SfromUAT(0.0f, 98, timeToReach.Item2); if (!float.IsNaN(righttmostY) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(righttmostX, righttmostY) + source)) { return(true); } //calculate the time to reach the top of the rigidbody timeToReach = Physics.SuvatEquations.TfromSUA(topY, 0.0f, 98); //calculate the first X position, check it for collision, calculate the second, check for collision topX = Physics.SuvatEquations.SfromUAT(0.0f, acceleration, timeToReach.Item1); if (!float.IsNaN(topX) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(topX, topY) + source)) { return(true); } topX = Physics.SuvatEquations.SfromUAT(0.0f, acceleration, timeToReach.Item2); if (!float.IsNaN(topX) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(topX, topY) + source)) { return(true); } //calculate the time to reach the bottom of the rigidbody timeToReach = Physics.SuvatEquations.TfromSUA(bottomY, 0.0f, 98); //calculate the first X position, check it for collision, calculate the second, check for collision bottomX = Physics.SuvatEquations.SfromUAT(0.0f, acceleration, timeToReach.Item1); if (!float.IsNaN(bottomX) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(bottomX, bottomY) + source)) { return(true); } bottomX = Physics.SuvatEquations.SfromUAT(0.0f, acceleration, timeToReach.Item2); if (!float.IsNaN(bottomX) && RB.Shape.IsCollided(temp, RB.Position, new Vector2D(bottomX, bottomY) + source)) { return(true); } return(false); }
//Checks to see if a jump from source to destination would collid with the provided rigidbody public bool JumpCollidesWithRB(RigidBody RB, Vector2D source, Vector2D destination, Vector2D gravity) { //Get the max Y displacement float maxYRange = SuvatEquations.SFromUVA(jumpInitialVelocity, 0.0f, gravity.Y); //Return false if the rigid body is outside the widest possible jump range if (maxYRange + source.Y - playerRadius > RB.Shape.ComputeAABB().MAX.Y + RB.Position.Y) { return(false); } if (Math.Max(source.Y, destination.Y) + playerRadius < RB.Position.Y + RB.Shape.ComputeAABB().MIN.Y) { return(false); } if (RB.Shape.ComputeAABB().MAX.X + RB.Position.X < Math.Min(source.X, destination.X) - playerRadius) { return(false); } if (Math.Max(source.X, destination.X) + playerRadius < RB.Position.X + RB.Shape.ComputeAABB().MIN.X) { return(false); } Vector2D displacement = destination - source; //calculate the jump's acceleration duration, and total duration float accelerationTime = GetJumpFromSourceToDest(source, destination, gravity); float totalJumpTime = GetTotalJumpDuration(source, destination, gravity); //if the jump is not valid, return that it does not collide with the rigidbody if (float.IsNaN(totalJumpTime) || totalJumpTime < 0) { return(false); } //calculate the 8 points that could potentially intersect with the box (1 before and 1 after the jump's apex) Tuple <Tuple <Vector2D, Vector2D, Vector2D, Vector2D>, Tuple <Vector2D, Vector2D, Vector2D, Vector2D> > boxCollisionPoints = GetBoxCollisionPoints(RB, source, accelerationTime, totalJumpTime, gravity); if (boxCollisionPoints == null) { return(true); } //check to see if the player would collide with the rigidbody at any of the calculated positions Shape temp = new Circle(playerRadius); if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item1.Item1)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item1.Item2)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item1.Item3)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item1.Item4)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item2.Item1)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item2.Item2)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item2.Item3)) { return(true); } if (RB.Shape.IsCollided(temp, RB.Position, boxCollisionPoints.Item2.Item4)) { return(true); } return(false); }