private static EventAction <GameEntityModel> .ExecutionDelegate BuildSetGlobalVariable(Storage.GenericParameter parameter) { string variableName = parameter.SafeString(0); int setMode = parameter.SafeInt(1); int numeratorSubjectId = parameter.SafeInt(2); string numeratorVariableName = parameter.SafeString(1); int defaultValue = parameter.SafeInt(3); FixedFloat percentage = (numeratorSubjectId == 0 || defaultValue == 0) ? 1 : ((FixedFloat)defaultValue) / 100; return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ int variableValue = GetNumeratorValue(model, numeratorSubjectId, numeratorVariableName, defaultValue, subjectModels); variableValue = (int)(variableValue * percentage); // Global variable may have references to a team ID, character name, player number, etc numeratorVariableName = CharacterConditionsBuilder.ParseVariableValuesInGlobalName(model, numeratorVariableName); WorldModel worldModel = StateManager.state.MainModel as WorldModel; switch (setMode) { case 1: // add if (worldModel.globalVariables.ContainsKey(variableName)) { worldModel.globalVariables[variableName] += variableValue; } else { worldModel.globalVariables[variableName] = variableValue; } break; default: // set worldModel.globalVariables[variableName] = variableValue; break; } }); }
private static EventAction <GameEntityModel> .ExecutionDelegate BuildGetHurt(Storage.GenericParameter parameter) { int hittersSubjectId = parameter.SafeInt(1); int numeratorSubjectId = parameter.SafeInt(2); string numeratorVariableName = parameter.SafeString(0); int defaultPercentage = parameter.SafeInt(3); int facingOptions = parameter.SafeInt(4); return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ List <GameEntityModel> hitterSubjects = ConditionUtils <GameEntityModel> .GetNonEmptySubjectOrNil(subjectModels, hittersSubjectId); if (hitterSubjects == null || hitterSubjects.Count == 0) { return; } FixedFloat percentage = GetNumeratorValue(model, numeratorSubjectId, numeratorVariableName, defaultPercentage, subjectModels); percentage /= 100; switch (facingOptions) { case -1: // Use hit data GameEntityController.HurtBasedOnHitData(model, percentage, hitterSubjects); break; default: // Use given facing options GameEntityController.HurtBasedOnFacingOptions(model, (HitData.HitFacing)facingOptions, percentage, hitterSubjects); break; } }); }
// 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 }
private static EventAction <GameEntityModel> .ExecutionDelegate BuildSetVariable(Storage.GenericParameter parameter) { string variableName = parameter.SafeString(0); int setMode = parameter.SafeInt(1); int numeratorSubjectId = parameter.SafeInt(2); string numeratorVariableName = parameter.SafeString(1); int defaultValue = parameter.SafeInt(3); FixedFloat percentage = (numeratorSubjectId == 0 || defaultValue == 0) ? 1 : ((FixedFloat)defaultValue) / 100; return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ int variableValue = GetNumeratorValue(model, numeratorSubjectId, numeratorVariableName, defaultValue, subjectModels); variableValue = (int)(variableValue * percentage); switch (setMode) { case 1: // add if (model.customVariables.ContainsKey(variableName)) { model.customVariables[variableName] += variableValue; } else { model.customVariables[variableName] = variableValue; } break; default: // set model.customVariables[variableName] = variableValue; break; } }); }
// Check collisions between physic models, and apply gravity to them public FixedVector3 Raycast(PhysicWorldModel world, FixedVector3 origin, FixedVector3 direction) { // A raycast long enough FixedVector3 target = origin + direction * 99; // Get all planes to check collisions List <PhysicPlaneModel> allPlanes = GetAllPlanes(world); FixedVector3 intersection; // Find closest intersection FixedVector3 closestIntersection = new FixedVector3(FixedFloat.MaxValue, FixedFloat.MaxValue, FixedFloat.MaxValue); FixedFloat closestIntersectionDistance = FixedFloat.MaxValue; foreach (PhysicPlaneModel planeModel in allPlanes) { if (PhysicPlaneController.CheckIntersection(planeModel, origin, target, FixedVector3.Zero, out intersection)) { FixedFloat distance = FixedVector3.Distance(origin, intersection); if (distance < closestIntersectionDistance) { closestIntersectionDistance = distance; closestIntersection = intersection; } } } return(closestIntersection); }
public void Set(FixedFloat x, FixedFloat y, FixedFloat z) { this.x = x; this.y = y; this.z = z; magnitudeIsUpToDate = false; }
public FixedVector3(FixedFloat x, FixedFloat y, FixedFloat z) { this.x = x; this.y = y; this.z = z; magnitude = 0; magnitudeIsUpToDate = false; }
public static FixedVector3 Lerp(FixedVector3 first, FixedVector3 second, FixedFloat blend) { first.Set(first.x + (second.x - first.x) * blend, first.y + (second.y - first.y) * blend, first.z + (second.z - first.z) * blend ); return(first); }
public static FixedVector3 Clamp(FixedVector3 vec, FixedVector3 min, FixedVector3 max) { vec.Set(FixedFloat.Clamp(vec.x, min.x, max.x), FixedFloat.Clamp(vec.y, min.y, max.y), FixedFloat.Clamp(vec.z, min.z, max.z) ); return(vec); }
public static FixedFloat Angle(FixedVector3 from, FixedVector3 to) { if (from.Magnitude == FixedFloat.Zero || to.Magnitude == FixedFloat.Zero) { return(FixedFloat.Zero); } return(FixedFloat.Acos((FixedVector3.Dot(from, to)) / (from.Magnitude * to.Magnitude))); }
// Build a point static FixedVector3 BuildFixedVector3(Storage.GenericParameter parameter, int startFloatIndex = 0) { FixedFloat x = parameter.SafeFloat(startFloatIndex); FixedFloat y = parameter.SafeFloat(startFloatIndex + 1); FixedFloat z = parameter.SafeFloat(startFloatIndex + 2); return(new FixedVector3(x, y, z)); }
private static EventAction <GameEntityModel> .ExecutionDelegate BuildSetMaxInputVelocity(Storage.GenericParameter parameter) { FixedFloat maxX = parameter.SafeFloat(0); FixedFloat maxZ = parameter.SafeFloat(1); return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ model.maxInputVelocity = new FixedVector3(maxX, 0, maxZ); }); }
public static void HurtBasedOnHitData(GameEntityModel model, FixedFloat damagePercentage, List <GameEntityModel> hitterSubjects = null) { GameEntityController controller = model.Controller() as GameEntityController; if (controller.lastHurts.Count > 0) { HitData hitData = controller.lastHurts[0].hitData; HurtBasedOnFacingOptions(model, hitData.facingOptions, damagePercentage, hitterSubjects); } }
public static FixedFloat CollisionZForce(GameEntityModel model) { PhysicPointModel pointModel = GameEntityController.GetPointModel(model); if (pointModel == null) { return(FixedFloat.Zero); } return(FixedFloat.Abs(pointModel.collisionInpact.Z)); }
public static FixedVector3 operator /(FixedVector3 vec, FixedFloat scale) { FixedFloat mult = FixedFloat.One / scale; // if (mult == 0){ // UnityEngine.Debug.Log("Precision error: DIV"); // } vec.Set(vec.x * mult, vec.y * mult, vec.z * mult); return(vec); }
public static FixedVector3 ClampMagnitude(FixedVector3 vec, FixedFloat maxMagnitude) { FixedFloat magnitude = vec.Magnitude; if (magnitude > maxMagnitude) { FixedFloat scaleFactor = magnitude / maxMagnitude; vec *= scaleFactor; } return(vec); }
// Offsets a box, used to apply world coordinates of the entity, and it's orientation private Box OffsettedBox(Box box, FixedVector3 offset, bool facingRight) { FixedVector3 newPos1 = box.pointOne; FixedVector3 newPos2 = box.pointTwo; if (!facingRight) { // swap and make symetric FixedFloat tmp = -newPos1.X; newPos1.X = -newPos2.X; newPos2.X = tmp; } return(new Box(offset + newPos1, offset + newPos2)); }
// CompareWithNumerator, FixedFloat version private static bool CompareWithNumerator( GameEntityModel mainModel, int numeratorSubjectId, string numeratorSubjectVarName, FixedFloat comparisonValue, FixedFloat staticComparisonValue, ConditionUtils <GameEntityModel> .ComparisonOperation comparisonOperator, List <GameEntityModel>[] subjectModels ) { // no subject if (numeratorSubjectId == 0) { return(ConditionUtils <GameEntityModel> .Compare(comparisonOperator, comparisonValue, staticComparisonValue)); } // global variable if (numeratorSubjectId == 1) { // Global variable may have references to a team ID, character name, player number, etc numeratorSubjectVarName = ParseVariableValuesInGlobalName(mainModel, numeratorSubjectVarName); int globalVariableValue = 0; WorldModel worldModel = StateManager.state.MainModel as WorldModel; worldModel.globalVariables.TryGetValue(numeratorSubjectVarName, out globalVariableValue); return(ConditionUtils <GameEntityModel> .Compare(comparisonOperator, comparisonValue, (FixedFloat)globalVariableValue)); } // subject variable numeratorSubjectId -= 2; List <GameEntityModel> comparisonSubject = ConditionUtils <GameEntityModel> .GetNonEmptySubjectOrNil(subjectModels, numeratorSubjectId); if (comparisonSubject == null || comparisonSubject.Count == 0) { return(false); } // compare each model's velocity with each comparison subject variable, return true if all pass int variableValue; foreach (GameEntityModel comparisonModel in comparisonSubject) { if (!comparisonModel.customVariables.TryGetValue(numeratorSubjectVarName, out variableValue)) { return(false); } if (!ConditionUtils <GameEntityModel> .Compare(comparisonOperator, comparisonValue, (FixedFloat)variableValue)) { return(false); } } return(true); }
// 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)); } }
private static EventAction <GameEntityModel> .ExecutionDelegate BuildPausePhysics(Storage.GenericParameter parameter) { int numeratorSubjectId = parameter.SafeInt(1); string numeratorVariableName = parameter.SafeString(0); int defaultValue = parameter.SafeInt(2); FixedFloat percentage = (numeratorSubjectId == 0 || defaultValue == 0) ? 1 : ((FixedFloat)defaultValue) / 100; return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ int numeratorValue = GetNumeratorValue(model, numeratorSubjectId, numeratorVariableName, defaultValue, subjectModels); int pauseValue = (int)(numeratorValue * percentage); if (pauseValue > 0) { GameEntityController.PausePhysics(model, pauseValue); } }); }
// 'walk' private static EventAction <GameEntityModel> .ExecutionDelegate BuildSetAnimation(Storage.GenericParameter parameter) { string animationName = parameter.SafeString(0); FixedFloat transitionTime = parameter.SafeFloat(0); return(delegate(GameEntityModel model, List <GameEntityModel>[] subjectModels){ AnimationModel animModel = StateManager.state.GetModel(model.animationModelId) as AnimationModel; if (animModel == null) { return; } animModel.SetNextAnimation(animationName, 0); AnimationView view = animModel.View() as AnimationView; if (view != null) { view.transitionTime = (float)transitionTime; } }); }
// Auxiliar method to get Oriented Axis private static FixedFloat getOrientedAxisValue(FixedVector3 axis, Orientation orientation, bool useModule) { FixedFloat axisValue = FixedFloat.Zero; switch (orientation) { case Orientation.horizontal: axisValue = axis.X; break; case Orientation.vertical: axisValue = axis.Y; break; case Orientation.z: axisValue = axis.Z; break; case Orientation.any: axisValue = axis.Magnitude; break; } if (useModule) { axisValue = FixedFloat.Abs(axisValue); } return(axisValue); }
// Velocity private static EventCondition <GameEntityModel> .EvaluationDelegate BuildVelocity(Storage.GenericParameter parameter, out int keyFrame, Storage.CharacterAnimation animation) { keyFrame = InvalidKeyframe; // Read orientation, operator, numerator subject, numerator var, number, module Orientation orientation = (Orientation)parameter.SafeInt(1); ConditionUtils <GameEntityModel> .ComparisonOperation comparisonOperator = (ConditionUtils <GameEntityModel> .ComparisonOperation)parameter.SafeInt(2); int numeratorSubjectId = parameter.SafeInt(3); string numeratorSubjectVarName = parameter.SafeString(0); FixedFloat staticComparisonValue = parameter.SafeFloat(0); bool useModule = parameter.SafeBool(1); // return delegate return(delegate(GameEntityModel mainModel, List <GameEntityModel>[] subjectModels){ PhysicPointModel pointModel = StateManager.state.GetModel(mainModel.physicsModelId) as PhysicPointModel; if (pointModel == null) { return false; } FixedFloat velocityValue = getOrientedAxisValue(pointModel.GetVelocity(), orientation, useModule); return CompareWithNumerator(mainModel, numeratorSubjectId, numeratorSubjectVarName, velocityValue, staticComparisonValue, comparisonOperator, subjectModels); }); }
// Compute the intersection point against a line segment public static bool CheckIntersection(PhysicPlaneModel planeModel, FixedVector3 pos1, FixedVector3 pos2, FixedVector3 stepTolerance, out FixedVector3 intersection) { // plane may be moving, sum velocity to initial point position pos1 += planeModel.GetVelocity(); // Check bounding box intersection, including step tolerance if (!BoxIntersection(planeModel, pos1 + stepTolerance, pos2)) { intersection = FixedVector3.Zero; return(false); } // check collision with the hiperplane FixedVector3 pointDeltaPos = pos2 - pos1; if (pointDeltaPos.Magnitude == 0) { // The point is not moving relatively to the plane intersection = FixedVector3.Zero; return(false); } FixedVector3 pos1ToOrigin = planeModel.origin - pos1; FixedFloat dotDeltaPosNormal = FixedVector3.Dot(pointDeltaPos, planeModel.normal); if (dotDeltaPosNormal >= 0) { // Point moving away from the plane intersection = FixedVector3.Zero; return(false); } // Find intersection location in the deltapos vector FixedFloat t = FixedVector3.Dot(pos1ToOrigin, planeModel.normal) / dotDeltaPosNormal; // a small delta due to precision errors // based on deltaPos magnitude (the smaller the magnitude the higher the error) FixedFloat error = 0.01 / pointDeltaPos.Magnitude; if (t < -error) { // falling through the plane, try step tolerance to recover pos1 += stepTolerance; pointDeltaPos = pos2 - pos1; pos1ToOrigin = planeModel.origin - pos1; dotDeltaPosNormal = FixedVector3.Dot(pointDeltaPos, planeModel.normal); t = FixedVector3.Dot(pos1ToOrigin, planeModel.normal) / dotDeltaPosNormal; error = 0.01 / pointDeltaPos.Magnitude; } // give some tolerance if (t < -error || t > 1 + error) { // not colliding intersection = FixedVector3.Zero; return(false); } intersection = pos1 + t * pointDeltaPos; // Check if intersection point is inside the plane FixedFloat anglesSum = FixedFloat.Zero; FixedVector3 originVector = planeModel.origin - intersection; FixedVector3 vec1 = originVector; FixedVector3 vec2 = FixedVector3.Zero; FixedVector3 vertex; for (int i = 0; i < planeModel.offsets.Count; ++i) { vertex = planeModel.GetPointFromOffsetId(i); vec2 = vertex - intersection; anglesSum += FixedVector3.Angle(vec1, vec2); vec1 = vec2; } // last vertex with origin anglesSum += FixedVector3.Angle(vec2, originVector); // a small delta due to precision errors return(FixedFloat.Abs(anglesSum - FixedFloat.TwoPI) < 0.2); }
public FixedFloat NextFloat(FixedFloat min, FixedFloat max) { return(min + NextFloat() * (max - min)); }
// Random Fixed Float between [0, 1] public FixedFloat NextFloat() { // The magic number below is 1/(2^32 + 2). // The result is strictly between 0 and 1. return(FixedFloat.Create((NextUnsignedInt() + 1.0) * 2.328306435454494e-10)); }
public static void HurtBasedOnFacingOptions(GameEntityModel model, HitData.HitFacing facingOptions, FixedFloat damagePercentage, List <GameEntityModel> hitterSubjects = null) { // Facing if (facingOptions == HitData.HitFacing.hitterLocation || facingOptions == HitData.HitFacing.inverseHitterLocation) { FaceToHitterLocation(model, facingOptions == HitData.HitFacing.inverseHitterLocation); } else if (facingOptions == HitData.HitFacing.hitterOrientation || facingOptions == HitData.HitFacing.inverseHitterOrientation) { FaceToHitterDirection(model, facingOptions == HitData.HitFacing.inverseHitterOrientation); } else { // None, nothing to do } // Damage! if (damagePercentage != 0 && model.customVariables.ContainsKey("energy")) { GameEntityController controller = model.Controller() as GameEntityController; foreach (HitInformation hitInfo in controller.lastHurts) { if (hitterSubjects == null || hitterSubjects.Find(x => x.Index == hitInfo.entityId) != null) { int damageValue = (int)(hitInfo.hitData.damage * damagePercentage); if (damageValue == 0) { damageValue = 1; } model.customVariables["energy"] -= damageValue; } } } }