// Add a Physic Plane to the world public void AddPlane(PhysicWorldModel worldModel, OnPlaneModelChanged callback, object context, params FixedVector3[] paramPoints) { PhysicPlaneModel planeModel = new PhysicPlaneModel(paramPoints); addPlaneCallbacks[planeModel] = new Eppy.Tuple <OnPlaneModelChanged, object>(callback, context); StateManager.state.AddModel(planeModel, OnPlaneAdded, worldModel); }
// Delegate for when a plane is removed, it redirects to the caller delegate private void OnPlaneRemoved(Model model, object context) { Eppy.Tuple <OnPlaneModelChanged, object> callbackTuple; PhysicPlaneModel planeModel = model as PhysicPlaneModel; PhysicWorldModel worldModel = context as PhysicWorldModel; if (planeModel == null || worldModel == null) { // Something went wrong! return; } if (removePlaneCallbacks.TryGetValue(planeModel, out callbackTuple)) { if (callbackTuple.Item1 != null) { callbackTuple.Item1(planeModel, callbackTuple.Item2); } removePlaneCallbacks.Remove(planeModel); worldModel.planeModels.Remove(model.Index); } }
// Remove a Physic Plane from the world public void RemovePlane(PhysicWorldModel worldModel, PhysicPlaneModel planeModel, OnPlaneModelChanged callback = null, object context = null) { removePlaneCallbacks[planeModel] = new Eppy.Tuple <OnPlaneModelChanged, object>(callback, context); StateManager.state.RemoveModel(planeModel, OnPlaneRemoved, worldModel); }
// Collision reaction. // Return true if collision is considered stable (no position modifications occured) public virtual bool OnCollision(PhysicWorldModel world, PhysicPointModel pointModel, PhysicPlaneModel planeModel, FixedVector3 intersection) { // if (pointModel.position == intersection){ // // Nothing to change // return true; // } // Pick one of two methods depending on the plane's normal angle against up vector FixedFloat planeAngle = FixedVector3.Angle(planeModel.normal, FixedVector3.Up); // If it's too much inclined, use natural reaction if (planeAngle > FixedFloat.PI * 0.4) { // check direction against 4 walls FixedFloat maxDelta = FixedFloat.PI * 0.4; planeAngle = FixedVector3.Angle(planeModel.normal, FixedVector3.Left); if (planeAngle <= maxDelta || planeAngle >= FixedFloat.PI - maxDelta) { // collision in the X axis FixedFloat inpactX = pointModel.GetVelocity().X - planeModel.GetVelocity().X; if (FixedFloat.Abs(inpactX) > FixedFloat.Abs(newCollisionInpact.X)) { newCollisionInpact.X = inpactX; } } planeAngle = FixedVector3.Angle(planeModel.normal, FixedVector3.Forward); if (planeAngle <= maxDelta || planeAngle >= FixedFloat.PI - maxDelta) { // collision in the Z axis FixedFloat inpactZ = pointModel.GetVelocity().Z - planeModel.GetVelocity().Z; if (FixedFloat.Abs(inpactZ) > FixedFloat.Abs(newCollisionInpact.Z)) { newCollisionInpact.Z = inpactZ; } } return(CollisionNaturalReaction(world, pointModel, planeModel, intersection)); } else { // Otherwise we're hitting the ground, do not slide FixedFloat inpactY = pointModel.GetVelocity().Y - planeModel.GetVelocity().Y; if (FixedFloat.Abs(inpactY) > FixedFloat.Abs(newCollisionInpact.Y)) { newCollisionInpact.Y = inpactY; } // We use a lot of arguments here just to avoid recalculating them return(CollisionGroundReaction(world, pointModel, planeModel, intersection)); } }
// Natural reaction: slide along the plane protected bool CollisionNaturalReaction(PhysicWorldModel world, PhysicPointModel pointModel, PhysicPlaneModel planeModel, FixedVector3 intersection) { bool intersectionChanged = false; if (pointModel.position != intersection) { // Project remaining velocity against the plane FixedVector3 normal = planeModel.normal; FixedVector3 pos1 = pointModel.position; FixedVector3 pos2 = pointModel.position + normal; FixedVector3 pointDeltaPos = pos2 - pos1; FixedVector3 pos1ToOrigin = planeModel.origin - pos1; FixedFloat dotDeltaPosNormal = FixedVector3.Dot(pointDeltaPos, normal); FixedFloat t = FixedVector3.Dot(pos1ToOrigin, normal) / dotDeltaPosNormal; FixedVector3 newIntersection = pos1 + t * pointDeltaPos; if (newIntersection != intersection) { intersection = newIntersection; intersectionChanged = true; } // finally, our new position is the intersection point pointModel.position = intersection; } // in the end, also sum the plane velocity, essential for platforms GainPlaneVelocity(world, pointModel, planeModel); return(!intersectionChanged); // if intersection didn't change, it's considered stable }
// Note: objects over elevators may behave in a weird way if gravity isn't enough to keep them grounded // with increased gravity or slower elevators everything seems smoother protected void KillGravityEffectAgainstPlane(PhysicWorldModel world, PhysicPointModel pointModel, PhysicPlaneModel planeModel) { FixedVector3 normal = planeModel.normal; FixedVector3 defaultVel = pointModel.GetDefaultVelocityAffector(); //FixedVector3 velToAdd = FixedVector3.Zero; if ((world.gravity.X < 0 && defaultVel.X < world.gravity.X && normal.X > 0) || (world.gravity.X > 0 && defaultVel.X > world.gravity.X && normal.X < 0)) { defaultVel.X = world.gravity.X; //velToAdd.X = world.gravity.X - defaultVel.X; } if ((world.gravity.Y < 0 && defaultVel.Y < world.gravity.X && normal.Y > 0) || (world.gravity.Y > 0 && defaultVel.Y > world.gravity.Y && normal.Y < 0)) { defaultVel.Y = world.gravity.Y; //velToAdd.Y = world.gravity.Y - defaultVel.Y; } if ((world.gravity.Z < 0 && defaultVel.Z < world.gravity.Z && normal.Z > 0) || (world.gravity.Z > 0 && defaultVel.Z > world.gravity.Z && normal.Z < 0)) { defaultVel.Z = world.gravity.Z; //velToAdd.Z = world.gravity.Z - defaultVel.Z; } //UnityEngine.Debug.Log("Setting default velocity affector: " + defaultVel); pointModel.velocityAffectors[PhysicPointModel.defaultVelocityAffectorName] = defaultVel; //SetDefaultVelocityAffector(defaultVel); //AddDefaultVelocityAffector(velToAdd); }
protected void GainPlaneVelocity(PhysicWorldModel world, PhysicPointModel pointModel, PhysicPlaneModel planeModel) { FixedVector3 velocityToAdd = planeModel.GetVelocity(); // Only add velocity that doesn't conflict with gravity, otherwise it starts flickering if (velocityToAdd.X > 0 && world.gravity.X < 0 || velocityToAdd.X < 0 && world.gravity.X > 0) { velocityToAdd.X = 0; } if (velocityToAdd.Y > 0 && world.gravity.Y < 0 || velocityToAdd.Y < 0 && world.gravity.Y > 0) { velocityToAdd.Y = 0; } if (velocityToAdd.Z > 0 && world.gravity.Z < 0 || velocityToAdd.Z < 0 && world.gravity.Z > 0) { velocityToAdd.Z = 0; } AddVelocityAffector(pointModel, collisionVelocityAffectorName, velocityToAdd); }