|
|
@ -6,13 +6,6 @@ namespace Game { |
|
|
|
|
|
|
|
|
|
|
|
public class AIPlayer : Player { |
|
|
|
public class AIPlayer : Player { |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Possible optimizations: |
|
|
|
|
|
|
|
* - Try to hit ball with edge |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public Difficulty Difficulty { get; set; } |
|
|
|
public Difficulty Difficulty { get; set; } |
|
|
|
|
|
|
|
|
|
|
|
private float FutureSeconds => (float) Difficulty * 0.5f; |
|
|
|
private float FutureSeconds => (float) Difficulty * 0.5f; |
|
|
@ -41,14 +34,17 @@ namespace Game { |
|
|
|
Vector2 m2 = e2 - o2; |
|
|
|
Vector2 m2 = e2 - o2; |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
/* |
|
|
|
* o1x + r * m1x = o2x + s * m2x |
|
|
|
* |
|
|
|
* o1y + r * m1y = o2y + s * m2y |
|
|
|
* o1 + r * m1 = 02 + s * m2 |
|
|
|
* |
|
|
|
* |
|
|
|
* Solve for r and s: |
|
|
|
* o1x + r * m1x = o2x + s * m2x |
|
|
|
* Formulas below achieved by reordering |
|
|
|
* o1y + r * m1y = o2y + s * m2y |
|
|
|
* Order is irrelevant, but if m1x == 0 then first approach results in division by zero -> |
|
|
|
* |
|
|
|
* Invert order then, and if division by zero is still a problem, both lines are parallel anyway |
|
|
|
* Solve for r and s: |
|
|
|
*/ |
|
|
|
* Formulas below achieved by reordering |
|
|
|
|
|
|
|
* Order is irrelevant, but if m1x == 0 then first approach results in division by zero -> |
|
|
|
|
|
|
|
* Invert order then, and if division by zero is still a problem, both lines are parallel anyway |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
|
|
|
|
float r, s; |
|
|
|
float r, s; |
|
|
|
if (m1.x != 0) { |
|
|
|
if (m1.x != 0) { |
|
|
@ -72,6 +68,8 @@ namespace Game { |
|
|
|
|
|
|
|
|
|
|
|
private float IdlePosition => Difficulty >= Difficulty.Medium ? 0 : X(); |
|
|
|
private float IdlePosition => Difficulty >= Difficulty.Medium ? 0 : X(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// TODO solution for balls outside of border |
|
|
|
|
|
|
|
// TODO Also must include fact that players have a height, maybe check the incoming angle |
|
|
|
private bool IsPositionReachableInTime(float futurePosition, float seconds) { |
|
|
|
private bool IsPositionReachableInTime(float futurePosition, float seconds) { |
|
|
|
float requiredDistance = Mathf.Abs(futurePosition - X()) - Width / 2; |
|
|
|
float requiredDistance = Mathf.Abs(futurePosition - X()) - Width / 2; |
|
|
|
if (requiredDistance < 0) |
|
|
|
if (requiredDistance < 0) |
|
|
@ -160,19 +158,33 @@ namespace Game { |
|
|
|
return IdlePosition; |
|
|
|
return IdlePosition; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private float currentSmoothV; |
|
|
|
private void ApproachPosition(float pos) { |
|
|
|
private void ApproachPosition(float pos) { |
|
|
|
// Move smoothly, velocity capped by Speed |
|
|
|
float result = Mathf.SmoothDamp(X(), pos, ref currentSmoothV, .5f); |
|
|
|
|
|
|
|
transform.position = new Vector2(result, Y()); |
|
|
|
|
|
|
|
ClampInsideBorders(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private bool isApproaching; |
|
|
|
|
|
|
|
private float lastDirection; |
|
|
|
private void FixedUpdate() { |
|
|
|
private void FixedUpdate() { |
|
|
|
float target = GetTargetPosition(); |
|
|
|
float target = GetTargetPosition(); |
|
|
|
const float h = 0.5f; |
|
|
|
float h = Width / 2; |
|
|
|
goingLeft = target < X() - h; |
|
|
|
goingLeft = target < X() - h; |
|
|
|
goingRight = target > X() + h; |
|
|
|
goingRight = target > X() + h; |
|
|
|
if (goingLeft || goingRight) |
|
|
|
if (goingLeft || goingRight) { |
|
|
|
|
|
|
|
isApproaching = false; |
|
|
|
|
|
|
|
lastDirection = goingLeft ? -1 : 1; |
|
|
|
TryLinearMove(Time.fixedDeltaTime); |
|
|
|
TryLinearMove(Time.fixedDeltaTime); |
|
|
|
else |
|
|
|
} |
|
|
|
|
|
|
|
else { |
|
|
|
|
|
|
|
if (!isApproaching) { |
|
|
|
|
|
|
|
isApproaching = true; |
|
|
|
|
|
|
|
currentSmoothV = Speed * lastDirection; |
|
|
|
|
|
|
|
} |
|
|
|
ApproachPosition(target); |
|
|
|
ApproachPosition(target); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |