using Global;
using Logica;
namespace Logic {
public class PhysicsEngine {
public Ball ball { get; set; }
private Maze maze;
private double timeInterval = 0.1; //(100ms)
public bool isFinished = false;
double Dv = 0;
double Dh = 0;
private double elasticity = 0.5;
public PhysicsEngine(Ball ball, Maze maze) {
this.ball = ball;
this.maze = maze;
}
///
/// Checks for collisions on both axis
///
///
///
public void CheckForCollision(double x, double y) {
CheckXAxis(x);
CheckYAxis(y);
}
///
/// Check the x axis for collisions
///
///
internal void CheckXAxis(double x) {
double arrayX = x - 0.5;
bool directionCheck = ball.x > x; // true for left, false for right
bool axisCheck = false;
for (double i = -ball.size; i <= ball.size; i += 0.1) {
double checkX = directionCheck ? arrayX - ball.size : arrayX + ball.size;
double checkY = ball.y - 0.5 + i;
if (maze.cels[RoundToNearest(checkX), RoundToNearest(checkY)].isWall) {
axisCheck = true;
break;
}
}
if (!axisCheck) {
ball.x = x;
}
else {
Dv = -Dv * elasticity;
}
}
///
/// Check if the y axis collides with the edge
///
///
internal void CheckYAxis(double y) {
double arrayY = y - 0.5;
bool directionCheck = ball.y > y; // true for up, false for down
bool axisCheck = false;
for (double i = -ball.size; i <= ball.size; i += 0.1) {
double checkX = ball.x - 0.5 + i;
double checkY = directionCheck ? arrayY - ball.size : arrayY + ball.size;
if (maze.cels[RoundToNearest(checkX), RoundToNearest(checkY)].isWall) {
axisCheck = true;
break;
}
}
if (!axisCheck) {
ball.y = y;
}
else {
Dh = -Dh * elasticity;
}
}
///
/// Check if the ball is in the end cell.
///
///
internal bool CheckFinished() {
double tolerance = 0.5; // Adjust the tolerance as needed
if (Math.Abs(ball.x - maze.endCell.x) < tolerance && Math.Abs(ball.y - maze.endCell.y) < tolerance) {
return true;
}
else {
return false;
}
}
//round double to the nearest integer
public int RoundToNearest(double value) {
return (int)Math.Ceiling(value);
}
///
/// Calculate angle to x and y forces
///
///
///
///
public Ball CalculateAngleMovement(double vertR, double horzR) {
double radianAngleX = vertR * (Math.PI / 180);
double radianAngleY = horzR * (Math.PI / 180);
double aX = 9.81 * Math.Sin(radianAngleX);
double aY = 9.81 * Math.Sin(radianAngleY);
Dh += (1.0 / 2.0) * aX * Math.Pow(timeInterval, 2);
Dv += (1.0 / 2.0) * aY * Math.Pow(timeInterval, 2);
AddFriction();
double nextX = ball.x + Dv;
double nextY = ball.y - Dh;
CheckForCollision(nextX, nextY);
if (CheckFinished()) {
isFinished = true;
}
else {
isFinished = false;
}
return ball;
}
///
/// Add friction the the ball
///
private void AddFriction() {
double friction = 0.15;
Dv *= (1.0 - friction * timeInterval);
Dh *= (1.0 - friction * timeInterval);
}
}
}