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; } }
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 }); } }
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 }); }
Vector2 surfaceCoordsToWorldCoords(SurfaceCoords s) { var theta = (_target.gameObject.transform.rotation.eulerAngles.z + s.degrees) * Mathf.Deg2Rad; return(Vector2Ext.FromPolar(s.radius, theta) + _target.transform.position.AsVector2()); }
public Vector2 CheckNormal() { var normalAngle = (_target.rotation + _curPos.normalDegrees) * Mathf.Deg2Rad; return(Vector2Ext.FromPolar(1, normalAngle)); }