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#
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
}
|