private CrushData GetClosestCrushData(Vector3 contactPoint) { float minDist = 9999; CrushData minData = null; foreach (CrushData data in _carFile.CrushSections[1].Data) { Vector3 crushPoint = Vector3.Transform(_localVertices[data.RefVertex].Position, GameVars.ScaleMatrix * _actor.GlobalPose); float dist = Vector3.Distance(crushPoint, contactPoint); if (dist < minDist) { minDist = dist; minData = data; } } return(minData); }
public void OnContact(Vector3 contactPoint, float force2, Vector3 normal) { List <int> hitPoints = new List <int>(); Vector3 force = force2 * normal; force = Vector3.Transform(force, _actor.GlobalOrientation); force.X *= 0.5f; //limit sideways crush force.Y *= 0.9f; force *= 0.00000011f * _carFile.CrushSections[1].DamageMultiplier; //scale it down to a managable number float forceSize = force.Length(); //if (forceSize > 0.04f) //{ //force *= 0.04f / forceSize; //cap max force so things dont get loco //} if (forceSize < 0.004f) { return; } Vector3 force3 = force; force.X = Math.Abs(force.X); force.Y = Math.Abs(force.Y); force.Z = Math.Abs(force.Z); if (float.IsNaN(Vector3.Normalize(force).X)) { return; } int hitpoints = 0; CrushData data = GetClosestCrushData(contactPoint); if (data == null) { return; //no crush data for this car } //foreach (CrushData data in _carFile.CrushSections[1].Data) { Vector3 crushPoint = Vector3.Transform(_localVertices[data.RefVertex].Position, GameVars.ScaleMatrix * _actor.GlobalPose); // if (Vector3.Distance(crushPoint, contactPoint) < 0.5f) { hitPoints.Add(data.RefVertex); hitpoints++; Vector3 curPos = _localVertices[data.RefVertex].Position; Vector3 directedForce = new Vector3(); directedForce.X = curPos.X < 0 ? force.X : -force.X; directedForce.Y = curPos.Y < 0 ? force.Y : -force.Y; directedForce.Z = curPos.Z < 0 ? force.Z : -force.Z; Vector3 parentScale = new Vector3(); parentScale.X = directedForce.X > 0 ? data.LeftScale : data.RightScale; parentScale.Y = directedForce.Y > 0 ? data.BottomScale : data.TopScale; parentScale.Z = directedForce.Z > 0 ? data.FrontScale : data.RearScale; directedForce *= parentScale; Vector3 oldPos = _localVertices[data.RefVertex].Position; curPos = KeepCrushPositionInBounds(curPos + directedForce, data.Box); float distanceMoved = Vector3.Distance(oldPos, curPos); _localVertices[data.RefVertex].Position = curPos; Vector3 parentDir = curPos - oldPos; if (distanceMoved < 0.0002f) { return; } Vector3 normalforce = Vector3.Normalize(force); foreach (CrushPoint point in data.Points) { if (point.VertexIndex < 0) { continue; } if (float.IsNaN(normalforce.X) || float.IsNaN(normalforce.Y) || float.IsNaN(normalforce.Z)) { break; } curPos = _localVertices[point.VertexIndex].Position; //float distanceFromParent = Vector3.Distance(curPos, _localVertices[data.RefVertex].Position); //float originalDistanceFromParent = Vector3.Distance(curPos, _originalPositions[data.RefVertex]); //if (distanceFromParent < originalDistanceFromParent) // return; //directedForce = force * parentScale; Vector3 vdir = _localVertices[data.RefVertex].Position - _localVertices[point.VertexIndex].Position; vdir.Normalize(); Vector3 newpos = _localVertices[point.VertexIndex].Position + (vdir * distanceMoved * parentScale * 2f * (1 - point.DistanceFromParent)); if (point.DistanceFromParent < 0.1f || Engine.Random.Next(10) % 2 == 0) { newpos = _localVertices[point.VertexIndex].Position + (parentDir * 0.6f * (1 - point.DistanceFromParent)); } //else //{ //} float dist3 = Vector3.Distance(_originalPositions[point.VertexIndex], newpos); // if were not too far away from orig position and this will move us closer to our parent, move this vert if (dist3 < 0.07f) { _localVertices[point.VertexIndex].Position = newpos; if (_vertexLinks[point.VertexIndex] != null) { foreach (int idx in _vertexLinks[point.VertexIndex]) { _localVertices[idx].Position = newpos; } } } else { //GameConsole.WriteEvent("not moving child"); } //force = normalforce * distanceMoved * MathHelper.Lerp(1f, 0.1f, point.DistanceFromParent); //curPos = _localVertices[point.VertexIndex].Position; //if (Math.Abs(force.Y) < 0.0001f) // force.Y *= (_localVertices[data.RefVertex].Position.Y - curPos.Y) * 1000; //directedForce.X = curPos.X < 0 ? force.X : -force.X; //directedForce.Y = curPos.Y < 0 ? force.Y : -force.Y; //directedForce.Z = curPos.Z < 0 ? force.Z : -force.Z; ////rnd.Y = (_localVertices[data.RefVertex].Position.Y - curPos.Y) * 80; //rnd.Y *= curPos.Y > 0 ? 1 : -1; ////Vector3 forceToUse = directedForce * Vector3.Lerp(Vector3.One, rnd * 1.5f, point.DistanceFromParent); //as we get further away from parent, more random //if (Vector3.Distance(_originalPositions[point.VertexIndex], curPos + directedForce) < 0.04f) // _localVertices[point.VertexIndex].Position = curPos + directedForce; } _changed = true; } } if (_changed) { bool tidied = false; foreach (CrushData data2 in _carFile.CrushSections[1].Data) { Vector3 oldpos = _localVertices[data2.RefVertex].Position; _localVertices[data2.RefVertex].Position = KeepCrushPositionInBounds(_localVertices[data2.RefVertex].Position, data2.Box); if (oldpos != _localVertices[data2.RefVertex].Position) { tidied = true; } } if (tidied) { GameConsole.WriteEvent("tidied up"); } for (int i = 0; i < _localVertices.Length; i++) { if (float.IsNaN(_localVertices[i].Position.X) || float.IsNaN(_localVertices[i].Position.Y) || float.IsNaN(_localVertices[i].Position.Z)) { } } } if (hitpoints > 0) { GameConsole.WriteEvent("f: " + Math.Round(forceSize, 4) + ", pts: " + hitpoints); _lastHitPts = hitPoints; } }