You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
4.4 KiB
C#
156 lines
4.4 KiB
C#
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;
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// Checks for collisions on both axis
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
/// <param name="y"></param>
|
|
public void CheckForCollision(double x, double y) {
|
|
CheckXAxis(x);
|
|
CheckYAxis(y);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Check the x axis for collisions
|
|
/// </summary>
|
|
/// <param name="x"></param>
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Check if the y axis collides with the edge
|
|
/// </summary>
|
|
/// <param name="y"></param>
|
|
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;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
/// Check if the ball is in the end cell.
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
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);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Calculate angle to x and y forces
|
|
/// </summary>
|
|
/// <param name="vertR"></param>
|
|
/// <param name="horzR"></param>
|
|
/// <returns></returns>
|
|
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;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Add friction the the ball
|
|
/// </summary>
|
|
private void AddFriction() {
|
|
double friction = 0.15;
|
|
Dv *= (1.0 - friction * timeInterval);
|
|
Dh *= (1.0 - friction * timeInterval);
|
|
}
|
|
|
|
}
|
|
}
|