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.

257 lines
9.2 KiB
C#

using Global;
using Logic;
using Logica;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media.Media3D;
namespace Wpf_3D {
public partial class MainWindow : Window {
private int vertR = 0; //vertical angle
private int horzR = 0; //horizontal angle
private ModelVisual3D visual3D;
private Maze filled_maze;
private Ball3DGenerator ball3DGenerator = new Ball3DGenerator();
private Model3DGroup modelGroup = new Model3DGroup();
Maze3DGenerator mazeGen = new Maze3DGenerator();
private bool isGameOver = false;
private bool popupBeingShown = false;
private CancellationTokenSource gameLoopCancellationTokenSource;
private PhysicsEngine physicsEngine;
public MainWindow() {
InitializeComponent();
StartGamePopup();
}
/// <summary>
/// initialise the maze generation & 3D models
/// </summary>
private void InitializeMaze() {
Maze maze = new Maze(15, 15); //Change these parameters to change the size of the maze.
maze.GenerateGrid(System.Drawing.Color.Red);
DepthFirstAlgoritm algo = new DepthFirstAlgoritm(maze);
algo.Generate();
filled_maze = algo.maze;
mazeGen = new Maze3DGenerator();
AddGuiElements(mazeGen.GenerateMaze(algo.maze), ball3DGenerator.GenerateBall(maze.ball));
physicsEngine = new PhysicsEngine(maze.ball, maze);
isGameOver = false;
Task.Run(async () => await GameLoopAsync());
}
/// <summary>
/// calculate physics on the ball & redraw it every 50ms
/// </summary>
/// <returns></returns>
private async Task GameLoopAsync() {
gameLoopCancellationTokenSource = new CancellationTokenSource();
while (!isGameOver) {
await Task.Delay(50);
Dispatcher.Invoke(() => {
CalculateBallMovement();
});
}
}
/// <summary>
/// Popup for the start of the game
/// Starts the game;
/// </summary>
private void StartGamePopup() {
MessageBoxResult result = MessageBox.Show("Druk op OK om het spel te starten, \r\nKantel het bord met de pijltjes (↑ ↓ → ←)\r\nEn zoom de camera in & uit met de 'I' en 'O' toetsen.\r\nDuw op 'R' om het doolhof te resetten", "welkom", MessageBoxButton.OK);
if (result == MessageBoxResult.OK) {
InitializeMaze();
}
else {
Application.Current.Shutdown();
}
}
/// <summary>
/// Popup for the end of the game.
/// Can restart or end the game
/// </summary>
private async void ShowEndPopup() {
if (physicsEngine.isFinished == true && !popupBeingShown) {
popupBeingShown = true;
MessageBoxResult result = MessageBox.Show("Proficiat!\r\nU hebt het doolhof opgelost. \r\nDuw op OK om opnieuw te beginnen en duw op cancel om te stoppen", "Proficiat!", MessageBoxButton.OKCancel);
if (result == MessageBoxResult.OK) {
await Task.Delay(100);
InitializeMaze();
}
else if (result == MessageBoxResult.Cancel) {
gameLoopCancellationTokenSource.Cancel();
Application.Current.Shutdown();
}
popupBeingShown = false;
}
}
/// <summary>
/// Add all GUI elements to the modelgroup
/// </summary>
/// <param name="maze"></param>
/// <param name="ball"></param>
/// <returns></returns>
private Task AddGuiElements(Model3D maze, Model3D ball) {
modelGroup.Children.Clear();
modelGroup.Children.Add(maze);
modelGroup.Children.Add(ball);
visual3D = new ModelVisual3D {
Content = modelGroup
};
viewport3D1.Children[1] = visual3D;
CentreScreen();
return null;
}
/// <summary>
/// Call the PhysicsEngine and move the ball.
/// Check if the ball is in the end cell
/// </summary>
private void CalculateBallMovement() {
if (!isGameOver) {
Ball calcBall = physicsEngine.CalculateAngleMovement(vertR, horzR);
Dispatcher.Invoke(() => {
modelGroup.Children[1] = ball3DGenerator.GenerateBall(calcBall);
});
if (physicsEngine.isFinished) {
ShowEndPopup();
isGameOver = true;
}
}
}
/// <summary>
/// Center the screen
/// </summary>
private void CentreScreen() {
vertR = 0;
horzR = 0;
Transform3DGroup rotationGroup = new Transform3DGroup();
double centerX = filled_maze.length / 2;
double centerY = filled_maze.height / 2;
TranslateTransform3D centerTranslation = new TranslateTransform3D(-centerX, -centerY, 0);
rotationGroup.Children.Add(centerTranslation);
visual3D.Transform = rotationGroup;
}
/// <summary>
/// Handle the GUI controls
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Window_KeyDown(object sender, KeyEventArgs e) {
switch (e.Key) {
case Key.Left:
horzR--;
HorizontalMovement();
break;
case Key.Right:
horzR++;
HorizontalMovement();
break;
case Key.Up:
vertR--;
VerticalMovement();
break;
case Key.Down:
vertR++;
VerticalMovement();
break;
case Key.I:
ZoomCamera(-5);
break;
case Key.O:
ZoomCamera(5);
break;
case Key.R:
InitializeMaze();
break;
}
}
/// <summary>
/// Angle the board on the horizontal axis
/// </summary>
private void HorizontalMovement() {
if (horzR > 30) {
horzR = 30;
}
if (horzR < -30) {
horzR = -30;
}
double centerX = filled_maze.length / 2;
double centerY = filled_maze.height / 2;
TranslateTransform3D centerTranslation = new TranslateTransform3D(-centerX, -centerY, 0);
RotateTransform3D horizontalRotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), horzR));
RotateTransform3D verticalRotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), vertR));
Transform3DGroup rotationGroup = new Transform3DGroup();
rotationGroup.Children.Add(centerTranslation);
rotationGroup.Children.Add(horizontalRotation);
rotationGroup.Children.Add(verticalRotation);
visual3D.Transform = rotationGroup;
}
/// <summary>
/// Angle the board on the vertical axis
/// </summary>
private void VerticalMovement() {
if (vertR > 30) {
vertR = 30;
}
if (vertR < -30) {
vertR = -30;
}
double centerX = filled_maze.length / 2;
double centerY = filled_maze.height / 2;
TranslateTransform3D centerTranslation = new TranslateTransform3D(-centerX, -centerY, 0);
RotateTransform3D horizontalRotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(0, 1, 0), horzR));
RotateTransform3D verticalRotation = new RotateTransform3D(new AxisAngleRotation3D(new Vector3D(1, 0, 0), vertR));
Transform3DGroup rotationGroup = new Transform3DGroup();
rotationGroup.Children.Add(centerTranslation);
rotationGroup.Children.Add(horizontalRotation);
rotationGroup.Children.Add(verticalRotation);
visual3D.Transform = rotationGroup;
}
/// <summary>
/// Change the perspective of the camera to zoom in & out
/// </summary>
/// <param name="zoomFactor"></param>
private void ZoomCamera(double zoomFactor) {
PerspectiveCamera camera = (PerspectiveCamera)viewport3D1.Camera;
camera.FieldOfView += zoomFactor;
if (camera.FieldOfView < 1.0) {
camera.FieldOfView = 1.0;
}
if (camera.FieldOfView > 120.0) {
camera.FieldOfView = 120.0;
}
}
}
}