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(); } /// /// initialise the maze generation & 3D models /// 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()); } /// /// calculate physics on the ball & redraw it every 50ms /// /// private async Task GameLoopAsync() { gameLoopCancellationTokenSource = new CancellationTokenSource(); while (!isGameOver) { await Task.Delay(50); Dispatcher.Invoke(() => { CalculateBallMovement(); }); } } /// /// Popup for the start of the game /// Starts the game; /// 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(); } } /// /// Popup for the end of the game. /// Can restart or end the game /// 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; } } /// /// Add all GUI elements to the modelgroup /// /// /// /// 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; } /// /// Call the PhysicsEngine and move the ball. /// Check if the ball is in the end cell /// 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; } } } /// /// Center the screen /// 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; } /// /// Handle the GUI controls /// /// /// 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; } } /// /// Angle the board on the horizontal axis /// 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; } /// /// Angle the board on the vertical axis /// 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; } /// /// Change the perspective of the camera to zoom in & out /// /// 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; } } } }