/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> /// <param name="firstHit">Returns the first hit that occurs, i.e. the one with the highest proximity to the starting point.</param> /// <returns>Returns whether anything has been hit.</returns> public bool RayCast(Vector2 start, Vector2 end, RayCastCallback callback, out RayCastData firstHit) { if (callback == null) { callback = RayCast_DefaultCallback; } Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; float firstHitFraction = float.MaxValue; RayCastData firstHitLocal = default(RayCastData); this.native.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { RayCastData data = new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction); float result = callback(data); if (result >= 0.0f && data.Fraction < firstHitFraction) { firstHitLocal = data; firstHitFraction = data.Fraction; } return(result); }, fsWorldCoordA, fsWorldCoordB); firstHit = firstHitLocal; return(firstHitFraction != float.MaxValue); }
private void HorizontalCollisions(ref Vector2 velocity) { var directionX = MathF.Sign(velocity.X); var rayLength = MathF.Abs(velocity.X) + SkinWidth; for (var i = 0; i < HorizontalRayCount; i++) { var rayOrigin = directionX == -1 ? raycastOrigins.bottomLeft : raycastOrigins.bottomRight; rayOrigin -= Vector2.UnitY * (horizontalRaySpacing * i); if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor) { VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, directionX * rayLength, 0); } RayCastCallback raycastCallback = data => 1.0f; RayCastData rayCastData; if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitX * directionX * rayLength, raycastCallback, out rayCastData)) { var distance = (rayOrigin - rayCastData.Pos).Length; velocity.X = (distance - SkinWidth) * directionX; rayLength = distance; collisions.right = directionX == 1; collisions.left = directionX == -1; } } }
public override void Step() { bool advanceRay = TestSettings.pause == false || TestSettings.singleStep; base.Step(); float L = 11.0f; Vec2 point1 = new Vec2(0.0f, 10.0f); Vec2 d = new Vec2(L * (float)Math.Cos(m_angle), L * (float)Math.Sin(m_angle)); Vec2 point2 = point1 + d; if (m_mode == Mode.e_closest) { _callback = new RayCastClosestCallback(); m_world.RayCast(_callback, point1, point2); } else if (m_mode == Mode.e_any) { _callback = new RayCastAnyCallback(); m_world.RayCast(_callback, point1, point2); } else if (m_mode == Mode.e_multiple) { _callback = new RayCastMultipleCallback(); m_world.RayCast(_callback, point1, point2); } if (advanceRay) { m_angle += (float)(0.25 * Math.PI / 180.0); } }
private void VerticalCollisions(ref Vector2 velocity) { var directionY = MathF.Sign(velocity.Y); var rayLength = MathF.Abs(velocity.Y) + SkinWidth; for (var i = 0; i < VerticalRayCount; i++) { var rayOrigin = directionY == -1 ? raycastOrigins.topLeft : raycastOrigins.bottomLeft; rayOrigin += Vector2.UnitX * (verticalRaySpacing * i + velocity.X); if (DualityApp.ExecEnvironment == DualityApp.ExecutionEnvironment.Editor) { VisualLog.Default.DrawVector(rayOrigin.X, rayOrigin.Y, 0, 0, directionY * rayLength); } RayCastCallback raycastCallback = data => 1.0f; RayCastData rayCastData; if (RigidBody.RayCast(rayOrigin, rayOrigin + Vector2.UnitY * directionY * rayLength, raycastCallback, out rayCastData)) { var distance = (rayOrigin - rayCastData.Pos).Length; velocity.Y = (distance - SkinWidth) * directionY; rayLength = distance; collisions.below = directionY == 1; collisions.above = directionY == -1; } } }
public void CheckCanSeePlayer(Vector2 point) { CanSeePlayer = true; RayCastCallback callback = new RayCastCallback(RayCastCallback); world.RayCast(callback, point, SolitudeScreen.ship.Player.body.Position); }
/// <summary> /// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// /// Inside the callback: /// return -1: ignore this fixture and continue /// return 0: terminate the ray cast /// return fraction: clip the ray to this point /// return 1: don't clip the ray and continue /// </summary> /// <param name="callback">A user implemented callback class.</param> /// <param name="point1">The ray starting point.</param> /// <param name="point2">The ray ending point.</param> public void RayCast(RayCastCallback callback, Vector2 point1, Vector2 point2) { RayCastInput input = new RayCastInput(); input.MaxFraction = 1.0f; input.Point1 = point1; input.Point2 = point2; this.ContactManager.BroadPhase.RayCast((rayCastInput, proxyId) => { FixtureProxy proxy = this.ContactManager.BroadPhase.GetProxy(proxyId); Fixture fixture = proxy.Fixture; int index = proxy.ChildIndex; RayCastOutput output; bool hit = fixture.RayCast(out output, ref rayCastInput, index); if (hit) { float fraction = output.Fraction; Vector2 point = (1.0f - fraction) * rayCastInput.Point1 + fraction * rayCastInput.Point2; return(callback(fixture, point, output.Normal, fraction)); } return(rayCastInput.MaxFraction); //input.MaxFraction; }, ref input); }
public bool TryDrill(Vector2 direction) { if (direction == Vector2.Zero) { return(false); } Vector2 rayOrigin = GameObj.Transform.Pos.Xy; Vector2 rayEnd = rayOrigin + direction.Normalized * DrillDistance; RayCastCallback rayCB = data => { if (data.GameObj.GetComponent <TilemapCollider> () != null) { return(1.0f); } else { return(-1.0f); } }; RayCastData rayCastData; if (RigidBody.RayCast(rayOrigin, rayEnd, rayCB, out rayCastData)) { DoDrill(rayCastData, direction); return(true); } return(false); }
public void Jump() { if (Jumping || (Crouching && !CrouchHeadroomHitTest())) { return; } RayCastCallback callback = (fixture, point, normal, fraction) => { lock (_RenderSet.Scene.Game.UpdateLock) { // TODO: Have these values be not hard-coded if (fixture == FixtureUpper || fixture == FixtureLower) { return(1.0f); } //if(JumpTimer.Elapsed.TotalMilliseconds > 50 && GoneDown) if (!Jumping) { JumpTimer.Restart(); Body.LinearVelocity = new Microsoft.Xna.Framework.Vector2(Body.LinearVelocity.X, _JumpAmount); GoneDown = false; PlayAnimation(AnimationPreJump); _AnimationNext = new Lazy <SpriteAnimation>(() => { return(AnimationJumping); }); // HIGH JUMP //FixtureLower.CollisionCategories = Category.None; //FixtureUpper.CollisionCategories = Category.Cat1; } if (FixtureLower.CollisionCategories == Category.None) { // TODO: Give this functionality to more than just the player class // This code is VERY important; this code tells all of the objects // currently touching the lower fixture to separate as the fixture // is marked as non-colliding. This ensures things like floor switches // don't get stuck closed! FixtureLowerColliders.Add(fixture); FixtureLowerColliders.ForEach(c => { if (FixtureLower.OnSeparation != null) { FixtureLower.OnSeparation(FixtureLower, c); } if (c.OnSeparation != null) { c.OnSeparation(c, FixtureLower); } //Console.WriteLine (c.Body.UserData); }); FixtureLowerColliders.Clear(); } return(1.0f); } }; lock (_RenderSet.Scene.Game.UpdateLock) // Paranoid BodyPlatformRayCast(callback); }
/// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// @param callback a user implemented callback class. /// @param point1 the ray starting point /// @param point2 the ray ending point public void RayCast(RayCastCallback callback, Vector2 point1, Vector2 point2) { RayCastInput input = new RayCastInput(); input.maxFraction = 1.0f; input.p1 = point1; input.p2 = point2; _rayCastCallback = callback; _contactManager._broadPhase.RayCast(_rayCastCallbackWrapper, ref input); _rayCastCallback = null; }
/// <summary> /// 反註冊RayCastMgr /// </summary> /// <param name="rayCastCb">callback</param> /// <returns></returns> public bool UnRegister(RayCastCallback rayCastCb) { if (rayDic.ContainsKey(rayCastCb)) { cbFunction -= rayCastCb; rayDic.Remove(rayCastCb); ResetLayerMask(); return(true); } else { return(false); } }
public void RayCast(RayCastCallback callback, Microsoft.Xna.Framework.Vector2 point1, Microsoft.Xna.Framework.Vector2 point2) { World.RayCast(callback, point1, point2); if (Configuration.DrawBlueprints) { lock (_RenderLock) { new BlueprintLine( new Vector3d(point1.X * Configuration.MeterInPixels, point1.Y * Configuration.MeterInPixels, 0.0), new Vector3d(point2.X * Configuration.MeterInPixels, point2.Y * Configuration.MeterInPixels, 0.0), WorldBlueprint); } } }
/// <summary> /// 註冊RayCastMgr /// </summary> /// <param name="layers">layer name</param> /// <param name="rayCastCb">callback(RaycastHit[] rayCastHit)</param> /// <returns></returns> public bool Register(string[] layers, RayCastCallback rayCastCb) { if (!rayDic.ContainsKey(rayCastCb)) { cbFunction += rayCastCb; rayDic.Add(rayCastCb, layers); ResetLayerMask(); return(true); } else { return(false); } }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> public void RayCast(Vector2 start, Vector2 end, RayCastCallback callback) { if (callback == null) { callback = RayCast_DefaultCallback; } Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; this.native.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { return(callback(new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction))); }, fsWorldCoordA, fsWorldCoordB); }
public void RayCast(Vector3 from, Vector3 to, RayCastCallback callback) { var rayBounding = BoundingVolume.TowPoints(from, to); var v = FindOrthogonal((to - from).normalized); var abs_v = new Vector3(Mathf.Abs(v.x), Mathf.Abs(v.y), Mathf.Abs(v.z)); var stack = new Stack <int> (); stack.Push(rootNode); while (stack.Count > 0) { var index = stack.Pop(); if (!BoundingVolume.Intersects(rayBounding, nodes[index].bounding)) { continue; } var c = nodes[index].bounding.center; var h = nodes[index].bounding.extents; var separation = Mathf.Abs(Vector3.Dot(v, from - c)) - Vector3.Dot(abs_v, h); if (separation > 0.0f) { continue; } if (nodes[index].isLeaf) { if (callback != null) { callback.Invoke(from, to, nodes[index]); // TODO: Fraction update } } else { stack.Push(nodes[index].childA); stack.Push(nodes[index].childB); } } }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> /// <param name="hits"> /// A list that will be filled with all hits that were registered, ordered by their Fraction value. /// The list will not be cleared before adding items. /// </param> /// <returns>Returns whether any new hit was registered.</returns> public bool RayCast(Vector2 start, Vector2 end, RayCastCallback callback, RawList <RayCastData> hits) { if (callback == null) { callback = RayCast_DefaultCallback; } Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; int oldResultCount = hits.Count; this.native.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { int index = hits.Count++; RayCastData[] data = hits.Data; data[index] = new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction); float result = callback(data[index]); if (result < 0.0f) { hits.Count--; } return(result); }, fsWorldCoordA, fsWorldCoordB); hits.Data.StableSort( 0, hits.Count, (d1, d2) => (int)(1000000.0f * (d1.Fraction - d2.Fraction))); return(hits.Count > oldResultCount); }
public void BodyPlatformRayCast(RayCastCallback callback) { // TODO: make the foot reach distance (in pixels) a member variable AABB aabb; lock (Body) { // Paraoid... if (FixtureLower.CollisionCategories == Category.None && Jumping) { FixtureUpper.GetAABB(out aabb, 0); } else { FixtureLower.GetAABB(out aabb, 0); // Probably disabled lower fixture during jump } } float w = aabb.UpperBound.X - aabb.LowerBound.X; float h = aabb.UpperBound.Y - aabb.LowerBound.Y; float pixel = 1.0f / (float)Configuration.MeterInPixels; float px = (float)PositionX * pixel; float py = (float)PositionY * pixel; float x_start = 0.0f; float spread = 3.0f * pixel; float y_start = aabb.LowerBound.Y + spread - pixel; float y_end = aabb.LowerBound.Y - spread - pixel; for (int i = 0; i < JumpRayXDirections.Length; i++) { float dx = (float)(_Scale.X * w * JumpRayXDirections [i]); var start = new Microsoft.Xna.Framework.Vector2(px + x_start + dx, py + y_start); var end = new Microsoft.Xna.Framework.Vector2(start.X, py + y_end); _RenderSet.Scene.RayCast(callback, start, end); } }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> public static void RayCast(Vector2 start, Vector2 end, RayCastCallback callback) { if (callback == null) callback = Raycast_DefaultCallback; Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; Scene.PhysicsWorld.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { return callback(new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction)); }, fsWorldCoordA, fsWorldCoordB); }
/// Ray-cast against the proxies in the tree. This relies on the callback /// to perform a exact ray-cast in the case were the proxy contains a shape. /// The callback also performs the any collision filtering. This has performance /// roughly equal to k * log(n), where k is the number of collisions and n is the /// number of proxies in the tree. /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1). /// @param callback a callback class that is called for each proxy that is hit by the ray. public void RayCast(RayCastCallback callback, ref RayCastInput input) { Vector2 p1 = input.p1; Vector2 p2 = input.p2; Vector2 r = p2 - p1; Debug.Assert(r.LengthSquared() > 0.0f); r.Normalize(); // v is perpendicular to the segment. Vector2 v = MathUtils.Cross(1.0f, r); Vector2 abs_v = MathUtils.Abs(v); // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) float maxFraction = input.maxFraction; // Build a bounding box for the segment. AABB segmentAABB = new AABB(); { Vector2 t = p1 + maxFraction * (p2 - p1); segmentAABB.lowerBound = Vector2.Min(p1, t); segmentAABB.upperBound = Vector2.Max(p1, t); } int count = 0; stack[count++] = _root; while (count > 0) { int nodeId = stack[--count]; if (nodeId == NullNode) { continue; } DynamicTreeNode node = _nodes[nodeId]; if (AABB.TestOverlap(ref node.aabb, ref segmentAABB) == false) { continue; } // Separating axis for segment (Gino, p80). // |dot(v, p1 - c)| > dot(|v|, h) Vector2 c = node.aabb.GetCenter(); Vector2 h = node.aabb.GetExtents(); float separation = Math.Abs(Vector2.Dot(v, p1 - c)) - Vector2.Dot(abs_v, h); if (separation > 0.0f) { continue; } if (node.IsLeaf()) { RayCastInput subInput; subInput.p1 = input.p1; subInput.p2 = input.p2; subInput.maxFraction = maxFraction; RayCastOutput output; callback(out output, ref subInput, node.userData); if (output.hit) { // Early exit. if (output.fraction == 0.0f) { return; } maxFraction = output.fraction; // Update segment bounding box. { Vector2 t = p1 + maxFraction * (p2 - p1); segmentAABB.lowerBound = Vector2.Min(p1, t); segmentAABB.upperBound = Vector2.Max(p1, t); } } } else { Debug.Assert(count + 1 < k_stackSize); stack[count++] = node.child1; stack[count++] = node.child2; } } }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="worldCoordA">The starting point.</param> /// <param name="worldCoordB">The desired end point.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> /// <returns>Returns a list of all occurred hits, ordered by their Fraction value.</returns> public static List<RayCastData> RayCast(Vector2 worldCoordA, Vector2 worldCoordB, RayCastCallback callback = null) { if (callback == null) callback = Raycast_DefaultCallback; Vector2 fsWorldCoordA = PhysicsConvert.ToPhysicalUnit(worldCoordA); Vector2 fsWorldCoordB = PhysicsConvert.ToPhysicalUnit(worldCoordB); List<RayCastData> hitData = new List<RayCastData>(); Scene.PhysicsWorld.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { RayCastData data = new RayCastData( fixture.UserData as ShapeInfo, PhysicsConvert.ToDualityUnit(pos), normal, fraction); float result = callback(data); if (result >= 0.0f) hitData.Add(data); return result; }, fsWorldCoordA, fsWorldCoordB); hitData.StableSort((d1, d2) => (int)(1000000.0f * (d1.Fraction - d2.Fraction))); return hitData; }
public void RayCast(RayCastCallback callback, Vector2 start, Vector2 end, bool ignoreSensors = true, bool ignoreProjectile = true) { // Use Bresenham's line algorithm to check cells along the ray IMPROVE THAT AS IT'S NOT 100% RELIABLE BRESENHAM CELLS DON'T CATCH ALL POSSIBLE COLLIDERS NEEDS MORE THAN ONE CELL THICK !!! !!! !!! // Line line = new Line(start, end); _drawLines.Add(line); // Get starting end and positions. Vector2 pos1 = start - Origin; Vector2 pos2 = end - Origin; int x1 = (int)(pos1.X / _cellSize); int x2 = (int)(pos2.X / _cellSize); int y1 = (int)(pos1.Y / _cellSize); int y2 = (int)(pos2.Y / _cellSize); int deltaX = Math.Abs(x1 - x2); int deltaY = Math.Abs(y1 - y2); // Set signum values. int signX = x1 < x2 ? 1 : -1; int signY = y1 < y2 ? 1 : -1; int error = deltaX - deltaY; bool bFirst = true; while (true) { bool bLast = (x1 == x2 && y1 == y2); // Stop if we found the collision. if (CheckLineCollisions(x1, y1, line, callback, bFirst, bLast, ignoreSensors, ignoreProjectile)) { break; } // If we reached last cell break out of loop. if (bLast) { break; } if (bFirst) { bFirst = false; } // Double error to avoid using floats. int doubleError = error * 2; if (doubleError > -deltaY) { // Check cells inbetween to make sure. int y1b = y1 + signY; if (checkLineInCell(x1, y1b, line)) { if (CheckLineCollisions(x1, y1b, line, callback, bFirst, bLast, ignoreSensors, ignoreProjectile)) { break; } } // Increment in x direction. error -= deltaY; x1 += signX; } if (doubleError < deltaX) { // Check cells inbetween to make sure. int x1b = x1 + signX; if (checkLineInCell(x1b, y1, line)) { if (CheckLineCollisions(x1 + signX, y1, line, callback, bFirst, bLast, ignoreSensors, ignoreProjectile)) { break; } } // Increment in y direction. error += deltaX; y1 += signY; } } }
public void RayCast(RayCastCallback callback, Microsoft.Xna.Framework.Vector2 point1, Microsoft.Xna.Framework.Vector2 point2) { _World.RayCast (callback, point1, point2); if (Configuration.DrawBlueprints) { lock(RenderLock) { new BlueprintLine ( new Vector3d (point1.X * Configuration.MeterInPixels, point1.Y * Configuration.MeterInPixels, 0.0), new Vector3d (point2.X * Configuration.MeterInPixels, point2.Y * Configuration.MeterInPixels, 0.0), WorldBlueprint); } } }
public void BodyPlatformRayCast(RayCastCallback callback) { // TODO: make the foot reach distance (in pixels) a member variable AABB aabb; lock (Body) { // Paraoid... if(FixtureLower.CollisionCategories == Category.None && Jumping) FixtureUpper.GetAABB (out aabb, 0); else FixtureLower.GetAABB (out aabb, 0); // Probably disabled lower fixture during jump } float w = aabb.UpperBound.X - aabb.LowerBound.X; float h = aabb.UpperBound.Y - aabb.LowerBound.Y; float pixel = 1.0f / (float)Configuration.MeterInPixels; float px = (float)PositionX * pixel; float py = (float)PositionY * pixel; float x_start = 0.0f; float spread = 3.0f * pixel; float y_start = aabb.LowerBound.Y + spread; float y_end = aabb.LowerBound.Y - spread; for (int i = 0; i < JumpRayXDirections.Length; i++) { float dx = (float)(_Scale.X * w * JumpRayXDirections [i]); var start = new Microsoft.Xna.Framework.Vector2 (px + x_start + dx, py + y_start); var end = new Microsoft.Xna.Framework.Vector2 (start.X, py + y_end); _RenderSet.Scene.RayCast (callback, start, end); } }
/// <summary> /// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// /// Inside the callback: /// return -1: ignore this fixture and continue /// return 0: terminate the ray cast /// return fraction: clip the ray to this point /// return 1: don't clip the ray and continue /// </summary> /// <param name="callback">A user implemented callback class.</param> /// <param name="point1">The ray starting point.</param> /// <param name="point2">The ray ending point.</param> public void RayCast(RayCastCallback callback, Vector2 point1, Vector2 point2) { RayCastInput input = new RayCastInput(); input.MaxFraction = 1.0f; input.Point1 = point1; input.Point2 = point2; ContactManager.BroadPhase.RayCast((rayCastInput, proxyId) => { FixtureProxy proxy = ContactManager.BroadPhase.GetProxy(proxyId); Fixture fixture = proxy.Fixture; int index = proxy.ChildIndex; RayCastOutput output; bool hit = fixture.RayCast(out output, ref rayCastInput, index); if (hit) { float fraction = output.Fraction; Vector2 point = (1.0f - fraction) * input.Point1 + fraction * input.Point2; return callback(fixture, point, output.Normal, fraction); } return input.MaxFraction; }, ref input); }
/// <summary> /// 反註冊RayCastMgr /// </summary> /// <param name="rayCastCb">callback</param> /// <returns></returns> public bool UnRegister( RayCastCallback rayCastCb) { if (rayDic.ContainsKey(rayCastCb)) { cbFunction -= rayCastCb; rayDic.Remove(rayCastCb); ResetLayerMask(); return true; } else { return false; } }
public override void Draw() { base.Draw(); m_debugDraw.DrawString(5, m_textLine, "Press 1-5 to place stuff, m to change the mode"); m_textLine += 15; m_debugDraw.DrawString(5, m_textLine, "Mode = " + m_mode.ToString()); m_textLine += 15; if (_callback == null) { return; } float L = 11.0f; Vec2 point1 = new Vec2(0.0f, 10.0f); Vec2 d = new Vec2(L * (float)Math.Cos(m_angle), L * (float)Math.Sin(m_angle)); Vec2 point2 = point1 + d; if (_callback is RayCastClosestCallback) { RayCastClosestCallback callback = (RayCastClosestCallback)_callback; m_world.RayCast(_callback, point1, point2); if (callback.m_hit) { m_debugDraw.DrawPoint(callback.m_point, 5.0f, new ColorF(0.4f, 0.9f, 0.4f)); m_debugDraw.DrawSegment(point1, callback.m_point, new ColorF(0.8f, 0.8f, 0.8f)); Vec2 head = callback.m_point + 0.5f * callback.m_normal; m_debugDraw.DrawSegment(callback.m_point, head, new ColorF(0.9f, 0.9f, 0.4f)); } else { m_debugDraw.DrawSegment(point1, point2, new ColorF(0.8f, 0.8f, 0.8f)); } } else if (_callback is RayCastAnyCallback) { RayCastAnyCallback callback = (RayCastAnyCallback)_callback; _callback = new RayCastAnyCallback(); if (callback.m_hit) { m_debugDraw.DrawPoint(callback.m_point, 5.0f, new ColorF(0.4f, 0.9f, 0.4f)); m_debugDraw.DrawSegment(point1, callback.m_point, new ColorF(0.8f, 0.8f, 0.8f)); Vec2 head = callback.m_point + 0.5f * callback.m_normal; m_debugDraw.DrawSegment(callback.m_point, head, new ColorF(0.9f, 0.9f, 0.4f)); } else { m_debugDraw.DrawSegment(point1, point2, new ColorF(0.8f, 0.8f, 0.8f)); } } else if (_callback is RayCastMultipleCallback) { RayCastMultipleCallback callback = (RayCastMultipleCallback)_callback; m_debugDraw.DrawSegment(point1, point2, new ColorF(0.8f, 0.8f, 0.8f)); for (int i = 0; i < callback.m_count; ++i) { Vec2 p = callback.m_points[i]; Vec2 n = callback.m_normals[i]; m_debugDraw.DrawPoint(p, 5.0f, new ColorF(0.4f, 0.9f, 0.4f)); m_debugDraw.DrawSegment(point1, p, new ColorF(0.8f, 0.8f, 0.8f)); Vec2 head = p + 0.5f * n; m_debugDraw.DrawSegment(p, head, new ColorF(0.9f, 0.9f, 0.4f)); } } }
public RayCastMultipleCallback() { Count = 0; Callback = ReportFixture; }
public RayCastAnyCallback() { Hit = false; Callback = ReportFixture; }
private bool CheckLineCollisions(int col, int row, Line line, RayCastCallback callback, bool isFirst, bool isLast, bool ignoreSensor, bool ignoreProjectile) { Bag <PhysicsObject> possibleColliders = _grid[col, row]; Vector2 collisionPoint = line.P2; Vector2 collisionNormal = Vector2.Zero; PhysicsObject collidingObject = null; float distance = float.PositiveInfinity; if (possibleColliders == null) { return(false); } /// I actually don't now why I put this in - it may causes bugs in future but for the moment it seems to work when commented. /*if (possibleColliders.Count > 0) * { * // Cut out segment within the current cell. * // * * // Create a sensor within the cell to collide with * float xCell = (col + 0.5f) * _cellSize + Origin.X; * float yCell = (row + 0.5f) * _cellSize + Origin.Y; * * var cellCollider = new Sensor(this, new Vector2(xCell, yCell), new Vector2(_cellSize, _cellSize)); * * var newStart = Vector2.Zero; * var newEnd = Vector2.Zero; * var newNorm = Vector2.Zero; * var mirrorLine = new Line(line.P2, line.P1); * * if (!CollideLinePoly(line, (Polygon)cellCollider.CollisionShape, out newStart, out newNorm)) * { * newStart = line.P1; * } * if (!CollideLinePoly(mirrorLine, (Polygon)cellCollider.CollisionShape, out newEnd, out newNorm)) * { * newEnd = line.P2; * } * * line = new Line(newStart, newEnd); * * cellCollider.Dispense(); // Remove from world * }*/ // Test each object to collide with line. possibleColliders.ForEachWith((collider) => { if (ignoreSensor) { if (collider.IsSensor) { return; } } if (ignoreProjectile) { if (collider.IsProjectile) { return; } } if (collider.CollisionShape.Type == Shape.ShapeType.SH_POLYGON) { var poly = collider.CollisionShape as Polygon; if (isFirst) { if (CollidePointPoly(line.P1, poly)) { return; } } Vector2 curCollisionPoint, curCollisionNormal; if (CollideLinePoly(line, poly, out curCollisionPoint, out curCollisionNormal)) { // Check for closest point float curDistance = (curCollisionPoint - line.P1).Length(); if (curDistance < distance) { distance = curDistance; collidingObject = collider; collisionPoint = curCollisionPoint; collisionNormal = curCollisionNormal; } } } }, (collider) => { return(collider.IsActive); }); if (collidingObject != null) { callback(collidingObject, collisionPoint, collisionNormal); _drawPoints.Add(collisionPoint); return(true); } return(false); }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> /// <param name="hits">Returns a list of all occurred hits, ordered by their Fraction value.</param> public static void RayCast(Vector2 start, Vector2 end, RayCastCallback callback, out RawList<RayCastData> hits) { if (callback == null) callback = Raycast_DefaultCallback; Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; RawList<RayCastData> localHits = new RawList<RayCastData>(); Scene.PhysicsWorld.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { int oldCount = localHits.Count++; RayCastData[] data = localHits.Data; data[oldCount] = new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction); float result = callback(data[oldCount]); if (result < 0.0f) localHits.Count--; return result; }, fsWorldCoordA, fsWorldCoordB); localHits.Data.StableSort(0, localHits.Count, (d1, d2) => (int)(1000000.0f * (d1.Fraction - d2.Fraction))); hits = localHits; }
/// <summary> /// 註冊RayCastMgr /// </summary> /// <param name="layers">layer name</param> /// <param name="rayCastCb">callback(RaycastHit[] rayCastHit)</param> /// <returns></returns> public bool Register(string[] layers, RayCastCallback rayCastCb) { if (!rayDic.ContainsKey(rayCastCb)) { cbFunction += rayCastCb; rayDic.Add(rayCastCb, layers); ResetLayerMask(); return true; } else { return false; } }
/// <summary> /// Performs a 2d physical raycast in world coordinates. /// </summary> /// <param name="start">The starting point in world coordinates.</param> /// <param name="end">The desired end point in world coordinates.</param> /// <param name="callback"> /// The callback that is invoked for each hit on the raycast. Note that the order in which each hit occurs isn't deterministic /// and may appear random. Return -1 to ignore the curret shape, 0 to terminate the raycast, data.Fraction to clip the ray for current hit, or 1 to continue. /// </param> /// <param name="firstHit">Returns the first hit that occurs, i.e. the one with the highest proximity to the starting point.</param> /// <returns>Returns whether anything has been hit.</returns> public static bool RayCast(Vector2 start, Vector2 end, RayCastCallback callback, out RayCastData firstHit) { if (callback == null) callback = Raycast_DefaultCallback; Vector2 fsWorldCoordA = PhysicsUnit.LengthToPhysical * start; Vector2 fsWorldCoordB = PhysicsUnit.LengthToPhysical * end; float firstHitFraction = float.MaxValue; RayCastData firstHitLocal = default(RayCastData); Scene.PhysicsWorld.RayCast(delegate(Fixture fixture, Vector2 pos, Vector2 normal, float fraction) { RayCastData data = new RayCastData( fixture.UserData as ShapeInfo, PhysicsUnit.LengthToDuality * pos, normal, fraction); float result = callback(data); if (result >= 0.0f && data.Fraction < firstHitFraction) { firstHitLocal = data; firstHitFraction = data.Fraction; } return result; }, fsWorldCoordA, fsWorldCoordB); firstHit = firstHitLocal; return firstHitFraction != float.MaxValue; }
public bool RayCast(Vector3 from, Vector3 to, RayCastCallback callback = null) { Vector3 r = to - from; r.Normalize(); float maxFraction = 1.0f; // v is perpendicular to the segment. Vector3 v = VectorUtil.FindOrthogonal(r).normalized; Vector3 absV = VectorUtil.Abs(v); // build a bounding box for the segment. Aabb rayBounds = Aabb.Empty; rayBounds.Include(from); rayBounds.Include(to); m_stack.Clear(); m_stack.Push(m_root); bool hitAnyBounds = false; while (m_stack.Count > 0) { int index = m_stack.Pop(); if (index == Null) { continue; } if (!Aabb.Intersects(m_nodes[index].Bounds, rayBounds)) { continue; } // Separating axis for segment (Gino, p80). // |dot(v, a - c)| > dot(|v|, h) Vector3 c = m_nodes[index].Bounds.Center; Vector3 h = m_nodes[index].Bounds.HalfExtents; float separation = Mathf.Abs(Vector3.Dot(v, from - c)) - Vector3.Dot(absV, h); if (separation > 0.0f) { continue; } if (m_nodes[index].IsLeaf) { Aabb tightBounds = m_nodes[index].Bounds; tightBounds.Expand(-FatBoundsRadius); float t = tightBounds.RayCast(from, to, maxFraction); if (t < 0.0f) { continue; } hitAnyBounds = true; float newMaxFraction = callback != null ? callback(from, to, m_nodes[index].UserData) : maxFraction; if (newMaxFraction >= 0.0f) { // Update segment bounding box. maxFraction = newMaxFraction; Vector3 newTo = from + maxFraction * (to - from); rayBounds.Min = VectorUtil.Min(from, newTo); rayBounds.Max = VectorUtil.Max(from, newTo); } } else { m_stack.Push(m_nodes[index].ChildA); m_stack.Push(m_nodes[index].ChildB); } } return(hitAnyBounds); }
/// <summary> /// Ray-cast the world for all fixtures in the path of the ray. Your callback controls whether you /// get the closest point, any point, or n-points. The ray-cast ignores shapes that contain the /// starting point. /// </summary> /// <param name="callback">a user implemented callback class.</param> /// <param name="point1">the ray starting point</param> /// <param name="point2">the ray ending point</param> public virtual void raycast(RayCastCallback callback, Vec2 point1, Vec2 point2) { wrcwrapper.broadPhase = m_contactManager.m_broadPhase; wrcwrapper.callback = callback; input.maxFraction = 1.0f; input.p1.set_Renamed(point1); input.p2.set_Renamed(point2); m_contactManager.m_broadPhase.raycast(wrcwrapper, input); }
public EdgeShapesCallback() { Fixture = null; Callback = ReportFixture; }
/// <summary> /// Ray-cast the world for all fixtures in the path of the ray. Your callback /// controls whether you get the closest point, any point, or n-points. /// The ray-cast ignores shapes that contain the starting point. /// </summary> /// <param name="callback">A user implemented callback class.</param> /// <param name="point1">The ray starting point.</param> /// <param name="point2">The ray ending point.</param> public void RayCast(RayCastCallback callback, Vector2 point1, Vector2 point2) { RayCastInput input = new RayCastInput(); input.MaxFraction = 1.0f; input.Point1 = point1; input.Point2 = point2; _rayCastCallback = callback; ContactManager.BroadPhase.RayCast(_rayCastCallbackWrapper, ref input); _rayCastCallback = null; }
/** * Ray-cast the world for all fixtures and particles in the path of the ray. Your callback * controls whether you get the closest point, any point, or n-points. The ray-cast ignores shapes * that contain the starting point. * * @param callback a user implemented callback class. * @param particleCallback the particle callback class. * @param point1 the ray starting point * @param point2 the ray ending point */ public void raycast(RayCastCallback callback, ParticleRaycastCallback particleCallback, Vec2 point1, Vec2 point2) { wrcwrapper.broadPhase = m_contactManager.m_broadPhase; wrcwrapper.callback = callback; input.maxFraction = 1.0f; input.p1.set(point1); input.p2.set(point2); m_contactManager.m_broadPhase.raycast(wrcwrapper, input); m_particleSystem.raycast(particleCallback, point1, point2); }