/// <summary> /// SupportMapping. Finds the point in the shape furthest away from the given direction. /// Imagine a plane with a normal in the search direction. Now move the plane along the normal /// until the plane does not intersect the shape. The last intersection point is the result. /// </summary> /// <param name="direction">The direction.</param> /// <param name="result">The result.</param> public override void SupportMapping(ref JVector direction, out JVector result) { result = direction; result.Normalize(); JVector.Multiply(ref result, radius, out result); }
/// <summary> /// Normalizes the given vector. /// </summary> /// <param name="value">The vector which should be normalized.</param> /// <returns>A normalized vector.</returns> #region public static JVector Normalize(JVector value) public static JVector Normalize(JVector value) { JVector result; JVector.Normalize(ref value, out result); return(result); }
/// <summary> /// Initializes a new instance of the HingeJoint class. /// </summary> /// <param name="world">The world class where the constraints get added to.</param> /// <param name="body1">The first body connected to the second one.</param> /// <param name="body2">The second body connected to the first one.</param> /// <param name="position">The position in world space where both bodies get connected.</param> /// <param name="hingeAxis">The axis if the hinge.</param> public LimitedHingeJoint(World world, RigidBody body1, RigidBody body2, JVector position, JVector hingeAxis, float hingeFwdAngle, float hingeBckAngle) : base(world) { // Create the hinge first, two point constraints worldPointConstraint = new PointOnPoint[2]; hingeAxis *= 0.5f; JVector pos1 = position; JVector.Add(ref pos1, ref hingeAxis, out pos1); JVector pos2 = position; JVector.Subtract(ref pos2, ref hingeAxis, out pos2); worldPointConstraint[0] = new PointOnPoint(body1, body2, pos1); worldPointConstraint[1] = new PointOnPoint(body1, body2, pos2); // Now the limit, one max distance constraint hingeAxis.Normalize(); // choose a direction that is perpendicular to the hinge JVector perpDir = JVector.Up; if (JVector.Dot(perpDir, hingeAxis) > 0.1f) perpDir = JVector.Right; // now make it perpendicular to the hinge JVector sideAxis = JVector.Cross(hingeAxis, perpDir); perpDir = JVector.Cross(sideAxis, hingeAxis); perpDir.Normalize(); // the length of the "arm" TODO take this as a parameter? what's // the effect of changing it? float len = 10.0f * 3; // Choose a position using that dir. this will be the anchor point // for body 0. relative to hinge JVector hingeRelAnchorPos0 = perpDir * len; // anchor point for body 2 is chosen to be in the middle of the // angle range. relative to hinge float angleToMiddle = 0.5f * (hingeFwdAngle - hingeBckAngle); JVector hingeRelAnchorPos1 = JVector.Transform(hingeRelAnchorPos0, JMatrix.CreateFromAxisAngle(hingeAxis, -angleToMiddle / 360.0f * 2.0f * JMath.Pi)); // work out the "string" length float hingeHalfAngle = 0.5f * (hingeFwdAngle + hingeBckAngle); float allowedDistance = len * 2.0f * (float)System.Math.Sin(hingeHalfAngle * 0.5f / 360.0f * 2.0f * JMath.Pi); JVector hingePos = body1.Position; JVector relPos0c = hingePos + hingeRelAnchorPos0; JVector relPos1c = hingePos + hingeRelAnchorPos1; distance = new PointPointDistance(body1, body2, relPos0c, relPos1c); distance.Distance = allowedDistance; distance.Behavior = PointPointDistance.DistanceBehavior.LimitMaximumDistance; }
public void HandleInput(GameTime gameTime) { currentTime += (float)gameTime.ElapsedGameTime.Milliseconds; KeyboardState keys = Keyboard.GetState(); if (keys.IsKeyDown(Keys.Up)) { float x = (float)Math.Sin(facing); float z = (float)Math.Cos(facing); JVector newPath = new JVector(x, 0f, z) * speed; newPath = newPath * currentTime; newPath.Normalize(); forward = newPath; body.AddForce(newPath*100f); //position = body.Position; //position += newPath; //body.Position = position; } if (keys.IsKeyDown(Keys.Left)) { facing -= 0.05f; } if (keys.IsKeyDown(Keys.Right)) { facing += 0.05f; } if (keys.IsKeyDown(Keys.Down)) { float x = (float)Math.Sin(facing); float z = (float)Math.Cos(facing); JVector newPath = new JVector(x, 0f, z) * speed; newPath = newPath * currentTime; newPath.Normalize(); body.AddForce(newPath * -100f); } if (keys.IsKeyDown(Keys.Space)) { body.AddForce(JVector.Up * 100f); } /*if (keys.IsKeyDown(Keys.A)) if (keys.IsKeyDown(Keys.S)) if (keys.IsKeyDown(Keys.W)) */ }
public override void Think (PhysicsComponent ownPhysics, HealthComponent ownHealth, object map, List<Entity> entitiesNearby) { Maze.Maze maze = map as Maze.Maze; if (maze != null && maze.HasFinished) { RigidBody rigidBody; JVector normal, temp_direction, old_direction = direction; float fraction; const int res_over_two = resolution / 2; direction = JVector.Zero; for (int i = -res_over_two; i <= res_over_two; i++) { temp_direction = JVector.Transform (old_direction, JMatrix.CreateFromAxisAngle (JVector.Up, i / res_over_two * MathHelper.PiOver4)); ownPhysics.World.CollisionSystem.Raycast ( ownPhysics.RigidBody.Position, temp_direction, new Jitter.Collision.RaycastCallback((rb, n, f) => { var e = rb.Tag as Entity; return f < max_distance && e != null && (e.HasComponent<WallComponent>() || e.Name.Contains("exit")); }), out rigidBody, out normal, out fraction); if (rigidBody != null) { var diff = ownPhysics.RigidBody.Position - rigidBody.Position; diff = new JVector (diff.X, 0, diff.Z); diff.Normalize(); direction += diff * (max_distance - fraction); } else { direction += temp_direction * max_distance; } } if (direction.Length() > 0.1) direction.Normalize(); else { fallback = JVector.Transform (fallback, JMatrix.CreateFromAxisAngle (JVector.Up, MathHelper.PiOver6)); direction = fallback; } if (ownPhysics.RigidBody.Position.X > maze.Size.X * 8) direction = new JVector ((maze.Size.X * 8) - ownPhysics.RigidBody.Position.X, 0, direction.Z); else if (ownPhysics.RigidBody.Position.X < 0) direction = new JVector (0 - ownPhysics.RigidBody.Position.X, 0, direction.Z); if (ownPhysics.RigidBody.Position.Z > maze.Size.Y * 8) direction = new JVector (direction.X, 0, (maze.Size.Y * 8) - ownPhysics.RigidBody.Position.Z); else if (ownPhysics.RigidBody.Position.Z < 0) direction = new JVector (direction.X, 0, 0 - ownPhysics.RigidBody.Position.Z); if (ownPhysics.RigidBody.LinearVelocity.Length() < speed) ownPhysics.RigidBody.LinearVelocity += (direction * acceleration); ownPhysics.RigidBody.Position = new JVector (ownPhysics.RigidBody.Position.X, height, ownPhysics.RigidBody.Position.Z); var player = entitiesNearby.FirstOrDefault (e => e.Name == "player"); if (player != null && gameState.Scene.CameraManager.ActiveCamera != null) { do_reset = true; var player_pos = player.GetComponent<TransformComponent>().Position; var ghost_pos = ownPhysics.RigidBody.Position.ToFreezingArcherVector(); float distance; Vector3.Distance(ref player_pos, ref ghost_pos, out distance); float fov = ((AIcomp.MaximumEntityDistance - distance) / AIcomp.MaximumEntityDistance); if (fov >= 0.5f) { var player_health = player.GetComponent<HealthComponent> (); player_health.Health += player_health.MaximumHealth * 0.05f; } } else if (do_reset) { do_reset = false; } } }
/// <summary> /// Checks two shapes for collisions. /// </summary> /// <param name="support1">The SupportMappable implementation of the first shape to test.</param> /// <param name="support2">The SupportMappable implementation of the seconds shape to test.</param> /// <param name="orientation1">The orientation of the first shape.</param> /// <param name="orientation2">The orientation of the second shape.</param> /// <param name="position1">The position of the first shape.</param> /// <param name="position2">The position of the second shape</param> /// <param name="point">The pointin world coordinates, where collision occur.</param> /// <param name="normal">The normal pointing from body2 to body1.</param> /// <param name="penetration">Estimated penetration depth of the collision.</param> /// <returns>Returns true if there is a collision, false otherwise.</returns> public static bool Detect(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector point, out JVector normal, out double penetration) { // Used variables JVector temp1, temp2; JVector v01, v02, v0; JVector v11, v12, v1; JVector v21, v22, v2; JVector v31, v32, v3; JVector v41, v42, v4; JVector mn; // Initialization of the output point = normal = JVector.Zero; penetration = 0.0f; //JVector right = JVector.Right; // Get the center of shape1 in world coordinates -> v01 support1.SupportCenter(out v01); JVector.Transform(ref v01, ref orientation1, out v01); JVector.Add(ref position1, ref v01, out v01); // Get the center of shape2 in world coordinates -> v02 support2.SupportCenter(out v02); JVector.Transform(ref v02, ref orientation2, out v02); JVector.Add(ref position2, ref v02, out v02); // v0 is the center of the minkowski difference JVector.Subtract(ref v02, ref v01, out v0); // Avoid case where centers overlap -- any direction is fine in this case if (v0.IsNearlyZero()) v0 = new JVector(0.00001f, 0, 0); // v1 = support in direction of origin mn = v0; JVector.Negate(ref v0, out normal); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v11); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v12); JVector.Subtract(ref v12, ref v11, out v1); if (JVector.Dot(ref v1, ref normal) <= 0.0f) return false; // v2 = support perpendicular to v1,v0 JVector.Cross(ref v1, ref v0, out normal); if (normal.IsNearlyZero()) { JVector.Subtract(ref v1, ref v0, out normal); normal.Normalize(); point = v11; JVector.Add(ref point, ref v12, out point); JVector.Multiply(ref point, 0.5f, out point); JVector.Subtract(ref v12, ref v11, out temp1); penetration = JVector.Dot(ref temp1, ref normal); //point = v11; //point2 = v12; return true; } JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v21); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v22); JVector.Subtract(ref v22, ref v21, out v2); if (JVector.Dot(ref v2, ref normal) <= 0.0f) return false; // Determine whether origin is on + or - side of plane (v1,v0,v2) JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); double dist = JVector.Dot(ref normal, ref v0); // If the origin is on the - side of the plane, reverse the direction of the plane if (dist > 0.0f) { JVector.Swap(ref v1, ref v2); JVector.Swap(ref v11, ref v21); JVector.Swap(ref v12, ref v22); JVector.Negate(ref normal, out normal); } int phase2 = 0; int phase1 = 0; bool hit = false; // Phase One: Identify a portal while (true) { if (phase1 > MaximumIterations) return false; phase1++; // Obtain the support point in a direction perpendicular to the existing plane // Note: This point is guaranteed to lie off the plane JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v31); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v32); JVector.Subtract(ref v32, ref v31, out v3); if (JVector.Dot(ref v3, ref normal) <= 0.0f) { return false; } // If origin is outside (v1,v0,v3), then eliminate v2 and loop JVector.Cross(ref v1, ref v3, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v2 = v3; v21 = v31; v22 = v32; JVector.Subtract(ref v1, ref v0, out temp1); JVector.Subtract(ref v3, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // If origin is outside (v3,v0,v2), then eliminate v1 and loop JVector.Cross(ref v3, ref v2, out temp1); if (JVector.Dot(ref temp1, ref v0) < 0.0f) { v1 = v3; v11 = v31; v12 = v32; JVector.Subtract(ref v3, ref v0, out temp1); JVector.Subtract(ref v2, ref v0, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); continue; } // Phase Two: Refine the portal // We are now inside of a wedge... while (true) { phase2++; // Compute normal of the wedge face JVector.Subtract(ref v2, ref v1, out temp1); JVector.Subtract(ref v3, ref v1, out temp2); JVector.Cross(ref temp1, ref temp2, out normal); // Can this happen??? Can it be handled more cleanly? if (normal.IsNearlyZero()) return true; normal.Normalize(); // Compute distance from origin to wedge face double d = JVector.Dot(ref normal, ref v1); // If the origin is inside the wedge, we have a hit if (d >= 0 && !hit) { // HIT!!! hit = true; } // Find the support point in the direction of the wedge face JVector.Negate(ref normal, out mn); SupportMapTransformed(support1, ref orientation1, ref position1, ref mn, out v41); SupportMapTransformed(support2, ref orientation2, ref position2, ref normal, out v42); JVector.Subtract(ref v42, ref v41, out v4); JVector.Subtract(ref v4, ref v3, out temp1); double delta = JVector.Dot(ref temp1, ref normal); penetration = JVector.Dot(ref v4, ref normal); // If the boundary is thin enough or the origin is outside the support plane for the newly discovered vertex, then we can terminate if (delta <= CollideEpsilon || penetration <= 0.0f || phase2 > MaximumIterations) { if (hit) { JVector.Cross(ref v1, ref v2, out temp1); double b0 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v3, ref v2, out temp1); double b1 = JVector.Dot(ref temp1, ref v0); JVector.Cross(ref v0, ref v1, out temp1); double b2 = JVector.Dot(ref temp1, ref v3); JVector.Cross(ref v2, ref v1, out temp1); double b3 = JVector.Dot(ref temp1, ref v0); double sum = b0 + b1 + b2 + b3; if (sum <= 0) { b0 = 0; JVector.Cross(ref v2, ref v3, out temp1); b1 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v3, ref v1, out temp1); b2 = JVector.Dot(ref temp1, ref normal); JVector.Cross(ref v1, ref v2, out temp1); b3 = JVector.Dot(ref temp1, ref normal); sum = b1 + b2 + b3; } double inv = 1.0f / sum; JVector.Multiply(ref v01, b0, out point); JVector.Multiply(ref v11, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v21, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v31, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v02, b0, out temp2); JVector.Add(ref temp2, ref point, out point); JVector.Multiply(ref v12, b1, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v22, b2, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref v32, b3, out temp1); JVector.Add(ref point, ref temp1, out point); JVector.Multiply(ref point, inv * 0.5f, out point); } // Compute the barycentric coordinates of the origin return hit; } //// Compute the tetrahedron dividing face (v4,v0,v1) //JVector.Cross(ref v4, ref v1, out temp1); //double d1 = JVector.Dot(ref temp1, ref v0); //// Compute the tetrahedron dividing face (v4,v0,v2) //JVector.Cross(ref v4, ref v2, out temp1); //double d2 = JVector.Dot(ref temp1, ref v0); // Compute the tetrahedron dividing face (v4,v0,v3) JVector.Cross(ref v4, ref v0, out temp1); double dot = JVector.Dot(ref temp1, ref v1); if (dot >= 0.0f) { dot = JVector.Dot(ref temp1, ref v2); if (dot >= 0.0f) { // Inside d1 & inside d2 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } else { // Inside d1 & outside d2 ==> eliminate v3 v3 = v4; v31 = v41; v32 = v42; } } else { dot = JVector.Dot(ref temp1, ref v3); if (dot >= 0.0f) { // Outside d1 & inside d3 ==> eliminate v2 v2 = v4; v21 = v41; v22 = v42; } else { // Outside d1 & outside d3 ==> eliminate v1 v1 = v4; v11 = v41; v12 = v42; } } } } }
/// <summary> /// Initializes a contact. /// </summary> /// <param name="body1">The first body.</param> /// <param name="body2">The second body.</param> /// <param name="point1">The collision point in worldspace</param> /// <param name="point2">The collision point in worldspace</param> /// <param name="n">The normal pointing to body2.</param> /// <param name="penetration">The estimated penetration depth.</param> public void Initialize(RigidBody body1, RigidBody body2, ref JVector point1, ref JVector point2, ref JVector n, double penetration, bool newContact, ContactSettings settings) { this.body1 = body1; this.body2 = body2; this.normal = n; normal.Normalize(); this.p1 = point1; this.p2 = point2; this.newContact = newContact; JVector.Subtract(ref p1, ref body1.position, out relativePos1); JVector.Subtract(ref p2, ref body2.position, out relativePos2); JVector.Transform(ref relativePos1, ref body1.invOrientation, out realRelPos1); JVector.Transform(ref relativePos2, ref body2.invOrientation, out realRelPos2); this.initialPen = penetration; this.penetration = penetration; body1IsMassPoint = body1.isParticle; body2IsMassPoint = body2.isParticle; // Material Properties if (newContact) { treatBody1AsStatic = body1.isStatic; treatBody2AsStatic = body2.isStatic; accumulatedNormalImpulse = 0.0f; accumulatedTangentImpulse = 0.0f; lostSpeculativeBounce = 0.0f; switch (settings.MaterialCoefficientMixing) { case ContactSettings.MaterialCoefficientMixingType.TakeMaximum: staticFriction = JMath.Max(body1.material.staticFriction, body2.material.staticFriction); dynamicFriction = JMath.Max(body1.material.kineticFriction, body2.material.kineticFriction); restitution = JMath.Max(body1.material.restitution, body2.material.restitution); break; case ContactSettings.MaterialCoefficientMixingType.TakeMinimum: staticFriction = JMath.Min(body1.material.staticFriction, body2.material.staticFriction); dynamicFriction = JMath.Min(body1.material.kineticFriction, body2.material.kineticFriction); restitution = JMath.Min(body1.material.restitution, body2.material.restitution); break; case ContactSettings.MaterialCoefficientMixingType.UseAverage: staticFriction = (body1.material.staticFriction + body2.material.staticFriction) / 2.0f; dynamicFriction = (body1.material.kineticFriction + body2.material.kineticFriction) / 2.0f; restitution = (body1.material.restitution + body2.material.restitution) / 2.0f; break; } } this.settings = settings; }
public static bool ClosestPoints(ISupportMappable support1, ISupportMappable support2, ref JMatrix orientation1, ref JMatrix orientation2, ref JVector position1, ref JVector position2, out JVector p1, out JVector p2, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); p1 = p2 = JVector.Zero; JVector r = position1 - position2; JVector w, v; JVector supVertexA; JVector rn,vn; rn = JVector.Negate(r); SupportMapTransformed(support1, ref orientation1, ref position1, ref rn, out supVertexA); JVector supVertexB; SupportMapTransformed(support2, ref orientation2, ref position2, ref r, out supVertexB); v = supVertexA - supVertexB; normal = JVector.Zero; int maxIter = 15; float distSq = v.LengthSquared(); float epsilon = 0.00001f; while ((distSq > epsilon) && (maxIter-- != 0)) { vn = JVector.Negate(v); SupportMapTransformed(support1, ref orientation1, ref position1, ref vn, out supVertexA); SupportMapTransformed(support2, ref orientation2, ref position2, ref v, out supVertexB); w = supVertexA - supVertexB; if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, supVertexA, supVertexB); if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); normal = v; } else distSq = 0.0f; } simplexSolver.ComputePoints(out p1, out p2); if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) normal.Normalize(); simplexSolverPool.GiveBack(simplexSolver); return true; }
// see: btSubSimplexConvexCast.cpp /// <summary> /// Checks if a ray definied through it's origin and direction collides /// with a shape. /// </summary> /// <param name="support">The supportmap implementation representing the shape.</param> /// <param name="orientation">The orientation of the shape.</param> /// <param name="invOrientation">The inverse orientation of the shape.</param> /// <param name="position">The position of the shape.</param> /// <param name="origin">The origin of the ray.</param> /// <param name="direction">The direction of the ray.</param> /// <param name="fraction">The fraction which gives information where at the /// ray the collision occured. The hitPoint is calculated by: origin+friction*direction.</param> /// <param name="normal">The normal from the ray collision.</param> /// <returns>Returns true if the ray hit the shape, false otherwise.</returns> public static bool Raycast(ISupportMappable support, ref JMatrix orientation, ref JMatrix invOrientation, ref JVector position,ref JVector origin,ref JVector direction, out float fraction, out JVector normal) { VoronoiSimplexSolver simplexSolver = simplexSolverPool.GetNew(); simplexSolver.Reset(); normal = JVector.Zero; fraction = float.MaxValue; float lambda = 0.0f; JVector r = direction; JVector x = origin; JVector w, p, v; JVector arbitraryPoint; SupportMapTransformed(support, ref orientation, ref position, ref r, out arbitraryPoint); JVector.Subtract(ref x, ref arbitraryPoint, out v); int maxIter = MaxIterations; float distSq = v.LengthSquared(); float epsilon = 0.000001f; float VdotR; while ((distSq > epsilon) && (maxIter-- != 0)) { SupportMapTransformed(support, ref orientation, ref position, ref v, out p); JVector.Subtract(ref x, ref p, out w); float VdotW = JVector.Dot(ref v, ref w); if (VdotW > 0.0f) { VdotR = JVector.Dot(ref v, ref r); if (VdotR >= -JMath.Epsilon) { simplexSolverPool.GiveBack(simplexSolver); return false; } else { lambda = lambda - VdotW / VdotR; JVector.Multiply(ref r, lambda, out x); JVector.Add(ref origin, ref x, out x); JVector.Subtract(ref x, ref p, out w); normal = v; } } if (!simplexSolver.InSimplex(w)) simplexSolver.AddVertex(w, x, p); if (simplexSolver.Closest(out v)) { distSq = v.LengthSquared(); } else distSq = 0.0f; } #region Retrieving hitPoint // Giving back the fraction like this *should* work // but is inaccurate against large objects: // fraction = lambda; JVector p1, p2; simplexSolver.ComputePoints(out p1, out p2); p2 = p2 - origin; fraction = p2.Length() / direction.Length(); #endregion if (normal.LengthSquared() > JMath.Epsilon * JMath.Epsilon) normal.Normalize(); simplexSolverPool.GiveBack(simplexSolver); return true; }
public override void Think (PhysicsComponent ownPhysics, HealthComponent ownHealth, object map, List<Entity> entitiesNearby) { Maze.Maze maze = map as Maze.Maze; if (maze != null && maze.HasFinished) { RigidBody rigidBody; JVector normal, temp_direction, old_direction = direction; float fraction; const int res_over_two = resolution / 2; direction = JVector.Zero; for (int i = -res_over_two; i <= res_over_two; i++) { temp_direction = JVector.Transform (old_direction, JMatrix.CreateFromAxisAngle (JVector.Up, i / res_over_two * MathHelper.PiOver4)); ownPhysics.World.CollisionSystem.Raycast ( ownPhysics.RigidBody.Position, temp_direction, new Jitter.Collision.RaycastCallback((rb, n, f) => { var e = rb.Tag as Entity; return f < max_distance && e != null && (e.HasComponent<WallComponent>() || e.Name.Contains("exit")); }), out rigidBody, out normal, out fraction); if (rigidBody != null) { var diff = ownPhysics.RigidBody.Position - rigidBody.Position; diff = new JVector (diff.X, 0, diff.Z); diff.Normalize(); direction += diff * (max_distance - fraction); } else { direction += temp_direction * max_distance; } } foreach (var light in state.Scene.Lights) { var temp = ownPhysics.RigidBody.Position.ToFreezingArcherVector () - light.PointLightPosition; if (temp.LengthSquared < 400 && light.On) { if (Vector3.CalculateAngle (temp, light.DirectionalLightDirection) < degInRad) { direction += new JVector (temp.X * 20, 0, temp.Z * 20); } } } if (direction.Length() > 0.1) direction.Normalize(); else { fallback = JVector.Transform (fallback, JMatrix.CreateFromAxisAngle (JVector.Up, MathHelper.PiOver6)); direction = fallback; } if (ownPhysics.RigidBody.Position.X > maze.Size.X * 8) direction = new JVector ((maze.Size.X * 8) - ownPhysics.RigidBody.Position.X, 0, direction.Z); else if (ownPhysics.RigidBody.Position.X < 0) direction = new JVector (0 - ownPhysics.RigidBody.Position.X, 0, direction.Z); if (ownPhysics.RigidBody.Position.Z > maze.Size.Y * 8) direction = new JVector (direction.X, 0, (maze.Size.Y * 8) - ownPhysics.RigidBody.Position.Z); else if (ownPhysics.RigidBody.Position.Z < 0) direction = new JVector (direction.X, 0, 0 - ownPhysics.RigidBody.Position.Z); if (ownPhysics.RigidBody.LinearVelocity.Length() < speed) ownPhysics.RigidBody.LinearVelocity += (direction * acceleration); ownPhysics.RigidBody.Position = new JVector (ownPhysics.RigidBody.Position.X, height, ownPhysics.RigidBody.Position.Z); var player = entitiesNearby.FirstOrDefault (e => e.Name == "player"); if (player != null) { do_reset = true; var player_pos = player.GetComponent<TransformComponent>().Position; bool damage = false; foreach (var particle in smokeParticleEmitter.Particles) { if ((player_pos - particle.Position).LengthSquared < 4) { damage = true; break; } } if (damage && (DateTime.Now - lastDamage).TotalSeconds > 2) { var ghost_pos = ownPhysics.RigidBody.Position.ToFreezingArcherVector(); float distance; Vector3.Distance(ref player_pos, ref ghost_pos, out distance); float fac = ((AIcomp.MaximumEntityDistance - distance) / AIcomp.MaximumEntityDistance); var player_health = player.GetComponent<HealthComponent>(); player_health.Health -= fac * 20; lastDamage = DateTime.Now; } if (MessageCreated != null) MessageCreated (new AIAttackMessage (entity)); } else if (do_reset) { do_reset = false; } } }
public override void Think (PhysicsComponent ownPhysics, HealthComponent ownHealth, object map, List<Entity> entitiesNearby) { Maze.Maze maze = map as Maze.Maze; if (maze != null && maze.HasFinished) { RigidBody rigidBody; JVector normal, temp_direction, old_direction = direction; float fraction; const int res_over_two = resolution / 2; direction = JVector.Zero; for (int i = -res_over_two; i <= res_over_two; i++) { temp_direction = JVector.Transform (old_direction, JMatrix.CreateFromAxisAngle (JVector.Up, i / res_over_two * MathHelper.PiOver4)); ownPhysics.World.CollisionSystem.Raycast ( ownPhysics.RigidBody.Position, temp_direction, new Jitter.Collision.RaycastCallback((rb, n, f) => { var e = rb.Tag as Entity; return f < max_distance && e != null && (e.HasComponent<WallComponent>() || e.Name.Contains("exit")); }), out rigidBody, out normal, out fraction); if (rigidBody != null) { var diff = ownPhysics.RigidBody.Position - rigidBody.Position; diff = new JVector (diff.X, 0, diff.Z); diff.Normalize(); direction += diff * (max_distance - fraction); } else { direction += temp_direction * max_distance; } } if (direction.Length() > 0.1) direction.Normalize(); else { fallback = JVector.Transform (fallback, JMatrix.CreateFromAxisAngle (JVector.Up, MathHelper.PiOver6)); direction = fallback; } if (ownPhysics.RigidBody.Position.X > maze.Size.X * 8) direction = new JVector ((maze.Size.X * 8) - ownPhysics.RigidBody.Position.X, 0, direction.Z); else if (ownPhysics.RigidBody.Position.X < 0) direction = new JVector (0 - ownPhysics.RigidBody.Position.X, 0, direction.Z); if (ownPhysics.RigidBody.Position.Z > maze.Size.Y * 8) direction = new JVector (direction.X, 0, (maze.Size.Y * 8) - ownPhysics.RigidBody.Position.Z); else if (ownPhysics.RigidBody.Position.Z < 0) direction = new JVector (direction.X, 0, 0 - ownPhysics.RigidBody.Position.Z); if (ownPhysics.RigidBody.LinearVelocity.Length() < speed) ownPhysics.RigidBody.LinearVelocity += (direction * acceleration); ownPhysics.RigidBody.Position = new JVector (ownPhysics.RigidBody.Position.X, height, ownPhysics.RigidBody.Position.Z); var player = entitiesNearby.FirstOrDefault (e => e.Name == "player"); if (player != null) { do_reset = true; var player_pos = player.GetComponent<TransformComponent>().Position; var ghost_pos = ownPhysics.RigidBody.Position.ToFreezingArcherVector(); float distance; Vector3.Distance(ref player_pos, ref ghost_pos, out distance); float fac = ((AIcomp.MaximumEntityDistance - distance) / AIcomp.MaximumEntityDistance); warpingNode.WarpFactor = fac / 10; var playerPhysics = player.GetComponent<PhysicsComponent>(); if (playerPhysics != null) playerPhysics.SpeedMultiplier = 1 - fac; if ((DateTime.Now - lastDamage).TotalSeconds > 0.5f) { player.GetComponent<HealthComponent>().Health -= fac * 40; lastDamage = DateTime.Now; } var lowpass = state.AudioContext.GlobalFilter as LowpassFilter; if (lowpass == null) { lowpass = new LowpassFilter (); state.AudioContext.GlobalFilter = lowpass; } lowpass.GainHF = (1 - fac) / 10; temp_player = player; //Here send Caligo Attack Message if (MessageCreated != null) MessageCreated (new AIAttackMessage (entity)); } else if (do_reset) { do_reset = false; warpingNode.WarpFactor = 0; if (temp_player != null) temp_player.GetComponent<PhysicsComponent>().SpeedMultiplier = 1; var lowpass = state.AudioContext.GlobalFilter as LowpassFilter; if (lowpass != null) lowpass.GainHF = 1; state.AudioContext.GlobalFilter = null; } } }