private void HandleNonCarCollision(Vehicle vehicle, NonCar nonCar, Vector3 pos, Vector3 patchnormal, Vector3 normalforce, ContactPairFlag events) { if (nonCar.LastTouchTime + 0.1f > GameEngine.TotalSeconds) { nonCar.LastTouchTime = GameEngine.TotalSeconds; return; } nonCar.LastVehicleToHit = vehicle; if (nonCar.IsAttached) { if (normalforce == Vector3.Zero) { return; } nonCar.Hit = true; float speed = vehicle.Chassis.LastSpeeds.GetMax(); if (speed < 20) { return; } normalforce = Vector3.Normalize(normalforce); Vector3 directedForce = normalforce * speed * vehicle.Config.Mass; float factor = (1 / (nonCar.Config.TorqueRequiredToMove * nonCar.Config.MassWhenAttached)) * 0.005f; nonCar.Rotation.X += -directedForce.X * factor; nonCar.Rotation.Z += directedForce.Z * factor; nonCar.LastTouchTime = GameEngine.TotalSeconds; nonCar.LastForcePosition = pos; nonCar.LastForce = directedForce; //multiply force to match the force generated by hitting a solid wall/barrier etc vehicle.OnCollision(directedForce.Length() * 15, pos, normalforce, true); } else { vehicle.OnCollision(normalforce.Length(), pos, normalforce, false); } nonCar.LastTouchTime = GameEngine.TotalSeconds; }
private void HandleNonCarCollision(Vehicle vehicle, NonCar nonCar, Vector3 pos, Vector3 patchnormal, Vector3 normalforce, ContactPairFlag events) { if (nonCar.LastTouchTime + 0.1f > Engine.TotalSeconds) { nonCar.LastTouchTime = Engine.TotalSeconds; return; } nonCar.LastVehicleToHit = vehicle; if (nonCar.IsAttached) { if (normalforce == Vector3.Zero) return; nonCar.Hit = true; float speed = vehicle.Chassis.LastSpeeds.GetMax(); if (speed < 20) return; normalforce = Vector3.Normalize(normalforce); Vector3 directedForce = normalforce * speed * vehicle.Config.Mass; float factor = (1 / (nonCar.Config.TorqueRequiredToMove * nonCar.Config.MassWhenAttached)) * 0.005f; nonCar.Rotation.X += -directedForce.X * factor; nonCar.Rotation.Z += directedForce.Z * factor; nonCar.LastTouchTime = Engine.TotalSeconds; nonCar.LastForcePosition = pos; nonCar.LastForce = directedForce; //multiply force to match the force generated by hitting a solid wall/barrier etc vehicle.OnCollision(directedForce.Length() * 15, pos, normalforce, true); } else { vehicle.OnCollision(normalforce.Length(), pos, normalforce, false); } nonCar.LastTouchTime = Engine.TotalSeconds; }
public override void OnTrigger(Shape triggerShape, Shape otherShape, TriggerFlag status) { if (otherShape.Actor.UserData is Vehicle) { Vehicle vehicle = (Vehicle)otherShape.Actor.UserData; if (otherShape.Name != PhysXConsts.VehicleBody) { return; } if (triggerShape.Actor.UserData is Checkpoint) { if (vehicle.Driver is PlayerDriver) { Checkpoint checkpoint = (Checkpoint)triggerShape.Actor.UserData; Race.Current.OnCheckpointHit(checkpoint); } } else if (triggerShape.Actor.UserData is SpecialVolume) { if (status == TriggerFlag.OnEnter) { Race.Current.OnVehicleEnterSpecVol((SpecialVolume)triggerShape.Actor.UserData, vehicle); } else if (status == TriggerFlag.OnLeave) { Race.Current.OnVehicleExitSpecVol((SpecialVolume)triggerShape.Actor.UserData, vehicle); } } else if (triggerShape.Actor.UserData is Pedestrian) { Race.Current.OnPedestrianHit((Pedestrian)triggerShape.Actor.UserData, vehicle); } } else if (otherShape.Actor.UserData is NonCar) { NonCar noncar = otherShape.Actor.UserData as NonCar; // if the trigger is a noncar that was hit within 7 seconds if (triggerShape.Actor.UserData is Pedestrian && noncar.LastTouchTime + 7f > GameEngine.TotalSeconds) { Pedestrian ped = (Pedestrian)triggerShape.Actor.UserData; if (!ped.IsHit) { if (noncar.LastVehicleToHit != null) { Race.Current.OnPedestrianHit(ped, noncar.LastVehicleToHit); if (noncar.LastVehicleToHit.Driver is PlayerDriver) { if (GameVars.Emulation == EmulationMode.Demo) // billiard.pix doesn't exist in c1 demo { MessageRenderer.Instance.PostHeaderMessage("Nice shot, sir!", 3); } else { MessageRenderer.Instance.PostMainMessage("billiard.pix", 3, 0.7f, 0.003f, 1.4f); } } } } } } }
public static NonCar GenerateNonCar(CActor actor, List <NoncarFile> nonCars) { if (actor.Model == null) { return(null); } if (actor.Name.StartsWith("&")) { int index = int.Parse(actor.Name.Substring(1, 2)); NoncarFile nonCarFile = nonCars.Find(a => a.IndexNumber == index); if (nonCarFile == null) { Debug.WriteLine("No noncar matching " + actor.Name); return(null); } ActorDescription actorDesc = new ActorDescription(); actorDesc.BodyDescription = new BodyDescription() { Mass = nonCarFile.Mass }; BoxShapeDescription boxDesc = new BoxShapeDescription(); boxDesc.Size = nonCarFile.BoundingBox.GetSize(); boxDesc.LocalPosition = nonCarFile.BoundingBox.GetCenter(); actorDesc.Shapes.Add(boxDesc); foreach (Vector3 extraPoint in nonCarFile.ExtraBoundingBoxPoints) { SphereShapeDescription extra = new SphereShapeDescription(0.2f); extra.LocalPosition = extraPoint; extra.Mass = 0; actorDesc.Shapes.Add(extra); } Vector3 scaleout, transout; Quaternion b; bool success = actor.Matrix.Decompose(out scaleout, out b, out transout); //if (!success) throw new Exception(); Matrix m = Matrix.CreateFromQuaternion(b) * Matrix.CreateTranslation(transout); StillDesign.PhysX.Actor instance = PhysX.Instance.Scene.CreateActor(actorDesc); instance.GlobalPose = m; instance.SetCenterOfMassOffsetLocalPosition(nonCarFile.CenterOfMass); instance.Group = PhysXConsts.NonCarId; //foreach (Shape s in instance.Shapes) // s.SetFlag(ShapeFlag.Visualization, false); NonCar noncar = new NonCar { Config = nonCarFile, CActor = actor }; instance.UserData = noncar; actor.AttachToPhysX(instance); if (nonCarFile.BendAngleBeforeSnapping > 0) { noncar.AttachToGround(); } instance.Sleep(); return(noncar); } else { return(null); } }
public static Actor GenerateTrackActor(RaceFile file, CActorHierarchy actors, out List <NonCar> nonCarInstances) { List <Vector3> verts = new List <Vector3>(); List <ushort> indices = new List <ushort>(); List <ushort> materialIndices = new List <ushort>(); List <OpenC1.CActor> actorsList = actors.All(); nonCarInstances = new List <NonCar>(); for (int i = 0; i < actorsList.Count; i++) { CActor actor = actorsList[i]; if (actor.Model == null) { continue; } if (actor.Name.StartsWith("&")) { if (Char.IsDigit(actor.Name[1]) && Char.IsDigit(actor.Name[2])) { NonCar nc = GenerateNonCar(actor, file.NonCars); if (nc != null) { nonCarInstances.Add(nc); continue; //dont-merge with track } } } int baseIndex = verts.Count; for (int j = 0; j < actor.Model.VertexCount; j++) { verts.Add(Vector3.Zero); } foreach (Polygon poly in actor.Model.Polygons) { if (poly.MaterialIndex < 0) { continue; } string materialName = actor.Model.MaterialNames == null ? "none" : actor.Model.MaterialNames[poly.MaterialIndex]; //this is a non-solid material if (materialName.StartsWith("!")) { continue; } int index = baseIndex + poly.Vertex1; indices.Add((ushort)index); if (verts[index] == Vector3.Zero) { Vector3 transformedVec = Vector3.Transform(actors.Models._vertexPositions[actor.Model.VertexBaseIndex + poly.Vertex1], actor.Matrix); verts[index] = transformedVec; } index = baseIndex + poly.Vertex2; indices.Add((ushort)index); if (verts[index] == Vector3.Zero) { Vector3 transformedVec = Vector3.Transform(actors.Models._vertexPositions[actor.Model.VertexBaseIndex + poly.Vertex2], actor.Matrix); verts[index] = transformedVec; } index = baseIndex + poly.Vertex3; indices.Add((ushort)index); if (verts[index] == Vector3.Zero) { Vector3 transformedVec = Vector3.Transform(actors.Models._vertexPositions[actor.Model.VertexBaseIndex + poly.Vertex3], actor.Matrix); verts[index] = transformedVec; } if (Char.IsDigit(materialName[0])) { ushort matModiferId = (ushort)(ushort.Parse(materialName.Substring(0, 1)) + 1); if (matModiferId >= file.MaterialModifiers.Count) { matModiferId = 0; } materialIndices.Add(matModiferId); } else { materialIndices.Add(0); } } } TriangleMeshDescription meshDesc = new TriangleMeshDescription(); meshDesc.TriangleCount = indices.Count / 3; meshDesc.VertexCount = verts.Count; meshDesc.AllocateVertices <Vector3>(meshDesc.VertexCount); meshDesc.AllocateTriangles <ushort>(meshDesc.TriangleCount); meshDesc.AllocateMaterialIndices <ushort>(materialIndices.Count); meshDesc.TriangleStream.SetData(indices.ToArray()); meshDesc.VerticesStream.SetData(verts.ToArray()); meshDesc.MaterialIndicesStream.SetData(materialIndices.ToArray()); meshDesc.Flags = MeshFlag.Indices16Bit; MemoryStream s = new MemoryStream(); Cooking.InitializeCooking(); Cooking.CookTriangleMesh(meshDesc, s); Cooking.CloseCooking(); s.Position = 0; TriangleMesh triangleMesh = PhysX.Instance.Core.CreateTriangleMesh(s); TriangleMeshShapeDescription shape = new TriangleMeshShapeDescription() { TriangleMesh = triangleMesh, }; ActorDescription actorDescription = new ActorDescription() { GlobalPose = Matrix.CreateTranslation(0, 0, 0), Shapes = { shape } }; foreach (Checkpoint checkpoint in file.Checkpoints) { ActorDescription actorDesc = new ActorDescription(); BoxShapeDescription box = new BoxShapeDescription(checkpoint.BBox.GetSize()); box.Flags = ShapeFlag.TriggerOnEnter | ShapeFlag.Visualization; actorDesc.Shapes.Add(box); Actor actor = PhysX.Instance.Scene.CreateActor(actorDesc); actor.GlobalPosition = checkpoint.BBox.GetCenter(); actor.UserData = checkpoint; } StillDesign.PhysX.Actor environment = PhysX.Instance.Scene.CreateActor(actorDescription); environment.Group = PhysXConsts.TrackId; environment.Shapes[0].SetFlag(ShapeFlag.Visualization, false); CreateDefaultWaterSpecVols(file, actorsList, actors.Models); for (int i = 1; i < file.SpecialVolumes.Count; i++) { SpecialVolume vol = file.SpecialVolumes[i]; Vector3 scale = new Vector3(); Vector3 trans = new Vector3(); Quaternion q = new Quaternion(); Matrix matrix = vol.Matrix; bool success = matrix.Decompose(out scale, out q, out trans); if (scale.Z == 0) { scale.Z = 0.1f; } ActorDescription actorDesc = new ActorDescription(); BoxShapeDescription box = new BoxShapeDescription(scale); if (success) { if (float.IsNaN(q.X)) { continue; } box.LocalRotation = Matrix.CreateFromQuaternion(q); } else { //if the matrix cannot be decomposed, like part of the long tunnel in coasta... // get the rotation by calculating some points and working out rotation from them Vector3 v1 = Vector3.Transform(new Vector3(-1, -1, 1), matrix); Vector3 v2 = Vector3.Transform(new Vector3(-1, 1, -1), matrix); Vector3 forwards = v2 - v1; forwards.Normalize(); box.LocalRotation = Matrix.CreateWorld(Vector3.Zero, forwards, Vector3.Up); } box.Flags = ShapeFlag.TriggerOnEnter | ShapeFlag.TriggerOnLeave | ShapeFlag.Visualization; actorDesc.Shapes.Add(box); Actor actor = PhysX.Instance.Scene.CreateActor(actorDesc); actor.GlobalPosition = vol.Matrix.Translation; actor.UserData = vol; } return(environment); }
public static NonCar GenerateNonCar(CActor actor, List<NoncarFile> nonCars) { if (actor.Model == null) return null; if (actor.Name.StartsWith("&")) { int index = int.Parse(actor.Name.Substring(1, 2)); NoncarFile nonCarFile = nonCars.Find(a => a.IndexNumber == index); if (nonCarFile == null) { Debug.WriteLine("No noncar matching " + actor.Name); return null; } ActorDescription actorDesc = new ActorDescription(); actorDesc.BodyDescription = new BodyDescription() { Mass = nonCarFile.Mass }; BoxShapeDescription boxDesc = new BoxShapeDescription(); boxDesc.Size = nonCarFile.BoundingBox.GetSize(); boxDesc.LocalPosition = nonCarFile.BoundingBox.GetCenter(); actorDesc.Shapes.Add(boxDesc); foreach (Vector3 extraPoint in nonCarFile.ExtraBoundingBoxPoints) { SphereShapeDescription extra = new SphereShapeDescription(0.2f); extra.LocalPosition = extraPoint; extra.Mass = 0; actorDesc.Shapes.Add(extra); } Vector3 scaleout, transout; Quaternion b; bool success = actor.Matrix.Decompose(out scaleout, out b, out transout); //if (!success) throw new Exception(); Matrix m = Matrix.CreateFromQuaternion(b) * Matrix.CreateTranslation(transout); StillDesign.PhysX.Actor instance = PhysX.Instance.Scene.CreateActor(actorDesc); instance.GlobalPose = m; instance.SetCenterOfMassOffsetLocalPosition(nonCarFile.CenterOfMass); instance.Group = PhysXConsts.NonCarId; //foreach (Shape s in instance.Shapes) // s.SetFlag(ShapeFlag.Visualization, false); NonCar noncar = new NonCar { Config = nonCarFile, CActor = actor }; instance.UserData = noncar; actor.AttachToPhysX(instance); if (nonCarFile.BendAngleBeforeSnapping > 0) { noncar.AttachToGround(); } instance.Sleep(); return noncar; } else { return null; } }