internal override void RecalculateBounds(Collider collider) { // if we dont have rotation or dont care about TRS we use localOffset as the center so we'll start with that center = collider.LocalOffset; if (collider.ShouldColliderScaleAndRotateWithTransform) { var hasUnitScale = true; Matrix2D tempMat; var combinedMatrix = Matrix2D.CreateTranslation(-_polygonCenter); if (collider.Entity.Transform.Scale != Vector2.One) { Matrix2D.CreateScale(collider.Entity.Transform.Scale.X, collider.Entity.Transform.Scale.Y, out tempMat); Matrix2D.Multiply(ref combinedMatrix, ref tempMat, out combinedMatrix); hasUnitScale = false; // scale our offset and set it as center. If we have rotation also it will be reset below var scaledOffset = collider.LocalOffset * collider.Entity.Transform.Scale; center = scaledOffset; } if (collider.Entity.Transform.Rotation != 0) { Matrix2D.CreateRotation(collider.Entity.Transform.Rotation, out tempMat); Matrix2D.Multiply(ref combinedMatrix, ref tempMat, out combinedMatrix); // to deal with rotation with an offset origin we just move our center in a circle around 0,0 with our offset making the 0 angle // we have to deal with scale here as well so we scale our offset to get the proper length first. var offsetAngle = Mathf.Atan2(collider.LocalOffset.Y, collider.LocalOffset.X) * Mathf.Rad2Deg; var offsetLength = hasUnitScale ? collider._localOffsetLength : (collider.LocalOffset * collider.Entity.Transform.Scale).Length(); center = Mathf.PointOnCircle(Vector2.Zero, offsetLength, collider.Entity.Transform.RotationDegrees + offsetAngle); } Matrix2D.CreateTranslation(ref _polygonCenter, out tempMat); // translate back center Matrix2D.Multiply(ref combinedMatrix, ref tempMat, out combinedMatrix); // finaly transform our original points Vector2Ext.Transform(_originalPoints, ref combinedMatrix, Points); IsUnrotated = collider.Entity.Transform.Rotation == 0; // we only need to rebuild our edge normals if we rotated if (collider._isRotationDirty) { _areEdgeNormalsDirty = true; } } position = collider.Entity.Transform.Position + center; bounds = RectangleF.RectEncompassingPoints(Points); bounds.Location += position; }
/// <summary> /// gets the points for the rectangle with all transforms applied /// </summary> /// <returns>The transformed points.</returns> public Vector2[] GetTransformedPoints() { var pts = new Vector2[] { new Vector2(X, Y), new Vector2(X + Width, Y), new Vector2(X + Width, Y + Height), new Vector2(X, Y + Height) }; var mat = GetCombinedMatrix(); Vector2Ext.Transform(pts, ref mat, pts); return(pts); }
public Vector2[] getTransformedPoints() { var pts = new Vector2[] { start, end }; var mat = getCombinedMatrix(); Vector2Ext.transform(pts, ref mat, pts); return(pts); }
/// <summary> /// gets the points that make up the path with any transforms present applied. The points can be used to approximate the path by /// drawing lines between them. /// /// Important notes: ISvgPathBuilder is a faux interface that is required because PCLs cannot access System.Drawing which is used /// to get the drawing points. In order to use this method you need to put the SvgPathBuilder in your main project and then pass in /// an SvgPathBuilder object to this method. /// </summary> /// <returns>The transformed drawing points.</returns> /// <param name="pathBuilder">Path builder.</param> /// <param name="flatness">Flatness.</param> public Vector2[] getTransformedDrawingPoints(ISvgPathBuilder pathBuilder, float flatness = 3) { var pts = pathBuilder.getDrawingPoints(segments, flatness); var mat = getCombinedMatrix(); Vector2Ext.transform(pts, ref mat, pts); return(pts); }
public void LengthBetweenTwoPoints() { Vector2 v0 = new Vector2(0.0f, 0.0f); Vector2 v1 = new Vector2(10.0f, 0.0f); var result = Vector2Ext.DistanceBetweenTwoPoints(v0, v1); Assert.Equal(10.0f, result); }
public Vector2[] getTransformedPoints() { var pts = new Vector2[points.Length]; var mat = getCombinedMatrix(); Vector2Ext.transform(points, ref mat, pts); return(pts); }
public Vector2[] GetTransformedPoints() { var pts = new Vector2[] { Start, End }; var mat = GetCombinedMatrix(); Vector2Ext.Transform(pts, ref mat, pts); return(pts); }
/// <summary> /// gets the points for the rectangle with all transforms applied /// </summary> /// <returns>The transformed points.</returns> public Vector2[] getTransformedPoints() { var pts = new Vector2[] { new Vector2(x, y), new Vector2(x + width, y), new Vector2(x + width, y + height), new Vector2(x, y + height) }; var mat = getCombinedMatrix(); Vector2Ext.transform(pts, ref mat, pts); return(pts); }
private Point FindNearestPoint(List <Vector2> points, List <LineSegment> snap_lines, Vector2 p) { float min_distance = 1e9f; int min_point = -1; if (points.Count > 0) { min_point = 0; min_distance = Vector2Ext.Distance(p, points[0]); for (int index = 1; index < points.Count; index++) { float dist = Vector2Ext.Distance(p, points[index]); if (dist < min_distance) { min_point = index; min_distance = dist; } } //return points[min_point]; } int min_line = -1; if (snap_lines.Count > 0) { for (int index = 0; index < snap_lines.Count; index++) { float dist = snap_lines[index].Distance(p); if (dist < min_distance) { min_line = index; min_distance = dist; min_point = -1; } } } if (min_point == -1) { if (min_line == -1) { return(p.ToPoint()); } else { Vector2 nearestPoint = GeometryHelper.GetNearestPointInSegmentToPoint( snap_lines[min_line].StartPos, snap_lines[min_line].EndPos, p); return(nearestPoint.ToPoint()); } } else { return(points[min_point].ToPoint()); } }
public void CreateUnitInDirectionTestEqual() { Vector2 v0 = new Vector2(10.0f, 10.0f); Vector2 v1 = new Vector2(10.0f, 10.0f); var result = Vector2Ext.UnitInDirection(v0, v1); Assert.Equal(0.0f, result.X); Assert.Equal(0.0f, result.Y); }
public override Vector2 getPosition() { // we need a position that's far enough away to be safe // calculate the vector from them to us, then make sure it's at least the approach distance // 1. get dir to me var dirToMe = Vector2Ext.Normalize(nt.Position - mind.state.me.body.pos); // 2. scale to minimum range, find resultant (away) var targetAway = approachRange * -dirToMe; return(targetAway); }
public void CreateUnitInDirectionTest() { Vector2 v0 = new Vector2(0.0f, 0.0f); Vector2 v1 = new Vector2(10.0f, -10.0f); var result = Vector2Ext.UnitInDirection(v0, v1); var expected = (float)Math.Sqrt(0.5f); Assert.Equal(expected, result.X, 5); Assert.Equal(-expected, result.Y, 5); }
public static void Spawn(string name, float a = 0f, float s = 0f) { var wingPly = new BirdPersonality { A = a, S = s }; // wingPly.generateRandom(); var spawnOffset = Vector2Ext.Rotate(new Vector2(0, -120f), Random.NextFloat() * Mathf.PI * 2f); var wing = play.setup.createNpcWing(name, play.state.player.Entity.Position + spawnOffset, wingPly); play.AddEntity(wing.Entity); debugLog($"spawned 1 entity named {wing.Entity.Name}"); }
/// <summary> /// gets optimized drawing points with extra points in curves and less in straight lines with any transforms present applied /// </summary> /// <returns>The optimized drawing points.</returns> /// <param name="distanceTolerance">Distance tolerance.</param> public Vector2[] getOptimizedTransformedDrawingPoints(float distanceTolerance = 2f) { var pointList = getOptimizedDrawingPoints(distanceTolerance); var points = pointList.ToArray(); ListPool <Vector2> .free(pointList); var mat = getCombinedMatrix(); Vector2Ext.transform(points, ref mat, points); return(points); }
static bool CollideEdgeAndCircle(EdgeShape edge, ref FSTransform edgeTransform, CircleShape circle, ref FSTransform circleTransform, out FSCollisionResult result) { result = new FSCollisionResult(); Collision.CollideEdgeAndCircle(ref _manifold, edge, ref edgeTransform, circle, ref circleTransform); if (_manifold.PointCount > 0) { // code adapted from PositionSolverManifold.Initialize if (_manifold.Type == ManifoldType.Circles) { // this is essentically directly from ContactSolver.WorldManifold.Initialize. To avoid doing the extra math twice we duplicate this code // here because it doesnt return some values we need to calculate separation var pointA = MathUtils.Mul(ref edgeTransform, _manifold.LocalPoint); var pointB = MathUtils.Mul(ref circleTransform, _manifold.Points[0].LocalPoint); result.Normal = pointA - pointB; Vector2Ext.Normalize(ref result.Normal); var cA = pointA - edge.Radius * result.Normal; var cB = pointB + circle.Radius * result.Normal; result.Point = 0.5f * (cA + cB); result.Point *= FSConvert.SimToDisplay; var separation = Vector2.Dot(pointA - pointB, result.Normal) - edge.Radius - circle.Radius; // Ensure normal points from A to B Vector2.Negate(ref result.Normal, out result.Normal); result.MinimumTranslationVector = result.Normal * Math.Abs(separation); } else // FaceA { result.Normal = MathUtils.Mul(edgeTransform.Q, _manifold.LocalNormal); var planePoint = MathUtils.Mul(ref edgeTransform, _manifold.LocalPoint); var clipPoint = MathUtils.Mul(ref circleTransform, _manifold.Points[0].LocalPoint); var separation = Vector2.Dot(clipPoint - planePoint, result.Normal) - edge.Radius - circle.Radius; result.Point = (clipPoint - result.Normal * circle.Radius) * FSConvert.SimToDisplay; result.MinimumTranslationVector = result.Normal * -separation; } #if DEBUG_FSCOLLISIONS Debug.drawPixel(result.point, 5, Color.Red, 0.2f); Debug.drawLine(result.point, result.point + result.normal * 20, Color.Yellow, 0.2f); #endif return(true); } return(false); }
void preparePolygonForCollisionChecks() { // we need to setup a Polygon with one edge. It needs the center to be in the opposite direction of it's normal. // this is necessary so that SAT knows which way to calculate the MTV, which uses Shape positions. var perp = Vector2Ext.perpendicular(_particleTwo.position - _particleOne.position); perp.Normalize(); // set our Polygon points var midPoint = Vector2.Lerp(_particleOne.position, _particleTwo.position, 0.5f); _polygon.position = midPoint + perp * 50; _polygon.points[0] = _particleOne.position - _polygon.position; _polygon.points[1] = _particleTwo.position - _polygon.position; _polygon.recalculateCenterAndEdgeNormals(); }
public Gas(float x, float y) { initialRadius = MoreRandom.Next(8, 17); initialColor = colors[MoreRandom.Next(0, colors.Length)]; Circle = new Circle(x, y, initialRadius) { Color = initialColor }; Circle.ApplyChanges(); velocity = Vector2Ext.Random() * MoreRandom.Next(25, 120); rateOfDecay = (float)MoreRandom.NextDouble(8, 40); Lingering = true; }
public void Update() { if (CanAccelearte) { CurrentSpeed += Acceleration * Time.DeltaTime; if (CurrentSpeed > MaxSpeed) { CurrentSpeed = MaxSpeed; CanAccelearte = false; } } var motion = Vector2Ext.Normalize(player.Position - Entity.Position) * CurrentSpeed * Time.DeltaTime; mover.ApplyMovement(motion); }
/// <summary> /// builds the Polygon edge normals. These are lazily created and updated only by the edgeNormals getter /// </summary> void buildEdgeNormals() { // special case for 2 points. we just have a single edge if (points.Length == 2) { if (_edgeNormals == null || _edgeNormals.Length != 1) { _edgeNormals = new Vector2[1]; } var perp = Vector2Ext.perpendicular(ref points[0], ref points[1]); Vector2Ext.normalize(ref perp); _edgeNormals[0] = perp; return; } // for boxes we only require 2 edges since the other 2 are parallel var totalEdges = isBox ? 2 : points.Length; if (_edgeNormals == null || _edgeNormals.Length != totalEdges) { _edgeNormals = new Vector2[totalEdges]; } Vector2 p2; for (var i = 0; i < totalEdges; i++) { var p1 = points[i]; if (i + 1 >= points.Length) { p2 = points[0]; } else { p2 = points[i + 1]; } var perp = Vector2Ext.perpendicular(ref p1, ref p2); Vector2Ext.normalize(ref perp); _edgeNormals[i] = perp; } return; }
public void update() { Position getMouseTile() { // calculate the selection tilepos var selectionPos = Vector2Ext.transform(Input.mousePosition, entity.scene.camera.inverseTransformMatrix); var relativeSelectionPos = selectionPos - (entity.transform.position + localOffset); var mouseTilePos = new Position((int)relativeSelectionPos.X / TILE_DRAW_SIZE, (int)relativeSelectionPos.Y / TILE_DRAW_SIZE); return(mouseTilePos); } var selectionTilePos = getMouseTile(); if (Input.leftMouseButtonPressed) { // check if there's a selectable item on that tile var therePawn = gameState.pawns.FirstOrDefault(x => x.pos.equalTo(selectionTilePos)); if (therePawn != null) { if (therePawn.lastMove < gameState.time) { selectedThing = therePawn; } } } if (Input.rightMouseButtonPressed) { // check if we had a selection and apply it if (selectedThing != null) { if (selectedThing is PawnRef pawn) { // TODO: queue sending move message pawnMove?.Invoke(pawn, selectionTilePos); pawn.lastMove = gameState.time; selectedThing = null; // deselect } } } }
public static void Reorder(this List <Vertex> vertices, Vector2 pivot) { vertices.Sort((a, b) => { var localA = a.Position - pivot; var angleA = Vector2Ext.PositiveAngle(localA); var localB = b.Position - pivot; var angleB = Vector2Ext.PositiveAngle(localB); if (angleA == angleB) { return(0); } var delta = angleA - angleB; if (delta > 0) { return(1); } return(-1); }); }
/// <summary> /// works for circles whos center is in the box as well as just overlapping with the center out of the box. /// </summary> /// <returns><c>true</c>, if to box was circled, <c>false</c> otherwise.</returns> /// <param name="circle">First.</param> /// <param name="box">Second.</param> /// <param name="result">Result.</param> public static bool CircleToBox(Circle circle, Box box, out CollisionResult result) { result = new CollisionResult(); var closestPointOnBounds = box.bounds.GetClosestPointOnRectangleBorderToPoint(circle.position, out result.Normal); // deal with circles whos center is in the box first since its cheaper to see if we are contained if (box.ContainsPoint(circle.position)) { result.Point = closestPointOnBounds; // calculate mtv. Find the safe, non-collided position and get the mtv from that. var safePlace = closestPointOnBounds + result.Normal * circle.Radius; result.MinimumTranslationVector = circle.position - safePlace; return(true); } float sqrDistance; Vector2.DistanceSquared(ref closestPointOnBounds, ref circle.position, out sqrDistance); // see if the point on the box is less than radius from the circle if (sqrDistance == 0) { result.MinimumTranslationVector = result.Normal * circle.Radius; } else if (sqrDistance <= circle.Radius * circle.Radius) { result.Normal = circle.position - closestPointOnBounds; var depth = result.Normal.Length() - circle.Radius; result.Point = closestPointOnBounds; Vector2Ext.Normalize(ref result.Normal); result.MinimumTranslationVector = depth * result.Normal; return(true); } return(false); }
/// <summary> /// iterates all the edges of the polygon and gets the closest point on any edge to point. Returns via out the squared distance /// to the closest point and the normal of the edge it is on. point should be in the space of the Polygon (point - poly.position) /// </summary> /// <returns>The closest point on polygon to point.</returns> /// <param name="point">Point.</param> /// <param name="distanceSquared">Distance squared.</param> /// <param name="edgeNormal">Edge normal.</param> public static Vector2 getClosestPointOnPolygonToPoint( Vector2[] points, Vector2 point, out float distanceSquared, out Vector2 edgeNormal) { distanceSquared = float.MaxValue; edgeNormal = Vector2.Zero; var closestPoint = Vector2.Zero; float tempDistanceSquared; for (var i = 0; i < points.Length; i++) { var j = i + 1; if (j == points.Length) { j = 0; } var closest = ShapeCollisions.closestPointOnLine(points[i], points[j], point); Vector2.DistanceSquared(ref point, ref closest, out tempDistanceSquared); if (tempDistanceSquared < distanceSquared) { distanceSquared = tempDistanceSquared; closestPoint = closest; // get the normal of the line var line = points[j] - points[i]; edgeNormal.X = -line.Y; edgeNormal.Y = line.X; } } Vector2Ext.normalize(ref edgeNormal); return(closestPoint); }
public void MoveClockwise(float units) { if (_target == null) { return; } var normalAngle = (_target.rotation + _curPos.normalDegrees) * Mathf.Deg2Rad; var normal = Vector2Ext.FromPolar(1, normalAngle); var moveVec = Vector2Ext.FromPolar(units, normalAngle - Mathf.PI / 2); var newPos = transform.position.AsVector2() + moveVec; if (linecastAndSnap(newPos + normal, newPos - normal)) { return; } var cornerTestRot = -45 * Mathf.Sign(units); var cornerNormal = normal.Rotate(cornerTestRot); var cornerMoveVec = moveVec.Rotate(cornerTestRot); var cornerNewPos = transform.position.AsVector2() + cornerMoveVec; if (linecastAndSnap(cornerNewPos + cornerNormal, cornerNewPos - cornerNormal)) { return; } cornerTestRot = 45 * Mathf.Sign(units); cornerNormal = normal.Rotate(cornerTestRot); cornerMoveVec = moveVec.Rotate(cornerTestRot); cornerNewPos = transform.position.AsVector2() + cornerMoveVec; if (linecastAndSnap(cornerNewPos + cornerNormal, cornerNewPos - cornerNormal)) { return; } }
private void hitMelee() { // perform a melee hit var meleeWeapon = entity.getComponent <MeleeWeapon>(); var dir = lastFacing == Direction.Right ? 1 : -1; var facingFlipScale = new Vector2(dir, 1); var offset = meleeWeapon.offset; offset = Vector2Ext.transform(offset, Matrix2D.createScale(facingFlipScale)); var reach = meleeWeapon.reach; // reflect X based on direction RectangleExt.scale(ref reach, facingFlipScale); // var swordCollider = new BoxCollider(offset.X + reach.X, // offset.Y + reach.Y, reach.Width, reach.Height); var swordCollider = new BoxCollider(0, 0, reach.Width, reach.Height); swordCollider.localOffset = new Vector2(offset.X + reach.X + reach.Width / 2f, offset.Y + reach.Y + reach.Height / 2f); entity.addComponent(swordCollider); collisionResults.Clear(); swordCollider.collidesWithAnyMultiple(Vector2.Zero, collisionResults); for (var i = 0; i < collisionResults.Count; i++) { var result = collisionResults[i]; var character = result.collider?.entity.getComponent <Character>(); if (character != null) { hurtCharacter(character); } } entity.removeComponent(swordCollider); }
private static List <Vector2> CubicCurve(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, int numberOfLimit, bool cubic) { List <Vector2> output = new List <Vector2>(); //MoveTo the first Point; //How many times the curve change form innegative -> negative or vice versa int _limit = numberOfLimit; float t1, t2, _flatness; t1 = 0.0f; //t1 is the start point of [0..1]. t2 = 1.0f; //t2 is the end point of [0..1] _flatness = 1.0f; Vector2Ext _pStart, _pEnd, _pMid; _pStart = new Vector2Ext(cubic ? EvaluateForCubic(t1, p1, p2, p3, p4) : EvaluateForQuadratic(t1, p1, p2, p3, p4), t1); _pEnd = new Vector2Ext(cubic ? EvaluateForCubic(t2, p1, p2, p3, p4) : EvaluateForQuadratic(t2, p1, p2, p3, p4), t2); // The point on Line Segment[_pStart, _pEnd] correlate with _t _stack.Clear(); _stack.Push(_pEnd); //Push End Point into Stack //Array of Change Point _limitList.Clear(); if (_limitList.Capacity < _limit + 1) { _limitList.Capacity = _limit + 1; } int _count = 0; while (true) { _count++; float _tm = (t1 + t2) / 2; //tm is a middle of t1 .. t2. [t1 .. tm .. t2] //The point on the Curve correlate with tm _pMid = new Vector2Ext(cubic ? EvaluateForCubic(_tm, p1, p2, p3, p4) : EvaluateForQuadratic(_tm, p1, p2, p3, p4), _tm); //Calculate Distance from Middle Point to the Flatnet float dist = Distance(_pStart.point, ((Vector2Ext)_stack.Peek()).point, _pMid.point); //flag = true, Curve Segment must be drawn, else continue calculate other middle point. bool flag = false; if (dist < _flatness) { int i = 0; float mm = 0.0f; for (i = 0; i < _limit; i++) { mm = (t1 + _tm) / 2; Vector2Ext _q = new Vector2Ext(cubic ? EvaluateForCubic(mm, p1, p2, p3, p4) : EvaluateForQuadratic(mm, p1, p2, p3, p4), mm); if (_limitList.Count - 1 < i) { _limitList.Add(_q); } else { _limitList[i] = _q; } dist = Distance(_pStart.point, _pMid.point, _q.point); if (dist >= _flatness) { break; } else { _tm = mm; } } if (i == _limit) { flag = true; } else { //Continue calculate the first point has Distance > Flatness _stack.Push(_pMid); for (int j = 0; j <= i; j++) { _stack.Push(_limitList[j]); } t2 = mm; } } if (flag) { output.Add(_pStart.point); output.Add(_pMid.point); _pStart = _stack.Pop(); if (_stack.Count == 0) { break; } _pMid = _stack.Peek(); t1 = t2; t2 = _pMid.t; } else if (t2 > _tm) { //If Distance > Flatness and t1 < tm < t2 then new t2 is tm. _stack.Push(_pMid); t2 = _tm; } } output.Add(_pStart.point); return(output); }
private static List<Vector2> CubicCurve(Vector2 p1, Vector2 p2, Vector2 p3, Vector2 p4, int numberOfLimit, bool cubic) { List<Vector2> output = new List<Vector2>(); //MoveTo the first Point; //How many times the curve change form innegative -> negative or vice versa int _limit = numberOfLimit; float t1, t2, _flatness; t1 = 0.0f; //t1 is the start point of [0..1]. t2 = 1.0f; //t2 is the end point of [0..1] _flatness = 1.0f; Vector2Ext _pStart, _pEnd, _pMid; _pStart = new Vector2Ext(cubic ? EvaluateForCubic(t1, p1, p2, p3, p4) : EvaluateForQuadratic(t1, p1, p2, p3, p4), t1); _pEnd = new Vector2Ext(cubic ? EvaluateForCubic(t2, p1, p2, p3, p4) : EvaluateForQuadratic(t2, p1, p2, p3, p4), t2); // The point on Line Segment[_pStart, _pEnd] correlate with _t _stack.Clear(); _stack.Push(_pEnd); //Push End Point into Stack //Array of Change Point _limitList.Clear(); if(_limitList.Capacity < _limit + 1) _limitList.Capacity = _limit + 1; int _count = 0; while(true) { _count++; float _tm = (t1 + t2) / 2; //tm is a middle of t1 .. t2. [t1 .. tm .. t2] //The point on the Curve correlate with tm _pMid = new Vector2Ext(cubic ? EvaluateForCubic(_tm, p1, p2, p3, p4) : EvaluateForQuadratic(_tm, p1, p2, p3, p4), _tm); //Calculate Distance from Middle Point to the Flatnet float dist = Distance(_pStart.point, ((Vector2Ext)_stack.Peek()).point, _pMid.point); //flag = true, Curve Segment must be drawn, else continue calculate other middle point. bool flag = false; if(dist < _flatness) { int i = 0; float mm = 0.0f; for(i = 0; i < _limit; i++) { mm = (t1 + _tm) / 2; Vector2Ext _q = new Vector2Ext(cubic ? EvaluateForCubic(mm, p1, p2, p3, p4) : EvaluateForQuadratic(mm, p1, p2, p3, p4), mm); if(_limitList.Count - 1 < i) _limitList.Add(_q); else _limitList[i] = _q; dist = Distance(_pStart.point, _pMid.point, _q.point); if(dist >= _flatness) { break; } else { _tm = mm; } } if(i == _limit) { flag = true; } else { //Continue calculate the first point has Distance > Flatness _stack.Push(_pMid); for(int j = 0; j <= i; j++) _stack.Push(_limitList[j]); t2 = mm; } } if(flag) { output.Add(_pStart.point); output.Add(_pMid.point); _pStart = _stack.Pop(); if(_stack.Count == 0) break; _pMid = _stack.Peek(); t1 = t2; t2 = _pMid.t; } else if(t2 > _tm) { //If Distance > Flatness and t1 < tm < t2 then new t2 is tm. _stack.Push(_pMid); t2 = _tm; } } output.Add(_pStart.point); return output; }
/// <summary> /// old SpriteBatch drawing method. This should probably be removed since SpriteBatch was replaced by Batcher /// </summary> /// <param name="spriteBatch">Sprite batch.</param> /// <param name="text">Text.</param> /// <param name="position">Position.</param> /// <param name="color">Color.</param> /// <param name="rotation">Rotation.</param> /// <param name="origin">Origin.</param> /// <param name="scale">Scale.</param> /// <param name="effect">Effect.</param> /// <param name="depth">Depth.</param> internal void drawInto(SpriteBatch spriteBatch, ref FontCharacterSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effect, float depth) { var flipAdjustment = Vector2.Zero; var flippedVert = (effect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically; var flippedHorz = (effect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally; if (flippedVert || flippedHorz) { Vector2 size; measureString(ref text, out size); if (flippedHorz) { origin.X *= -1; flipAdjustment.X = -size.X; } if (flippedVert) { origin.Y *= -1; flipAdjustment.Y = lineHeight - size.Y; } } var requiresTransformation = flippedHorz || flippedVert || rotation != 0f || scale != Vector2.One; if (requiresTransformation) { Matrix2D temp; Matrix2D.CreateTranslation(-origin.X, -origin.Y, out _transformationMatrix); Matrix2D.CreateScale((flippedHorz ? -scale.X : scale.X), (flippedVert ? -scale.Y : scale.Y), out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); Matrix2D.CreateTranslation(flipAdjustment.X, flipAdjustment.Y, out temp); Matrix2D.Multiply(ref temp, ref _transformationMatrix, out _transformationMatrix); Matrix2D.CreateRotationZ(rotation, out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); Matrix2D.CreateTranslation(position.X, position.Y, out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); } BitmapFontRegion currentFontRegion = null; var offset = requiresTransformation ? Vector2.Zero : position - origin; for (var i = 0; i < text.Length; ++i) { var c = text[i]; if (c == '\r') { continue; } if (c == '\n') { offset.X = requiresTransformation ? 0f : position.X - origin.X; offset.Y += lineHeight; currentFontRegion = null; continue; } if (currentFontRegion != null) { offset.X += spacing + currentFontRegion.xAdvance; } if (!_characterMap.TryGetValue(c, out currentFontRegion)) { currentFontRegion = defaultCharacterRegion; } var p = offset; if (flippedHorz) { p.X += currentFontRegion.width; } p.X += currentFontRegion.xOffset; if (flippedVert) { p.Y += currentFontRegion.height - lineHeight; } p.Y += currentFontRegion.yOffset; // transform our point if we need to if (requiresTransformation) { Vector2Ext.Transform(ref p, ref _transformationMatrix, out p); } var destRect = RectangleExt.fromFloats ( p.X, p.Y, currentFontRegion.width * scale.X, currentFontRegion.height * scale.Y ); spriteBatch.Draw(currentFontRegion.subtexture, destRect, currentFontRegion.subtexture.sourceRect, color, rotation, Vector2.Zero, effect, depth); } }
UpdateResult doUpdatePosition(float vx, Func <Vector2, bool> normalCheck, int collisionValue, bool collisionSolid, bool checkWalls) { var normalAngle = ((_targetBody ? _targetBody.rotation : _target.transform.rotation.z) + _curPos.normalDegrees) * Mathf.Deg2Rad; if (!checkWalls && Mathf.Abs(vx) < 0.0001f) { return(new UpdateResult { stillStanding = normalCheck(Vector2Ext.FromPolar(1, normalAngle)), wallCollision = collisionValue, solidWallCollision = collisionSolid }); } if (FixVX) { vx /= Mathf.Cos(normalAngle - Mathf.PI / 2); } var pos = surfaceCoordsToWorldCoords(_curPos); var normal = Vector2Ext.FromPolar(1, normalAngle); var tangent = normal.Rotate(-90); var moveVec = vx * tangent; var newPos = pos + moveVec; if (checkWalls) { var newMiddle = newPos + (GravitySetting.Reverse ? -1 : 1) * Vector2.up * _heroDim.HalfHeight; var wallTestL = newMiddle - (tangent * _heroDim.HalfWidth) / tangent.x; var wallTestR = newMiddle + (tangent * _heroDim.HalfWidth) / tangent.x; Debug.DrawLine(wallTestL, wallTestR, Color.magenta); bool pushed; var penetration = wallTest(wallTestL, wallTestR, vx > 0 ? PushForce : -PushForce, out pushed, normalCheck); if (penetration.HasValue) { var depth = penetration.Value; if (GravitySetting.Reverse) { depth *= -1; } var colVal = 0; if (!pushed) { colVal = depth > 0 ? 1 : -1; } return(doUpdatePosition(vx - depth, normalCheck, colVal, !pushed, false)); } if (Mathf.Abs(vx) < 0.0001f) { return(new UpdateResult { stillStanding = normalCheck(Vector2Ext.FromPolar(1, normalAngle)), wallCollision = collisionValue, solidWallCollision = collisionSolid }); } } // Check if the center ray of the player hits the target collider. if (maybeMoveToSnap(linecastAndSnap(newPos + normal, newPos - normal), normalCheck)) { return(new UpdateResult { stillStanding = true, wallCollision = collisionValue, solidWallCollision = collisionSolid }); } // Check if we're walking around a 90 degree or greater bend. var cornerTestRot = -45 * Mathf.Sign(vx); var cornerNormal = normal.Rotate(cornerTestRot); var cornerMoveVec = moveVec.Rotate(cornerTestRot); var cornerNewPos = pos + cornerMoveVec; if (maybeMoveToSnap(linecastAndSnap(cornerNewPos + cornerNormal, cornerNewPos - cornerNormal), normalCheck)) { return(new UpdateResult { stillStanding = true, wallCollision = collisionValue, solidWallCollision = collisionSolid }); } // Check if we're edging out where the center doesn't collider, but an edge does. var edgeVec = tangent * (_heroDim.HalfWidth - _heroDim.InsetX); if (maybeMoveToSnap(linecastAndSnap(newPos + edgeVec + normal, newPos + edgeVec - normal, -edgeVec), normalCheck) || maybeMoveToSnap(linecastAndSnap(newPos - edgeVec + normal, newPos - edgeVec - normal, edgeVec), normalCheck)) { return(new UpdateResult { stillStanding = true, wallCollision = collisionValue, solidWallCollision = collisionSolid }); } return(new UpdateResult { stillStanding = false, wallCollision = collisionValue, solidWallCollision = collisionSolid }); }
public void DrawInto(Batcher batcher, ref FontCharacterSource text, Vector2 position, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effect, float depth) { var flipAdjustment = Vector2.Zero; var flippedVert = (effect & SpriteEffects.FlipVertically) == SpriteEffects.FlipVertically; var flippedHorz = (effect & SpriteEffects.FlipHorizontally) == SpriteEffects.FlipHorizontally; if (flippedVert || flippedHorz) { var size = MeasureString(ref text); if (flippedHorz) { origin.X *= -1; flipAdjustment.X = -size.X; } if (flippedVert) { origin.Y *= -1; flipAdjustment.Y = LineHeight - size.Y; } } var requiresTransformation = flippedHorz || flippedVert || rotation != 0f || scale != new Vector2(1); if (requiresTransformation) { Matrix2D temp; Matrix2D.CreateTranslation(-origin.X, -origin.Y, out _transformationMatrix); Matrix2D.CreateScale((flippedHorz ? -scale.X : scale.X), (flippedVert ? -scale.Y : scale.Y), out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); Matrix2D.CreateTranslation(flipAdjustment.X, flipAdjustment.Y, out temp); Matrix2D.Multiply(ref temp, ref _transformationMatrix, out _transformationMatrix); Matrix2D.CreateRotation(rotation, out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); Matrix2D.CreateTranslation(position.X, position.Y, out temp); Matrix2D.Multiply(ref _transformationMatrix, ref temp, out _transformationMatrix); } var previousCharacter = ' '; Character currentChar = null; var offset = requiresTransformation ? Vector2.Zero : position - origin; for (var i = 0; i < text.Length; ++i) { var c = text[i]; if (c == '\r') { continue; } if (c == '\n') { offset.X = requiresTransformation ? 0f : position.X - origin.X; offset.Y += LineHeight; currentChar = null; continue; } if (currentChar != null) { offset.X += Spacing.X + currentChar.XAdvance; } currentChar = ContainsCharacter(c) ? this[c] : DefaultCharacter; var p = offset; if (flippedHorz) { p.X += currentChar.Bounds.Width; } p.X += currentChar.Offset.X + GetKerning(previousCharacter, currentChar.Char); if (flippedVert) { p.Y += currentChar.Bounds.Height - LineHeight; } p.Y += currentChar.Offset.Y; // transform our point if we need to if (requiresTransformation) { Vector2Ext.Transform(ref p, ref _transformationMatrix, out p); } var destRect = RectangleExt.FromFloats ( p.X, p.Y, currentChar.Bounds.Width * scale.X, currentChar.Bounds.Height * scale.Y ); batcher.Draw(Textures[currentChar.TexturePage], destRect, currentChar.Bounds, color, rotation, Vector2.Zero, effect, depth); previousCharacter = c; } }
SnapResult linecastAndSnap(Vector2 p0, Vector2 p1, Vector2 offset) { var hitsPrime = Physics2D.LinecastAll(p0, p1, MooseController.CollisionLayerMask); var hitsDos = new List <RaycastHit2D>(); for (var i = 0; i < hitsPrime.Length; ++i) { if (_targetBody) { if (hitsPrime[i].rigidbody == _targetBody) { hitsDos.Add(hitsPrime[i]); } } else { if (hitsPrime[i].collider == _target) { hitsDos.Add(hitsPrime[i]); } } } if (hitsDos.Count == 0) { return new SnapResult { success = false } } ; var hit = hitsDos[0]; return(new SnapResult { success = true, newPos = worldCoordsToSurfaceCoords(hit.point + offset, hit.normal), normal = hit.normal }); } bool maybeMoveToSnap(SnapResult snap, Func <Vector2, bool> normalCheck) { if (!snap.success || !normalCheck(snap.normal)) { return(false); } moveToSurfaceCoord(snap.newPos); return(true); } void moveToSurfaceCoord(SurfaceCoords pos) { _lastPos = _curPos; _curPos = pos; _updateFlag = true; } Vector2 surfaceCoordsToWorldCoords(SurfaceCoords s) { var targetObject = _targetBody ? _targetBody.gameObject : _target.gameObject; var theta = (targetObject.transform.rotation.eulerAngles.z + s.degrees) * Mathf.Deg2Rad; return(Vector2Ext.FromPolar(s.radius, theta) + targetObject.transform.position.AsVector2()); } SurfaceCoords worldCoordsToSurfaceCoords(Vector2 pos, Vector2 normal) { var ds = pos - (_targetBody ? _targetBody.position : _target.transform.position.AsVector2()); var angleOffset = _targetBody ? _targetBody.rotation : _target.transform.rotation.z; return(new SurfaceCoords { radius = ds.magnitude, degrees = Mathf.Atan2(ds.y, ds.x) * Mathf.Rad2Deg - angleOffset, normalDegrees = Mathf.Atan2(normal.y, normal.x) * Mathf.Rad2Deg - angleOffset }); } }