Compare commits

..

197 Commits

Author SHA1 Message Date
Luca Conte 3c7d68109a Merge pull request 'fix ready' (#31) from game-end-stuff into main
Reviewed-on: #31
2024-12-23 22:22:00 +00:00
Luca Conte eaa5b64956 fix ready 2024-12-23 23:21:48 +01:00
Luca Conte 5b3ecb52bb Merge pull request 'add rotate instruction' (#30) from game-end-stuff into main
Reviewed-on: #30
2024-12-23 22:15:19 +00:00
Luca Conte 9ea176cc6d add rotate instruction 2024-12-23 23:15:04 +01:00
Luca Conte 7a706e1b73 Merge pull request 'game-end-stuff' (#29) from game-end-stuff into main
Reviewed-on: #29
2024-12-23 22:13:57 +00:00
Luca Conte 175241395e add docs to makefile 2024-12-23 23:13:11 +01:00
Luca Conte 1b08b39105 don't repaint fields after game end 2024-12-23 23:12:43 +01:00
Luca Conte 8dd697bb66 proper game closing 2024-12-23 23:04:16 +01:00
Luca Conte 30360c7bd4 Merge pull request 'kommentar-check' (#28) from kommentar-check into main
Reviewed-on: #28
2024-12-23 20:37:06 +00:00
Luca Conte 6f98a82a90 KOOMMMEEENTTAAAREEEEEEEE 2024-12-23 21:36:19 +01:00
Luca Conte a4cb3f68d5 Merge branch 'FH_Last_changes' into kommentar-check 2024-12-23 20:51:53 +01:00
eyFlorian 424dd2544e FUCK ME 2024-12-23 20:50:46 +01:00
Luca Conte 27157fb0a3 Merge pull request 'Add komentare' (#27) from ole into main
Reviewed-on: #27
2024-12-23 19:49:01 +00:00
Luca Conte 0fef0069f8 wtf 2024-12-23 20:48:51 +01:00
Luca Conte 5839b13980 Merge branch 'main' into ole 2024-12-23 20:47:40 +01:00
Luca Conte 0f42a66e4a Merge pull request 'lucasjoshua' (#26) from lucasjoshua into main
Reviewed-on: #26
2024-12-23 19:46:03 +00:00
Luca Conte c14f7d5bfe Merge branch 'main' into lucasjoshua 2024-12-23 20:44:31 +01:00
Luca Conte f13e0ab2ba Merge pull request 'Kommentare und Withdraw' (#24) from FH_Last_changes into main
Reviewed-on: #24
2024-12-23 19:39:53 +00:00
Luca Conte e85f151b33 a bit cleaner withdraw 2024-12-23 20:28:06 +01:00
Luca Conte 7fb19bfeac Merge branch 'main' into FH_Last_changes 2024-12-23 20:17:51 +01:00
Luca Conte 9ed0dc1e9e Merge pull request 'wip-fix-ai-players' (#25) from wip-fix-ai-players into main
Reviewed-on: #25
2024-12-23 19:14:59 +00:00
Luca Conte 9d51e708e5 remove game board on win or lose 2024-12-23 20:13:52 +01:00
Luca Conte 44f04a454f proper thread killing and online player myTurn handling 2024-12-23 20:02:11 +01:00
Joshua 678ed9d81e Got rid of some todos 2024-12-23 19:28:02 +01:00
Luca Conte be6b50739f Merge branch 'lucasjoshua' into wip-fix-ai-players 2024-12-23 19:05:24 +01:00
Joshua 458aa46638 Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-12-23 18:51:02 +01:00
Joshua be46f3587e Fixed semesterCounter for onlineGame. 2024-12-23 18:50:39 +01:00
Kaver 9c6d629357 fix Board halb 2024-12-23 18:41:10 +01:00
ole 70749c2c62 add Komentare 2024-12-23 18:36:15 +01:00
Joshua 3ad7233383 JoinGame now calls GameController.startOnlineGame(...) correctly. 2024-12-23 18:35:22 +01:00
Joshua 529178f4db Updated backButton.png. 2024-12-23 18:08:40 +01:00
eyFlorian 4045d3ce7b Kommentare und Withdraw 2024-12-23 15:28:33 +01:00
Luca Conte d97826db6c Merge pull request 'die letzten javadoc kommentare' (#23) from cleanup-work into main
Reviewed-on: #23
2024-12-22 23:29:12 +00:00
Luca Conte 2cce52b827 die letzten javadoc kommentare 2024-12-23 00:28:55 +01:00
Luca Conte f73114eaeb Merge pull request 'cleanup-work' (#22) from cleanup-work into main
Reviewed-on: #22
2024-12-22 23:06:00 +00:00
Luca Conte 931a757a67 Merge branch 'main' into cleanup-work 2024-12-23 00:05:49 +01:00
Luca Conte 8b4b017e85 MORE javadoc 2024-12-23 00:03:54 +01:00
Luca Conte 6909b9417f FINALLY FIX THE INDENTATION REEEE 2024-12-23 00:03:46 +01:00
flo 29d4118d8f Merge pull request 'AiPlayer Kommentare hinzugefügt' (#21) from FH_Fixes into main
Reviewed-on: #21
Reviewed-by: lgc <main@lugico.de>
2024-12-22 22:36:39 +00:00
Kaver 0cea473146 smol jdoc changes 2024-12-22 23:17:52 +01:00
eyFlorian a4bfe5eb5f KI HART Orientierung
Harte Ki Orientiert sich an der Orientierung um sich zu Orientieren und unnötige Schüsse zu vermeiden.
2024-12-22 16:15:11 +01:00
Kaver 1e58626e6f jdoc 2024-12-22 00:02:03 +01:00
eyFlorian 9d62e74877 AiPlayer Kommentare hinzugefügt
Bitte nicht schlagen. Kommentare sind drin. Kommentiert ja, High Quality Kommentare nein (._.) Bitte nicht schlagen.
2024-12-21 21:11:21 +01:00
Joshua 8933a40d53 Changed the color of ships to white, as to make AI ships invisible. 2024-12-21 16:54:08 +01:00
Joshua cb9b110621 Added and integrated new sounds.
Added standardPort to be default value of port field.
2024-12-21 16:26:10 +01:00
Kaver 4dd1c9b39b Code aufräumen und kleine Anpassungen/Korrekturen vorgenommen 2024-12-20 19:39:56 +01:00
Luca Conte a3827d6bd0 add metric shit ton of javadoc comments 2024-12-20 18:29:49 +01:00
Luca Conte b7215db6d9 destroy players on game end 2024-12-20 17:57:50 +01:00
Luca Conte 7f610b4a90 Merge branch 'ole' into cleanup-work 2024-12-20 17:56:41 +01:00
Luca Conte 65451d6912 destroy for AI Player 2024-12-20 17:55:38 +01:00
ole bfb25dfe2c disable testButton 2024-12-20 17:32:53 +01:00
ole 3370975e57 change parameta from showPanelWin and loos to check the request 2024-12-20 17:31:32 +01:00
Luca Conte 20732e730c some cleanup 2024-12-20 17:31:16 +01:00
ole f4cf28f4bf add endScreen machanic 2024-12-20 17:30:21 +01:00
ole 7ef04711c3 add getter for Player 1 2024-12-20 17:29:37 +01:00
Luca Conte fdd2e6d2f1 Merge pull request 'lucasjoshua' (#20) from lucasjoshua into main
Reviewed-on: #20
2024-12-20 16:08:05 +00:00
Luca Conte 31e4d91baf Merge pull request 'FloA' (#19) from FloA into main
Reviewed-on: #19
2024-12-20 15:59:51 +00:00
FlorianAlexy 3c03e63899 Hard AI Verbesserung
besser aber nicht perfekt
2024-12-19 17:42:48 +01:00
Luca Conte f7d2e14196 game start fixes & AI Player Names 2024-12-19 17:23:45 +01:00
FlorianAlexy 8e4a516e2c smol fix
:3
2024-12-19 16:44:07 +01:00
Kaver e27b852c14 Kleine JavaDoc Anpassungen 2024-12-18 18:39:19 +01:00
Joshua 15c23c1f2c Added final TODOs 2024-12-17 17:21:59 +01:00
Kaver 0b2ee88316 mini Anpassungen 2024-12-17 17:13:40 +01:00
Joshua 42fc341608 Added more Javadoc (TODOs) comments. 2024-12-17 16:42:50 +01:00
Kaver 10e5a8ef5e WinScreen und LooseScreen erstellt zzgl. Methoden in MainFrame für Aufrufen aus dem Backend.
Diverse Javadoc Kommentaren hinzugefügt und alte nicht mehr Gebraucht Klassen entfernt.
Viel Code aufgeräumt
2024-12-17 16:30:05 +01:00
Joshua 1f04760f6a Added more Javadoc (TODOs) comments.
Added new sound.
temporarily disabled sound when hitting/sinking ships (buggy)
2024-12-17 15:58:05 +01:00
Joshua db2b0532bc Added more Javadoc (TODOs) comments. 2024-12-17 14:34:03 +01:00
Joshua 8c953a1f2b Added Javadoc comments to all FrontEnd classes.
Added functionality to mute button.
Added "//" comments to all Actionlisteners.
Added "Todo" where there is still need for something
2024-12-17 09:19:52 +01:00
Joshua 626ae041e5 Added 3 more sounds. Added function calls to test sounds, some still untested 2024-12-15 18:55:45 +01:00
Joshua f5a0f8c9fe Merge remote-tracking branch 'origin/main' into lucasjoshua 2024-12-15 17:17:39 +01:00
Joshua f1adf06035 Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-12-15 16:56:20 +01:00
Joshua e0748ceff9 Small Stuff 2024-12-15 16:55:59 +01:00
Kaver 0935c3bcb7 WinLoose grob erstellt 2024-12-15 16:55:29 +01:00
Luca Conte 78f6dd01f9 Merge pull request 'display improvements' (#18) from pewpew into main
Reviewed-on: #18
2024-12-15 15:54:33 +00:00
Luca Conte ec35646dab display improvements 2024-12-15 16:54:04 +01:00
Joshua d8804d5369 Added TODO for frontend 2024-12-15 16:17:02 +01:00
Luca Conte 6857df94e0 Merge pull request 'pewpew' (#17) from pewpew into main
Reviewed-on: #17
2024-12-15 15:08:21 +00:00
Luca Conte d7637e1e51 Merge branch 'main' into pewpew 2024-12-15 16:05:09 +01:00
Luca Conte 7b80e3dfd3 Merge pull request 'lucasjoshua' (#16) from lucasjoshua into main
Reviewed-on: #16
2024-12-15 15:02:32 +00:00
Kaver 37a984772c Javadoc Kommentare erweitert in BoardDisplay 2024-12-15 16:01:52 +01:00
Joshua c0f22cec6e Cleaned up code 2024-12-15 16:01:11 +01:00
Luca Conte d9a93952d2 PEW PEW 2024-12-15 15:59:26 +01:00
Kaver ad61fcecb7 Anpasung an paintFields, sodass preview unterscheidet, ob setzen von Schiff valide ist 2024-12-15 15:51:32 +01:00
Kaver b4f1de82bd Preview des setzen von Schiffen 2024-12-15 15:25:53 +01:00
Luca Conte 60e44f2e1a add getVirtualOccupiedPoints 2024-12-15 15:10:20 +01:00
Kaver 7605646b80 Action Listener Update fuer BoardDisplay 2024-12-15 14:51:40 +01:00
Kaver 5be3f4daf3 Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-12-15 14:44:41 +01:00
Luca Conte 0391b3265a Merge pull request 'fix horizontal' (#15) from lucasjoshua into main
Reviewed-on: #15
2024-12-15 13:42:34 +00:00
Luca Conte 864ca20e18 fix horizontal 2024-12-15 14:42:18 +01:00
Luca Conte 9e07350f7d Merge pull request 'lucasjoshua' (#14) from lucasjoshua into main
Reviewed-on: #14
2024-12-15 13:27:15 +00:00
Luca Conte b5f1151a4f add checkValidShipPlacement and set horizontal in setPosition 2024-12-15 14:26:42 +01:00
Luca Conte f565708461 implement ready for players and board refresh method 2024-12-15 14:21:17 +01:00
Joshua 970550308b Fixed showing Player names in GameBoard.
Added functionality to Button coloring (when selected, placed etc.)
2024-12-15 13:48:01 +01:00
Luca Conte d1dbcfe603 remove isPlaced field 2024-12-15 12:54:36 +01:00
Luca Conte 256d769ccf add ship reset position 2024-12-15 12:53:44 +01:00
Luca Conte 80b5d8e701 set player names 2024-12-15 12:40:12 +01:00
Joshua d3f5421808 Added kontextText variations.
Added functionality to "Ready" Button.
2024-12-14 17:26:46 +01:00
Kaver 587d88f764 Reset Button Funktionalität hinzugefuegt 2024-12-14 16:47:12 +01:00
Joshua decef526da Fixed ship rotation method.
Added pulsating Effect for "kontextText"
2024-12-14 15:29:45 +01:00
Joshua bf78db9404 Added (currently not working) ship rotation method, colored Ready and Reset button, added (currently not working) Player name Labels etc. to GameBoard 2024-12-13 20:46:38 +01:00
Kaver a7e7d75c62 Button ausschalten wenn Schiff gesetzt wurde, nicht komplett richtige Funktion 2024-12-13 20:30:15 +01:00
Luca Conte 88ec23c5e5 fix ship placing :) 2024-12-13 19:12:26 +01:00
Kaver bd3976cc0c ShipButton hinzugefuegt,Schiffe setzen WIP 2024-12-13 18:47:14 +01:00
Luca Conte fd5a97cd6e Merge pull request 'start game stuff - both online and offline' (#13) from start-game into main
Reviewed-on: #13
2024-12-13 16:27:43 +00:00
Luca Conte dfbe4b3c53 fix online game start 2024-12-13 17:26:18 +01:00
Luca Conte 5ba5919775 Merge branch 'lucasjoshua' into start-game 2024-12-13 17:24:17 +01:00
Kaver 00df38dd7a Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua
# Conflicts:
#	src/BoardDisplay.java
2024-12-13 17:06:45 +01:00
Kaver f397803b64 Kleine Anpassung von BoardDisplay 2024-12-13 17:00:51 +01:00
Luca Conte fd82e64814 remove connection timeout 2024-12-13 16:59:02 +01:00
Joshua 84865e5468 Added comments (Javadoc etc.) to most GUI classes und deleted old code and comments etc. (in general cleanup) 2024-12-12 17:19:35 +01:00
Kaver adac40156a Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-12-11 16:04:06 +01:00
Joshua 6f9f5c5063 Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-12-10 17:26:58 +01:00
Joshua bb61a68f24 Player names will now be passed correctly between classes. Added lots of comments in startLocalGame, startLocalGameLoadingScreen, startMultiplayerGame and JoinGame. 2024-12-10 17:26:27 +01:00
Kaver 663991e418 Merge remote-tracking branch 'origin/start-game' into lucasjoshua
# Conflicts:
#	src/JoinGame.java
2024-12-10 16:58:38 +01:00
Kaver 8a9e7fb4b2 Implementierung von Schiffe platzieren gestartet(BoardDisplay),
Anpassungen an Buttons im GameBoard sowie diverse getter hinzugefeugt(backend)
2024-12-10 16:52:10 +01:00
Luca Conte 60e6ed1277 kill the zombies 2024-12-10 14:42:15 +01:00
Luca Conte 5cf8befdc1 add todo 2024-12-10 14:08:00 +01:00
Luca Conte ffa04a50cb set IP to 0.0.0.0 in server mode 2024-12-10 14:07:56 +01:00
Luca Conte 21563dd469 remove unused imports 2024-12-10 14:07:45 +01:00
Luca Conte 7f5e031574 find correct constructor 2024-12-10 14:07:39 +01:00
Luca Conte 44f2b0f0f1 move socket connection into thread within AsyncSocket 2024-12-10 14:07:16 +01:00
Joshua 3b6ffeb82d JoinGame and related functions should now work properly 2024-12-10 13:48:55 +01:00
Luca Conte 9ab97b5f0c Merge branch 'lucasjoshua' into start-game 2024-12-10 12:51:11 +01:00
Joshua f151a89ea4 Added function to JoinGame. 2024-12-10 12:50:26 +01:00
Luca Conte c55a62663e pass main frame to game controller 2024-12-10 12:50:19 +01:00
Luca Conte b958ffd6b9 initialise board arrays correctly 2024-12-10 12:44:34 +01:00
Luca Conte 6a57a6e1ff remove unused import 2024-12-10 12:44:01 +01:00
Luca Conte 9ff0958fbc start game in frontend 2024-12-10 12:39:41 +01:00
Luca Conte 6118d480d9 Merge pull request 'lucasjoshua' (#12) from lucasjoshua into main
Reviewed-on: #12
2024-12-10 11:38:36 +00:00
Joshua 7a9b70c271 Started making changes to JoinGame etc. 2024-12-10 12:36:34 +01:00
Kaver 0ef34e18eb Anpassungen/Erweiterungen an dem Spielfeld durch BoardDisplay und GameBoard
Test Button hinzugefuegt um auf Spielfeld JPanel zu wechseln
2024-12-04 15:38:10 +01:00
Joshua 15ff3034d3 Added Comments to MainFrame,
Fixed functionality of left/right buttons after adding more difficulties in startLocalGame and startMultiplayerGame
2024-12-04 11:51:00 +01:00
Joshua 7ee0f9c097 Added AI difficulties, and updated methods to cycle between them correctly 2024-12-03 16:42:37 +01:00
Joshua 48bc601a0d Added BoardDisplay, startet connecting FrontEnd/BackAnd.
Added new graphics.
Added startLocalGameLoadingScreen
2024-12-03 15:33:15 +01:00
Luca Conte f20896566c Merge pull request 'game-controller-adjustments' (#11) from game-controller-adjustments into main
Reviewed-on: #11
2024-12-03 12:48:14 +00:00
Luca Conte d9baeec957 make all methods static, add player name to start game method params 2024-12-03 13:47:36 +01:00
Luca Conte f166200499 add static main frame 2024-12-03 13:47:13 +01:00
Luca Conte 2c84e02261 Merge pull request 'Network and Frontend' (#10) from ole into main
Reviewed-on: #10
Reviewed-by: lgc <main@lugico.de>
2024-12-03 12:13:27 +00:00
ole 175bb20345 change idea settings 2024-12-03 13:11:06 +01:00
ole 0ce9e012dd Merge remote-tracking branch 'origin/lucasjoshua' into ole
# Conflicts:
#	src/startMultiplayerGame.java
2024-12-03 12:28:26 +01:00
Joshua 772f2d45c6 Added Backbutton function to GameBoard 2024-12-03 12:23:46 +01:00
ole 2160b5d410 add shoot to OnlinePlayer_1_1_0.java 2024-12-03 12:20:40 +01:00
Ole Wachtel 43545afb45 add coin flip and turn logic 2024-12-03 12:11:06 +01:00
Kaver 3b9b1eaebb Klasse fuer verbinden Panel erstellt(extrem grobes Beispiel) und Panel Weiterleitung eingefuegt
Anpassungen an ActionListenern in MainMenuView

Backbutton mit Funktion eingefuegt fuer joinGame Panel
2024-12-02 19:04:34 +01:00
Luca Conte addf542300 strip string before passing to handler 2024-11-30 18:43:04 +01:00
Luca Conte 1fb284eb1a add IAM Package 2024-11-30 18:40:04 +01:00
Luca Conte bdde2066f3 add getter and setter for name 2024-11-30 18:39:58 +01:00
Luca Conte ab1aae7798 add method to convert semester to board size 2024-11-30 18:39:41 +01:00
Luca Conte cecc44abf4 fix: remove board size from constructor 2024-11-30 18:28:05 +01:00
Luca Conte 998ff3d663 Merge branch 'networking' into networking-start-online-game 2024-11-30 18:16:27 +01:00
Luca Conte 2c6f9adf54 move board size out of player constructor 2024-11-30 18:15:07 +01:00
Luca Conte 3eeb4d25bd start online game 2024-11-30 17:58:24 +01:00
ole b1273e759d Merge remote-tracking branch 'origin/ole' into ole
# Conflicts:
#	src/OnlinePlayer.java
2024-11-30 17:15:51 +01:00
ole 6a4e157605 add: Network implementation 2024-11-30 17:09:44 +01:00
ole 22950cd155 add: Thread protection Player.java 2024-11-30 17:07:11 +01:00
ole 058d069ff2 change: all Points from java.awt.point too new Point.java 2024-11-30 17:06:25 +01:00
ole c2ca83c718 chore: remove all unjust imports 2024-11-30 17:04:29 +01:00
ole 5a48e7e0a9 Merge branch 'networking' into ole 2024-11-30 14:17:54 +01:00
Luca Conte 8bc64bd9ba move joined logic out of if statement 2024-11-30 14:14:29 +01:00
Luca Conte ff9ffbd628 sleep first in loop to avoid skipping sleep with continue 2024-11-30 14:13:15 +01:00
Luca Conte 7303f49d0d avoid nulls 2024-11-30 14:13:01 +01:00
ole 48a5958414 add Thread safety for Player 2024-11-30 13:48:50 +01:00
Luca Conte c92b3b3551 networking basis 2024-11-30 13:45:06 +01:00
Ole Wachtel a381c8d660 add OnlinePlayer Konstructer 2024-11-30 13:25:42 +01:00
Luca Conte d425e64fa0 Merge pull request 'hotfixes - so we can at least run it' (#9) from hotfixes into main
Reviewed-on: #9
2024-11-27 12:01:15 +00:00
Luca Conte b2a26c1f81 fix compiler errors 2024-11-27 13:00:18 +01:00
Luca Conte 73add1442b fix class names 2024-11-27 13:00:05 +01:00
Luca Conte 11c7dda19b fix deprecated function calls 2024-11-27 12:59:55 +01:00
Joshua 2274a1e558 Created GameBoard.
Added showPanel methods to pass parameters between methods.
2024-11-26 17:15:21 +01:00
alexy f3d56b37c7 Merge pull request 'Schiffe setzen Validierung hinzugefuegt' (#8) from oleFundF into main
Reviewed-on: #8
Reviewed-by: flo <florian.hantzschel@stud.hs-hannover.de>
2024-11-26 16:00:08 +00:00
FlorianAlexy c8b3f4f2db Schiffe setzen Validierung hinzugefuegt
Florian und Florian haben eine schoene Validierung zum setzen der Position eines Schiffes hinzugefuegt.
2024-11-26 16:43:25 +01:00
Kaver 88d016ed99 Umstrukturierung von MainFrame, sodass beim druecken eines Buttons parameter an die Funktion uebergeben werden welche das naechste Panel stellt (showPanelExtra) 2024-11-26 16:43:14 +01:00
Kaver 5cabd5325a Umstrukturierung von MainFrame, sodass beim druecken eines Buttons parameter an die Funktion uebergeben werden welche das naechste Panel stellt (showPanelExtra) 2024-11-26 16:42:00 +01:00
Luca Conte ec789dd562 Merge pull request 'ole' (#7) from ole into main
Reviewed-on: #7
Reviewed-by: lgc <main@lugico.de>
2024-11-26 14:01:01 +00:00
ole d00e12e72f Merge remote-tracking branch 'origin/lucasjoshua' into ole
# Conflicts:
#	src/HalloSchiffeVersenken.java
2024-11-26 14:56:19 +01:00
Joshua 1fc1abee3a Merge remote-tracking branch 'origin/lucasjoshua' into lucasjoshua 2024-11-26 14:14:43 +01:00
Joshua 3d557361ee Implemented coinToss(still incomplete) 2024-11-26 14:13:14 +01:00
eyFlorian aaa9d57f68 Easy/MediumAI
Haben eine sehr einfache und Medium KI hinzugefügt. F&F

Fragenaufwerfende Methoden:

https://cdn.discordapp.com/attachments/1296860613212897413/1310209916325068894/WhatsApp_Bild_2024-11-24_um_12.31.02_fb836c3d.jpg?ex=67446392&is=67431212&hm=82f37b83dc5e711622abb43abe51edd62833450dddf91ed524991da6d0981f38&
2024-11-24 12:47:45 +01:00
Kaver ea6a1c9804 grobe Weiterleitung fuer startMultiplayerGame an Spiel beitreten/Spiel erstellen eingefügt 2024-11-19 18:33:05 +01:00
Joshua 737e485773 Implemented coinToss(still incomplete) 2024-11-19 17:37:16 +01:00
Joshua 6ef3b38dd5 Implemented CardLayout into startMultiplayerGame, startLocalGame, MainMenuView. Implemented MainFrame. 2024-11-19 17:08:59 +01:00
Joshua 8069315c15 Implemented CardLayout into startMultiplayerGame, startLocalGame, MainMenuView. Implemented MainFrame. 2024-11-19 16:25:52 +01:00
Kaver a84110a8a8 Panellogik neu gemacht und dementsprechend views angepasst 2024-11-19 15:41:45 +01:00
Joshua 607004a3b3 Added test classes for CardLayout and GameBoard.java 2024-11-19 14:24:09 +01:00
Kaver d95df0cf5f Minimale Anpassung an Actionlistener fuer MainMenu zu LocalGame 2024-11-19 13:39:43 +01:00
Kaver 5bedfddc60 Erste Anpassungen an Multiplayermenu (sehr grob)
diverse alte ungenutzte Methoden entfernt
2024-11-18 18:20:48 +01:00
Joshua f7326a57d9 Added coinToss.java, first attempts integrating cardlayout in startLocalGame.java and startMultiplayerGame.java 2024-11-16 15:26:52 +01:00
Kaver a11885c76d Transission von Main zu MultiMenu angepasst
Panels eingeführt anstatt neue Frames zu öffnen
MainmenuController angepasst
2024-11-15 18:34:05 +01:00
Joshua fe942ab660 Continued work on startLocalGame and started work startMultiplayerGame 2024-11-15 18:18:28 +01:00
Joshua 15d5a67c38 Continued work on startLocalGame and started work startMultiplayerGame 2024-11-15 18:18:21 +01:00
ole ce4995fb94 add Shoot logik and Structure for backend 2024-11-15 17:35:35 +01:00
Joshua 016ef2a317 Test 2024-11-15 16:26:30 +01:00
Kaver 393984343c Grafiken in graphics Ordner verschoben 2024-11-15 16:24:38 +01:00
ole 22937ab45d Merge pull request 'Kronjuwild' (#6) from Kronjuwild into main
Reviewed-on: #6
Reviewed-by: ole <git@peer-ole.de>
2024-11-14 16:23:21 +00:00
Luca Conte b9a0a21503 fix some player stuff 2024-11-12 15:18:16 +01:00
Ole Wachtel 579ce9831d Merge branch 'FF24' into ole 2024-11-12 15:06:33 +01:00
eyFlorian 8ae51f6316 Locales Spiel Initialisierung
Florian und Florian Haben 3 Stunden an diesem kack gearbeitet.
Player, AiPlayer und jeweils die Boards wurden erstellt und Initialisiert.
Erweiterung zu Hitresponse /- type für die Board.
2024-11-03 12:39:19 +01:00
55 changed files with 4172 additions and 309 deletions

View File

@ -1,8 +1,7 @@
<component name="libraryTable">
<library name="jlayer-1.0.3">
<CLASSES>
<root url="jar://$USER_HOME$/Downloads/jlayer-master/jlayer-master/target/jlayer-1.0.3.jar!/" />
<root url="jar://$USER_HOME$/Downloads/jlayer-1.0.3.jar!/" />
<root url="jar://$PROJECT_DIR$/libs/jlayer-1.0.3.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES />

124
.idea/uiDesigner.xml Normal file
View File

@ -0,0 +1,124 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Palette2">
<group name="Swing">
<item class="com.intellij.uiDesigner.HSpacer" tooltip-text="Horizontal Spacer" icon="/com/intellij/uiDesigner/icons/hspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="1" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="com.intellij.uiDesigner.VSpacer" tooltip-text="Vertical Spacer" icon="/com/intellij/uiDesigner/icons/vspacer.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="1" anchor="0" fill="2" />
</item>
<item class="javax.swing.JPanel" icon="/com/intellij/uiDesigner/icons/panel.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3" />
</item>
<item class="javax.swing.JScrollPane" icon="/com/intellij/uiDesigner/icons/scrollPane.svg" removable="false" auto-create-binding="false" can-attach-label="true">
<default-constraints vsize-policy="7" hsize-policy="7" anchor="0" fill="3" />
</item>
<item class="javax.swing.JButton" icon="/com/intellij/uiDesigner/icons/button.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="0" fill="1" />
<initial-values>
<property name="text" value="Button" />
</initial-values>
</item>
<item class="javax.swing.JRadioButton" icon="/com/intellij/uiDesigner/icons/radioButton.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="RadioButton" />
</initial-values>
</item>
<item class="javax.swing.JCheckBox" icon="/com/intellij/uiDesigner/icons/checkBox.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="3" anchor="8" fill="0" />
<initial-values>
<property name="text" value="CheckBox" />
</initial-values>
</item>
<item class="javax.swing.JLabel" icon="/com/intellij/uiDesigner/icons/label.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="8" fill="0" />
<initial-values>
<property name="text" value="Label" />
</initial-values>
</item>
<item class="javax.swing.JTextField" icon="/com/intellij/uiDesigner/icons/textField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JPasswordField" icon="/com/intellij/uiDesigner/icons/passwordField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JFormattedTextField" icon="/com/intellij/uiDesigner/icons/formattedTextField.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1">
<preferred-size width="150" height="-1" />
</default-constraints>
</item>
<item class="javax.swing.JTextArea" icon="/com/intellij/uiDesigner/icons/textArea.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTextPane" icon="/com/intellij/uiDesigner/icons/textPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JEditorPane" icon="/com/intellij/uiDesigner/icons/editorPane.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JComboBox" icon="/com/intellij/uiDesigner/icons/comboBox.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="2" anchor="8" fill="1" />
</item>
<item class="javax.swing.JTable" icon="/com/intellij/uiDesigner/icons/table.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JList" icon="/com/intellij/uiDesigner/icons/list.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="2" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTree" icon="/com/intellij/uiDesigner/icons/tree.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3">
<preferred-size width="150" height="50" />
</default-constraints>
</item>
<item class="javax.swing.JTabbedPane" icon="/com/intellij/uiDesigner/icons/tabbedPane.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSplitPane" icon="/com/intellij/uiDesigner/icons/splitPane.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="3" hsize-policy="3" anchor="0" fill="3">
<preferred-size width="200" height="200" />
</default-constraints>
</item>
<item class="javax.swing.JSpinner" icon="/com/intellij/uiDesigner/icons/spinner.svg" removable="false" auto-create-binding="true" can-attach-label="true">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSlider" icon="/com/intellij/uiDesigner/icons/slider.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="8" fill="1" />
</item>
<item class="javax.swing.JSeparator" icon="/com/intellij/uiDesigner/icons/separator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="6" anchor="0" fill="3" />
</item>
<item class="javax.swing.JProgressBar" icon="/com/intellij/uiDesigner/icons/progressbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1" />
</item>
<item class="javax.swing.JToolBar" icon="/com/intellij/uiDesigner/icons/toolbar.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="6" anchor="0" fill="1">
<preferred-size width="-1" height="20" />
</default-constraints>
</item>
<item class="javax.swing.JToolBar$Separator" icon="/com/intellij/uiDesigner/icons/toolbarSeparator.svg" removable="false" auto-create-binding="false" can-attach-label="false">
<default-constraints vsize-policy="0" hsize-policy="0" anchor="0" fill="1" />
</item>
<item class="javax.swing.JScrollBar" icon="/com/intellij/uiDesigner/icons/scrollbar.svg" removable="false" auto-create-binding="true" can-attach-label="false">
<default-constraints vsize-policy="6" hsize-policy="0" anchor="0" fill="2" />
</item>
</group>
</component>
</project>

BIN
Sound/hit.mp3 Normal file

Binary file not shown.

BIN
Sound/loosescreenlaugh.mp3 Normal file

Binary file not shown.

BIN
Sound/plop.mp3 Normal file

Binary file not shown.

BIN
Sound/shipdestroyed.mp3 Normal file

Binary file not shown.

BIN
Sound/win.mp3 Normal file

Binary file not shown.

BIN
Sound/yourturn.mp3 Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 396 B

BIN
graphics/botPlayerEasy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 854 B

BIN
graphics/botPlayerHard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 875 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 889 B

BIN
graphics/gameboardempty.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 B

BIN
graphics/gameboardx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 B

View File

Before

Width:  |  Height:  |  Size: 2.2 MiB

After

Width:  |  Height:  |  Size: 2.2 MiB

View File

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

Before

Width:  |  Height:  |  Size: 959 B

After

Width:  |  Height:  |  Size: 959 B

View File

@ -29,6 +29,9 @@ test-jar: jar
# $(JR) -cp "$(OUT_DIR)/:$(LIB_DIR)/*" $(MAIN_CLASS)
$(JR) -jar $(OUT_DIR)/$(JAR_NAME)
docs:
javadoc -cp "$(LIB_DIR)/*" -d "docs" $(SRC_DIR)/*.java
test: classfiles
$(JR) -cp "$(OUT_DIR)$(SEPERATOR)$(LIB_DIR)/*" $(MAIN_CLASS)

167
src/AiPlayer.java Normal file
View File

@ -0,0 +1,167 @@
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
/**
* Die Klasse AiPlayer ist die Basis für alle Ki Spieler und jede Spezifische Ki erweitert diese Klasse.
* @author Florian Alexy und Florian Hantzschel
* */
public abstract class AiPlayer extends LocalPlayer implements Runnable {
/**
* Liste aller erstellten ShootThreads
*/
List<Thread> shootThreads;
/**
* Konstruktor
* @author Florian Alexy und Florian Hantzschel
*/
public AiPlayer() {
this.setName("AI Player");
this.shootThreads = new ArrayList<>();
}
/**
* Gibt einen zufälligen Punkt im Spielfeld zurück.
* @return Ein zufälliger Punkt
* @author Florian Alexy und Florian Hantzschel
*/
public Point RandomPoint() {
Random random = new Random(); // Pseudo Random für zufallszahlen
int posx = random.nextInt(super.board.getSize()); // Generiert 0 - 13
int posy = random.nextInt(super.board.getSize()); //
return new Point(posx,posy);
}
/**
* Initialisiert das Board.
* @param size größe des Boards
* @author Florian Alexy und Florian Hantzschel
*/
@Override
public void createBoard(int size) {
super.createBoard(size);
this.aiSetShips();
this.ready();
}
/**
* Ki Methode zum zufälligen Setzten der Schiffe
* @author Florian Alexy und Florian Hantzschel
*/
public void aiSetShips() {
for(int i = 0; i < super.board.getShips().size(); i++) { // Interiert durch alle Shiffe
//TODO: set horizontal
while(!super.board.getShips().get(i).setPosition(RandomPoint(), true, super.board.getShips(), super.board.getSize())) {}
} // Versucht das aktuelle Schiff zu setzten und wiederholt solange bis es funktioniert
return;
}
/**
* Ki Methode zum zufälligen Schießen auf das gegnerische Board.
* @author Florian Alexy und Florian Hantzschel
*/
public void aiShoot() {
if (!this.myTurn) return;
this.enemy.receiveShoot(RandomPoint());
return;
}
/**
* Nachdem receiveShoot beim gegner den schuss verarbeitet hat,
* wird diese Methode mit der antwort aufgerufen.
* @param hitResponse the hitresponse
* @author Florian Alexy und Florian Hantzschel und Luca Conte
*/
@Override
public synchronized void receiveHit(HitResponse hitResponse) {
// Eltern-Klasse LocalPlayer updatet myTurn
super.receiveHit(hitResponse);
if (this.myTurn) {
// Neuer Schuss wird erstellt und gestartet.
Thread t = new Thread(this);
t.start();
this.shootThreads.add(t);
}
}
/**
* Erhält einen schuss vom gegner und verarbeitet ihn.
* @param point the location to be shot
* @author Florian Alexy und Florian Hantzschel und Luca Conte
*/
@Override
public synchronized void receiveShoot(Point point) {
super.receiveShoot(point);
if (this.myTurn) {
Thread t = new Thread(this);
t.start();
this.shootThreads.add(t);
}
}
/**
* Wird aufgerufen, wenn in determineCoinToss festgestellt wurde das die Ki anfängt.
* Erster Schuss wird gestartet.
* @author Florian Alexy und Florian Hantzschel und Luca Conte
*/
@Override
public void beginTurn() {
Thread t = new Thread(this);
t.start();
this.shootThreads.add(t);
}
/**
* Closes past threads and tries firing a shot.
* @author Luca Conte, Florian Alexy und Florian Hantzschel
*/
public void run() {
Iterator<Thread> i = this.shootThreads.iterator();
while(i.hasNext()) {
Thread thread = i.next();
if (!thread.isAlive()) {
try {
thread.join();
i.remove();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
try {
Thread.sleep(250);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
this.aiShoot();
}
/**
* Closes all running threads and does some cleanup work so the garbage collector will delete the player
* @author Luca Conte
*/
@Override
public void destroy() {
super.destroy();
Iterator<Thread> i = this.shootThreads.iterator();
while(i.hasNext()) {
Thread thread = i.next();
try {
thread.interrupt();
thread.join();
i.remove();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
}

238
src/AsyncSocket.java Normal file
View File

@ -0,0 +1,238 @@
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
/**
* Provides an Interface to communicate using a socket asynchronously
* @author Luca Conte, Peer Ole Wachtel
*/
public class AsyncSocket {
private Socket socket;
private Thread checkerThread;
private Thread connectorThread;
private AsyncSocketListener handler;
private boolean shouldStop = false;
private String sendBuffer = "";
private BufferedReader in;
private BufferedWriter out;
/**
* Creates a socket server and turns the first incoming connection into an AsyncSocket
* @param port the port to listen on for a connection
* @param handler the handler that will be called when a message is received
* @author Luca Conte
*/
public AsyncSocket(int port, AsyncSocketListener handler) {
this.setHandler(handler);
// start server in new thread
this.connectorThread = new Thread(() -> {
try {
ServerSocket serverSocket = new ServerSocket(port);
System.out.println("Waiting for client connection on port " + port);
Socket socket = serverSocket.accept();
System.out.println("Socket connected.");
serverSocket.close();
this.initSocket(socket);
} catch (IOException e) {
e.printStackTrace();
// TODO: proper error handling
}
});
this.connectorThread.start();
}
/**
* Connects to the address provided and turns the resulting socket into an AsyncSocket
* @param address the socket address to connect to
* @param handler the handler that will be called when a message is received
* @author Luca Conte
*/
public AsyncSocket(InetSocketAddress address, AsyncSocketListener handler) {
this.setHandler(handler);
// start client in new thread
this.connectorThread = new Thread(() -> {
System.out.println("Connecting to " + address.toString());
Socket socket = new Socket();
try {
socket.connect(address, 10);
System.out.println("Socket connected.");
this.initSocket(socket);
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("Connection timed out");
}
});
this.connectorThread.start();
}
/**
* @param socket the socket to be wrapped in an AsyncSocket
* @param handler the handler that will be called when a message is received
* @author Luca Conte
*/
public AsyncSocket(Socket socket, AsyncSocketListener handler) throws IOException {
this.setHandler(handler);
this.initSocket(socket);
}
/**
* creates input and ouput writer / readers as well as a checker thread to repeatedly check
* for incoming messages
* @param socket the socket to be wrapped
* @author Luca Conte
*/
private void initSocket(Socket socket) throws IOException {
System.out.println("Initialising sockets");
this.socket = socket;
this.in = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.out = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));
this.shouldStop = false;
this.checkerThread = new Thread(() -> {
while (!this.shouldStop) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (!this.connectorThread.isAlive()) {
try {
this.connectorThread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
if (!this.in.ready()) {
continue;
}
if (this.handler == null) {
continue;
}
String message = this.in.readLine();
if (message.length() <= 0) continue;
message = message.strip();
System.out.println("RECEIVED - " + message);
this.handler.receive(message);
} catch (IOException e) {
e.printStackTrace();
}
}
});
System.out.println("starting checker thread");
this.checkerThread.start();
this.flushBuffer();
}
/**
* sets the message handler for the async socket
* @param handler the `AsyncSocketListener` to be set as the new handler
* @author Luca Conte
*/
public void setHandler(AsyncSocketListener handler) {
this.handler = handler;
}
/**
* sends a message through the socket
* @param socketPackage the socket package to be sent
* @author Luca Conte
*/
public synchronized void send(SocketPackage socketPackage) {
this.sendLine(socketPackage.toString());
}
/**
* sends a message through the socket
* @param packageName the name of the package to be sent
* @author Luca Conte
*/
public synchronized void send(String packageName) {
this.send(packageName, "");
}
/**
* sends a message through the socket
* @param packageName the name of the package to be sent
* @param packageContent the content of the package to be sent.
* `packageName` and `packageContent` are joined with a space " "
* @author Luca Conte
*/
public synchronized void send(String packageName, String packageContent) {
if (packageContent.length() > 0) {
packageContent = " " + packageContent;
}
this.sendLine(packageName + packageContent);
}
/**
* sends a string of text into the socket, concatenated with CRLF
* @author Luca Conte
*/
public synchronized void sendLine(String message) {
sendBuffer = sendBuffer + message + "\r\n";
this.flushBuffer();
}
/**
* flushes the buffers to send all pending messages
* @author Luca Conte
*/
private synchronized void flushBuffer() {
if (!this.sendBuffer.isEmpty() && this.out != null) {
try {
this.out.write(sendBuffer);
System.out.println("SENT - " + sendBuffer);
sendBuffer = "";
this.out.flush();
} catch (IOException e) {
e.printStackTrace();
// TODO: handle writing error
}
}
}
/**
* closes the socket connection and removes the checker thread
* @author Luca Conte
*/
public void close() {
this.shouldStop = true;
try {
this.socket.close();
if (this.checkerThread != null) {
this.checkerThread.interrupt();
this.checkerThread.join();
}
} catch (IOException e) {
e.printStackTrace();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}

View File

@ -0,0 +1,7 @@
/**
* defines a message listener for AsyncSockets
* @author Luca Conte
*/
public interface AsyncSocketListener {
public void receive(String message);
}

View File

@ -1,2 +1,162 @@
import java.util.ArrayList;
import java.util.List;
/**
* Diese Klasse ist das Board von eimem spieler und enthält alle logischen operationen.
* Sprich ist das Backend Board.
*
* @author Peer Ole Wachtel, Florian Alexy und Florian Hantzschel
*/
public class Board {
/**
* Alle bisher empfangenen HitResponsen
*/
private List<HitResponse> hits;
/**
* Alle Schiffe des Semesters
*/
private List<Ship> ships;
/**
* Die größe des Spielfeldes
*/
private final int size;
/**
* Erstellt ein neues Board.
* setzt die übergebene Spielfeldgröße.
* Erstellt die Liste aller Schiffe des Semesters
* @param size Die größe des Spielfeldes
* @author Peer Ole Wachtel, Florian Alexy und Florian Hantzschel
*/
public Board(int size) {
this.size = size;
this.ships = new ArrayList<>();
this.hits = new ArrayList<>();
this.createShip(size - 13);
}
/**
* Nimmt einen punkt entgegen und Gibt einen HitResponse zurück.
* @param point auf den geschossen wurde
* @return
* @author Peer Ole Wachtel
*/
public synchronized HitResponse hit (Point point){
HitResponse response = new HitResponse(HitResponseType.MISS,point);
for (int i = 0; i < this.ships.size(); i++) {
HitResponseType type = this.ships.get(i).shootOnShip(point);
if ( type == HitResponseType.SUNK) {
for (int ii = 0; ii < this.ships.size(); ii++) {
if (!this.ships.get(ii).isSunk()) {
response.setType(type);
this.addHits(response);
return response;
}
}
response.setType(HitResponseType.VICTORY);
this.addHits(response);
return response;
} else if (type == HitResponseType.HIT) {
response.setType(type);
this.addHits(response);
return response;
}
}
this.addHits(response);
return response;
}
/**
* finds adjacened hit responses and sets their type to SUNK if they are currently HIT
* this makes it so that all the points of the ship are marked as SUNK, not just the final hit
* @param p the Point from which to propate the SUNK type
* @author Luca Conte
*/
private void propagateSunk(Point p) {
HitResponse hit = this.getHitResponseOnPoint(p);
if (hit == null || hit.getType() != HitResponseType.HIT) return;
hit.setType(HitResponseType.SUNK);
propagateSunk(new Point(p.getX() + 1, p.getY()));
propagateSunk(new Point(p.getX() - 1, p.getY()));
propagateSunk(new Point(p.getX(), p.getY() + 1));
propagateSunk(new Point(p.getX(), p.getY() - 1));
}
/**
* creates all the ships on a board given a certain semester
* @param semester the semester to be played in
* @author Peer Ole Wachtel
*/
private void createShip(int semester){
List<ShipData> shipData = Ship.semeterList.get(semester-1);
for (int i = 0; i < shipData.size(); i++) {
this.ships.add(new Ship(shipData.get(i).size(), shipData.get(i).name()));
}
}
/**
* returns a list of all the Ships on the board
* @return a list of all the Ships on the board
* @author Peer Ole Wachtel
*/
public List<Ship> getShips() {
return ships;
}
/**
* adds a HitResponse to the list of Hits on the board
* If a hit response already exists on the same position, the hit response will not be added
* If the hit response is of type `HitResponseType.SUNK` it will propagate this hit response type
* to all adjacened hit responses with type HIT using `propagateSunk`.
* @param hitResponse the HitResponse to be added
* @return true when the hit response was added, otherwise false
* @author Peer Ole Wachtel, Luca Conte
*/
public synchronized boolean addHits(HitResponse hitResponse) {
if (this.getHitResponseOnPoint(hitResponse.getPoint()) == null){
this.hits.add(hitResponse);
//Propagate sunk for display purposes
if (hitResponse.getType() == HitResponseType.SUNK) {
hitResponse.setType(HitResponseType.HIT);
propagateSunk(hitResponse.getPoint());
}
return true;
}
return false;
}
/**
* @param point the position to get the hit response from
* @return the hit response at the position `point`
* @author Peer Ole Wachtel
*/
public synchronized HitResponse getHitResponseOnPoint(Point point) {
for (int i = 0; i < this.hits.size(); i++){
if (this.hits.get(i).getPoint().equals(point)){
return this.hits.get(i);
}
}
return null;
}
/**
* returns the size of the board
* @return the size of the board
* @author Florian Alexy, Florian Hantzschel
*/
public int getSize() {
return this.size;
}
}

254
src/BoardDisplay.java Normal file
View File

@ -0,0 +1,254 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;
/**
* Dient dem Aufbau der Matrix (Spielfeld) und füllt diese mit Funktion
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public class BoardDisplay extends JPanel {
private JButton[][] fields;
private int gridSize;
private Ship currentShip;
private Player player;
private boolean horizontal = false;
private List<ShipButton> shipButtonList;
private boolean enemyBoard;
private Point mousePosition;
/**
* Fügt Buttons zu Liste hinzu und aktualisiert Feld durch Aufruf von paintFields
* @param button Jeweiliger Button der hinzugefügt werden soll
* @author Joshua Kuklok
*/
public void addShipButton(ShipButton button) {
shipButtonList.add(button);
paintFields();
}
/**
* Gibt currentShip zurück
* @return currentShip Objekt der Klasse Schiff
* @author Lucas Bronson Luca Conte
*/
public Ship getCurrentShip() {
return currentShip;
}
/**
* Konstruktor des Board Displays
* @param gridSize Die Größe des Spielfelds
* @param player Der Spieler
* @author Lucas Bronson
*/
public BoardDisplay(int gridSize, Player player, boolean enemyBoard) {
super(new GridLayout(gridSize + 1, gridSize + 1)); // +1 wegen extra Zeile/Spalte
this.fields = new JButton[gridSize][gridSize];
this.shipButtonList = new ArrayList<>();
this.player = player;
this.gridSize = gridSize;
this.enemyBoard = enemyBoard;
// Erstellung vom Spielfeld
for (int i = 0; i <= gridSize; i++) {
for (int j = 0; j <= gridSize; j++) {
final int x = j - 1; // Temporäre Variable für überspringen von Rahmenzeile-/spalte
final int y = i - 1; // Temporäre Variable für überspringen von Rahmenzeile-/spalte
if (i == 0 && j == 0) {
add(new JLabel(" "));
} else if (i == 0) {
JLabel colLabel = new JLabel(String.valueOf(j));
colLabel.setHorizontalAlignment(SwingConstants.CENTER);
colLabel.setFont(new Font("Roboto", Font.BOLD, 14));
add(colLabel);
} else if (j == 0) {
JLabel rowLabel = new JLabel(String.valueOf((char) ('A' + i - 1)));
rowLabel.setHorizontalAlignment(SwingConstants.CENTER);
rowLabel.setFont(new Font("Roboto", Font.BOLD, 14));
add(rowLabel);
} else {
// Spielfeld (interaktive Zellen)
JButton field = new JButton("");
field.setBackground(Color.BLUE);
field.setOpaque(true);
field.setBorderPainted(true);
fields[x][y] = field;
add(field);
// Um Mausinteraktionen zu ermöglichen (Rechts/- Linksklick, Hover)
field.addMouseListener(new MouseAdapter() {
// Um beim "Hovern" Position zu setzten und weiterzugeben.
@Override
public void mouseEntered(MouseEvent e) {
mousePosition = new Point(x, y);
paintFields();
}
// Um nach "wegbewegen" der Maus wieder zu entfärben
@Override
public void mouseExited(MouseEvent e) {
paintFields();
}
// Um Schiffe zu rotieren/platzieren
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
togglePlacementDirection();
} else if (SwingUtilities.isLeftMouseButton(e)) {
Point o = new Point(x, y);
handleFieldClick(o);
SoundHandler.playSound("plop");
}
}
});
}
}
}
}
/**
* Aktuelles Schiff auswählen
* @param ship Schiff zum Auswählen
* @author Lucas Bronson, Joshua Kuklok
*/
public void selectCurrentShip(Ship ship) {
this.currentShip = ship;
paintFields();
}
/**
* Zurücksetzen von aktuellem Schiff und allen Schiffen des Spielers.
* Danach blau färben des Spielfeldes
* @author Lucas Bronson, Joshua Kuklok
*/
public void resetAllShips() {
this.currentShip = null;
for (Ship ship : player.getBoard().getShips()) {
ship.resetPosition();
}
paintFields();
}
/**
* Wechselt die Platzierungsrichtung zwischen horizontal und vertikal.
* @author Lucas Bronson, Joshua Kuklok
*/
private void togglePlacementDirection() {
horizontal = !horizontal;
String direction = horizontal ? "horizontal" : "vertikal";
System.out.println("Platzierungsrichtung geändert zu: " + direction);
paintFields();
}
/**
* Handhabt das Platzieren eines Schiffs auf dem Spielfeld.
* @param o Die Koordinaten des Klicks.
* @author Lucas Bronson, Luca Conte
*/
private void handleFieldClick(Point o) {
System.out.println("CLICK " + o);
if (!this.enemyBoard && !this.player.isGameRunning() && !this.player.isReady()) {
this.currentShip.setPosition(o, horizontal, player.getBoard().getShips(),this.gridSize);
}
if (this.enemyBoard && this.player.isGameRunning() && this.player.enemy.myTurn) {
this.player.enemy.shoot(o);
}
paintFields();
}
/**
* Färbt das Spielfeld blau, überprüft, ob das aktuelle Schiff null ist.
* Färbt eine Preview in das Spielfeld ein, ob Schiff setzen möglich ist
* Schiffe die gesetzt wurden, werden grau gefärbt
* Aufrufen von refreshButtonState um zu zeigen, ob Button drückbar ist
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public void paintFields() {
List<Point> test=new ArrayList<>();
if(currentShip != null) {
test = currentShip.getVirtualOccupiedPoints(mousePosition, horizontal);
}
if (player == null || player.getBoard() == null) return;
for(int i = 0; i < gridSize; i++) {
for(int j = 0; j < gridSize; j++) {
if(fields[i][j] == null) {
continue;
}
if (this.enemyBoard) {
// enemy board only accessible if game is running AND it's "enemy's" so local player's turn
if (!this.player.isGameRunning() || !this.player.enemy.myTurn) {
fields[i][j].setEnabled(false);
} else {
fields[i][j].setEnabled(true);
}
} else {
if (this.player.isGameRunning() || this.player.isReady()) {
fields[i][j].setEnabled(false);
} else {
fields[i][j].setEnabled(true);
}
}
if (this.enemyBoard) {
fields[i][j].setBackground(Color.WHITE);
} else {
fields[i][j].setBackground(Color.BLUE);
}
if (!this.player.isReady()) {
for(Point p : test) {
if(i==p.getX() && j==p.getY()) {
if (currentShip.checkValidPlacement(mousePosition,horizontal,player.getBoard().getShips(),gridSize)) {
fields[i][j].setBackground(Color.GREEN);
} else {
fields[i][j].setBackground(Color.RED);
}
}
}
}
for(Ship ship: player.getBoard().getShips()) {
if(ship.isShipOnPos(new Point(i,j))) {
fields[i][j].setBackground(Color.WHITE);
}
}
HitResponse hit = this.player.getBoard().getHitResponseOnPoint(new Point(i, j));
if (hit != null) {
switch (hit.getType()) {
case HIT:
fields[i][j].setBackground(Color.ORANGE);
//SoundHandler.playSound("hit");
break;
case SUNK:
//SoundHandler.playSound("destroyed");
case VICTORY:
fields[i][j].setBackground(Color.RED);
break;
case MISS:
if (this.enemyBoard) {
//SoundHandler.playSound("miss");
fields[i][j].setBackground(Color.BLUE);
} else {
fields[i][j].setBackground(Color.CYAN);
}
break;
}
}
}
}
for( ShipButton shipButton: shipButtonList) {
shipButton.refreshButtonState();
}
}
/**
* Ruft paintFields auf, um Felder zu aktualisieren
* @author Luca Conte
*/
public void refresh() {
paintFields();
}
}

237
src/GameBoard.java Normal file
View File

@ -0,0 +1,237 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
/**
* Das GameBoard dient als Panel, in dem das tatsächliche Spiel stattfindet.
* Der Benutzer kann hier seine Schiffe platzieren, das Spiel starten etc.
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public class GameBoard extends JPanel {
private BoardDisplay ownBoardPanel;
private BoardDisplay opponentBoardPanel;
private Player p1;
private Player p2;
// Grafiken
ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
ImageIcon gameBoardEmtpy = new ImageIcon("graphics/gameboardempty.png");
ImageIcon gameBoardX = new ImageIcon("graphics/gameboardx.png");
// kontextText Text-Strings
String kT1 = "Bitte Schiffe setzten - Rechtsclick zum drehen";
String kT2 = "Warte auf Gegner";
String kT3 = "Du fängst an";
String kT4 = "Dein Gegner fängt an";
String kT5 = "Du bist am Zug";
String kT6 = "Dein Gegner ist am Zug";
String kT7 = "Du hast das Spiel gewonnen";
String kT8 = "Du hast das Spiel verloren";
String kT9 = "Bitte erst alle Schiffe setzten";
// Labels
JLabel frameTitle = new JLabel("GameBoard");
JLabel kontextText = new JLabel(kT1);
// Buttons
JButton giveUpButton = new JButton("Aufgeben");
/**
* Konstruktor von GameBoard.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @param semesterCounter Ausgewähltes Semester
* @param p1 Erstes Spielerobjekt
* @param p2 Zweites Spielerobjekt
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
GameBoard(MainFrame frame, int semesterCounter,Player p1, Player p2) {
this.p1 = p1;
this.p2 = p2;
buildPanel(frame, semesterCounter);
List<Ship> shipsP1 =p1.getBoard().getShips();
List<Ship> shipsP2 =p2.getBoard().getShips();
giveUpButton.addActionListener((e) -> {
frame.showPanel("MainMenu");
p1.withdraw();
});
}
// Timer für pulsierenden SchwarzGrau-Effekt
Timer timer = new Timer(10, new ActionListener() {
// Start-Grauwert (0 = Schwarz, 255 = Weiß)
private int value = 50;
private boolean increasing = false;
@Override
public void actionPerformed(ActionEvent e) {
kontextText.setForeground(new Color(value, value, value));
if (increasing) {
value++;
if (value >= 90) {
increasing = false;
}
} else {
value--;
if (value <= 0) {
increasing = true;
}
}
}
});
/**
* Baut das grundlegende Spielboard
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @param semesterCounter Ausgewähltes Semester
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public void buildPanel(MainFrame frame, int semesterCounter) {
// Hauptlayout - BorderLayout für die Anordnung der Komponenten
setLayout(new BorderLayout());
// Spielfelder erstellen (eigenes und gegnerisches)
// Spielfelder werden in BoardDisplay erstellt
int gridSize = GameController.semesterToBoardSize(semesterCounter); // Größe des Spielfelds
this.ownBoardPanel = new BoardDisplay(gridSize,p1, false);
this.opponentBoardPanel = new BoardDisplay(gridSize, p2, true);
// Panel für das Kontext-Text-Feld
JPanel headerPanel = new JPanel();
headerPanel.setLayout(new BorderLayout());
headerPanel.add(kontextText, BorderLayout.WEST);
kontextText.setFont(new Font("Roboto", Font.BOLD, 30));
headerPanel.add(giveUpButton, BorderLayout.EAST);
JPanel leftButtonsPanel = new JPanel();
leftButtonsPanel.setLayout(new GridLayout(7, 1)); // 6 Buttons untereinander
JPanel rightButtonsPanel = new JPanel();
rightButtonsPanel.setLayout(new GridLayout(7, 1));
//Buttons in eine Gruppe packen damit diese beim drücken eines anderen Buttons wieder entwählt werden
ButtonGroup leftButtonGroup= new ButtonGroup();
ButtonGroup rightButtonGroup= new ButtonGroup();
// Panel für die Buttons des linken Spielers (ganz links)
for(Ship ship : p1.getBoard().getShips()) {
ShipButton shipButton= new ShipButton(ship,ownBoardPanel);
leftButtonsPanel.add(shipButton);
leftButtonGroup.add(shipButton);
ownBoardPanel.addShipButton(shipButton);
}
for(Ship ship : p2.getBoard().getShips()) {
ShipButton shipButton= new ShipButton(ship,opponentBoardPanel);
rightButtonsPanel.add(shipButton);
rightButtonGroup.add(shipButton);
opponentBoardPanel.addShipButton(shipButton);
shipButton.setEnabled(false);
}
JToggleButton readyButton = new JToggleButton("Bereit");
readyButton.setBackground(Color.GREEN);
rightButtonsPanel.add(readyButton);
JToggleButton resetButton = new JToggleButton("Reset");
resetButton.setBackground(Color.RED);
leftButtonsPanel.add(resetButton);
resetButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ownBoardPanel.resetAllShips();
}
});
// Um Bereit-Meldung and Backend zu geben, kontextText zu setzten und ready/reset Button zu deaktivieren
readyButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
kontextText.setText(kT2);
p1.ready();
if(p1.isReady()) {
remove(readyButton);
remove(resetButton);
remove(rightButtonsPanel);
remove(leftButtonsPanel);
readyButton.setEnabled(false);
resetButton.setEnabled(false);
}
}
});
// Panel für beide Spielfelder (nebeneinander in der Mitte)
JPanel centerPanel = new JPanel();
centerPanel.setLayout(new GridLayout(1, 2, 20, 0)); // 2 Spielfelder nebeneinander, mit Abstand von 20 Pixeln
centerPanel.add(ownBoardPanel);
centerPanel.add(opponentBoardPanel);
// Spieler-Namen über den Spielfeldern hinzufügen
JPanel playerNamesPanel = new JPanel();
playerNamesPanel.setLayout(new GridLayout(1, 2)); // Zwei Labels nebeneinander
JLabel player1NameLabel = new JLabel(p1.getName(), SwingConstants.CENTER);
JLabel player2NameLabel = new JLabel(p2.getName(), SwingConstants.CENTER);
System.out.println("Name in Gameboard: " + player1NameLabel.getText());
// Schrift und Formatierung der Labels
player1NameLabel.setFont(new Font("Roboto", Font.BOLD, 18));
player2NameLabel.setFont(new Font("Roboto", Font.BOLD, 18));
// Spieler-Labels zum Panel hinzufügen
playerNamesPanel.add(player1NameLabel);
playerNamesPanel.add(player2NameLabel);
// Spieler-Namen-Panel oberhalb der Spielfelder hinzufügen
JPanel namesAndBoardsPanel = new JPanel(new BorderLayout());
namesAndBoardsPanel.add(playerNamesPanel, BorderLayout.NORTH);
namesAndBoardsPanel.add(centerPanel, BorderLayout.CENTER);
// Panels dem Hauptlayout hinzufügen
add(leftButtonsPanel, BorderLayout.WEST);
add(rightButtonsPanel, BorderLayout.EAST);
add(headerPanel, BorderLayout.NORTH);
add(namesAndBoardsPanel, BorderLayout.CENTER);
timer.start();
}
/**
* Aktualisiert Zustand(kontextText) je nach Zug
* @author Luca Conte, Joshua Kuklok
*/
public void refresh() {
if (this.p1.myTurn) {
if (!kontextText.getText().equals(kT5)) {
this.kontextText.setText(kT5);
SoundHandler.playSound("yourturn");
}
} else {
this.kontextText.setText(kT6);
}
this.ownBoardPanel.refresh();
this.opponentBoardPanel.refresh();
}
/**
* Getter für Player1
* @return Player 1
* @author Peer Ole Wachtel
*/
public Player getP1() {
return p1;
}
/**
* Getter für Player2
* @return Player 2
* @author Luca Conte
*/
public Player getP2() {
return p2;
}
}

242
src/GameController.java Normal file
View File

@ -0,0 +1,242 @@
import java.io.IOException;
import java.net.InetSocketAddress;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* The central Backend Component
* @author Luca Conte
*/
public class GameController {
private static MainFrame mainFrame;
/**
* returns the current MainFrame
* @return the current MainFrame
* @author Luca Conte
*/
public static MainFrame getMainFrame() {
return GameController.mainFrame;
}
/**
* sets the current MainFrame
* @param mainFrame the current MainFrame
* @author Luca Conte
*/
public static void setMainFrame(MainFrame mainFrame) {
GameController.mainFrame = mainFrame;
}
/**
* converts a semester to be played in into its respective board size
* @param semester the semester to be played in
* @author Luca Conte
*/
public static int semesterToBoardSize(int semester) {
return semester + 13;
}
/**
* converts a board size into its respective semester
* @param size the board size to get the semester of
* @author Luca Conte
*/
public static int boardSizeToSemester(int size) {
return size - 13;
}
/**
* the list of supported versions of the online protocol
* https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
*/
public static HashMap<String, Class<? extends OnlinePlayer>> supportedVersions = new HashMap<>(Map.of(
"1.1.0", OnlinePlayer_1_1_0.class
));
/**
* Starts a game with one local player and one online player.
* @param localPlayerClass the class of the local player to be instantiated. must extend `LocalPlayer`
* @param localPlayerName the name of the local player. Only necessarry when localPlayerClass is `HumanPlayer`
* @param address the Address of the opposing player. If the hostname of the address is set to be 0.0.0.0, it
* is interpreted that this instance should instead listen on the defined port for incoming connections.
* @param size the board size that it is intended to be played in
* @author Luca Conte
*/
public static void startOnlineGame(Class<? extends LocalPlayer> localPlayerClass, String localPlayerName, InetSocketAddress address, int size) throws IOException {
AsyncSocket clientSocket;
boolean localPlayerIsServer = address.getHostName() == null || address.getHostName().isEmpty() || address.getHostName().equals("0.0.0.0");
if (localPlayerIsServer) {
// SERVER MODE
clientSocket = new AsyncSocket(address.getPort(), null);
} else {
// CLIENT MODE
clientSocket = new AsyncSocket(address, null);
}
clientSocket.send("VERSION", "Gruppe03 " + String.join(" ", supportedVersions.keySet()));
clientSocket.setHandler((message) -> {
SocketPackage socketPackage = new SocketPackage(message);
if (socketPackage.getName().equals("VERSION")) {
List<String> opponentSupportedVersions = socketPackage.splitData();
String usedVersion = findMostRecentVersion(new ArrayList<String>(supportedVersions.keySet()), opponentSupportedVersions);
if (usedVersion == null) {
throw new RuntimeException("No common versions found");
}
// instantiate players
Class<? extends OnlinePlayer> onlinePlayerClass = supportedVersions.get(usedVersion);
LocalPlayer localPlayer;
OnlinePlayer onlinePlayer;
try {
localPlayer = localPlayerClass.getDeclaredConstructor().newInstance();
onlinePlayer = onlinePlayerClass.getDeclaredConstructor(Integer.class, AsyncSocket.class).newInstance((Integer)size, clientSocket);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to instantiate players");
}
localPlayer.isServer = localPlayerIsServer;
onlinePlayer.isServer = !localPlayerIsServer;
localPlayer.setName(localPlayerName);
localPlayer.setEnemy(onlinePlayer);
onlinePlayer.setEnemy(localPlayer);
onlinePlayer.sendIAM();
// Start game only after IAM Package was exchanged
} else {
throw new RuntimeException("Unexpected Package received before game initialisation");
}
});
}
/**
* finds the largest common version in two lists of version strings
* @return null if no common versions are found otherwise returns the most recent version present in both lists
* @author Luca Conte
*/
public static String findMostRecentVersion(List<String> versions1, List<String> versions2) {
if (versions1 == null || versions2 == null) return null;
String largestCommonVersion = null;
for (String v1 : versions1) {
if (!checkVersionString(v1)) continue;
for (String v2 : versions2) {
if (!checkVersionString(v2)) continue;
// strings within the lists must be equal
// if no largest common version has been found or currently checked version is larger than
// previous largest common version, new largest version has been found
if (compareVersions(v1, v2) == 0 && (largestCommonVersion == null || compareVersions(v1, largestCommonVersion) >= 1)) {
largestCommonVersion = v1;
continue;
}
}
}
return largestCommonVersion;
}
/**
* compares two version strings
* @param version1 the first version to be compared
* @param version2 the second version to be compared
* @return
* 0 if versions are equal
* 1 if version1 is more recent than version2
* -1 otherwise
* @author Luca Conte
*/
public static int compareVersions(String version1, String version2) {
if (!checkVersionString(version1) || !checkVersionString(version2)) {
throw new IllegalArgumentException("Version is not valid version string");
}
String[] version1Split = version1.split("\\.");
String[] version2Split = version2.split("\\.");
for (int i = 0; i < version1Split.length; i++) {
int v1 = Integer.parseInt(version1Split[i]);
int v2 = Integer.parseInt(version2Split[i]);
if (v1 == v2) continue;
if (v1 > v2) {
return 1;
} else {
return -1;
}
}
return 0;
}
/**
* checks if a provided string matches the format of a version number
* @param versionString the version String to be checked
* @author Luca Conte
*/
public static boolean checkVersionString(String versionString) {
return versionString != null && versionString.matches("\\d+\\.\\d+\\.\\d+");
}
/**
* Starts a game with two local players
* @param localPlayerClass the class of the local player to be instantiated. must extend `LocalPlayer`
* @param localPlayerName the name of the local player. Only necessarry when localPlayerClass is `HumanPlayer`
* @param enemyClass the class of the enemy player. Must extend `AiPlayer`. For Humans VS Human games use an online game instead.
* @param size the board size that it is intended to be played in
* @author Luca Conte
*/
public static void startLocalGame(Class<? extends LocalPlayer> localPlayerClass, String localPlayerName, Class<? extends AiPlayer> enemyClass, int size) {
LocalPlayer localPlayer;
AiPlayer aiPlayer;
try {
localPlayer = localPlayerClass.getDeclaredConstructor().newInstance();
aiPlayer = enemyClass.getDeclaredConstructor().newInstance();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("Unable to instantiate players");
}
localPlayer.isServer = true;
aiPlayer.isServer = false;
localPlayer.setEnemy(aiPlayer);
aiPlayer.setEnemy(localPlayer);
localPlayer.createBoard(size);
aiPlayer.createBoard(size);
localPlayer.setName(localPlayerName);
startGameWithInstancedPlayers(localPlayer, aiPlayer, size);
}
/**
* switches to the ingame screen
* @param p1 the first player. This player is always shown on the left side of the screen and is expected to be the Human player, if there is one.
* @param p2 the second player
* @param boardSize the board size to be played in
* @author Luca Conte
*/
public static void startGameWithInstancedPlayers(LocalPlayer p1, Player p2, int boardSize) {
mainFrame.showPanelSLG("GameBoard", boardSizeToSemester(boardSize), p1, p2);
// TODO: frontend configuration
}
}

View File

@ -1,26 +1,17 @@
/**
* Hauptklasse über die der MainFrame gestartet wird
* @author Lucas Bronson, Peer Ole Wachtel, Joshua Kuklok
*/
public class HalloSchiffeVersenken {
/**
* Erstellt und setzt den Mainframe
* @param args Argumente an Main durch Konsole etc.
* @throws InterruptedException
* @author Peer Ole Wachtel
*/
public static void main(String[] args) throws InterruptedException {
//LUCAS CODE
MainMenuModel model = new MainMenuModel();
MainMenuView view = new MainMenuView();
MainMenuController controller = new MainMenuController(model, view);
//System.out.println("HelloSchiffeVersenekn");
/*
System.out.println("sound");
SoundHandler.playSound("hit");
Thread.sleep(10000);
SoundHandler.setSoundOn(false);
System.out.println("sound off");
SoundHandler.playSound("hit");
*/
//JOSHUA CODE
startLocalGame huso = new startLocalGame();
MainFrame mf = new MainFrame();
mf.setVisible(true);
}
}
}

View File

@ -1,6 +1,90 @@
import java.awt.*;
/**
* Eine Antwort auf einen Schuss
* enthält einen Punkt, auf den geschossen wurde, sowie einen typen,
* der angibt, ob es sich bei dem Schuss um einen Treffer handelt
* @author Peer Ole Wachtel
*/
public class HitResponse {
/**
* Speichert den typ der HitResponse.
*/
private HitResponseType type;
/**
* Speicher den Punkt wofür die HitResponse gilt.
*/
private Point point;
/**
* Erstellt eine neue HitResponse und setzt den Punkt und typ.
* @param type der HitResponse.
* @param point für den die HitResponse gilt.
* @author Peer Ole Wachtel.
*/
public HitResponse(HitResponseType type, Point point) {
this.type = type;
this.point = point;
}
/**
*Erstellt eine neue HitResponse und setzt den Punkt und typ.
* @param typeIndex der HitResponse.
* @param point für den die HitResponse gilt.
* @throws IllegalArgumentException wenn der übergebene int nicht auf ein typ referenziert werden kann.
* @author Peer Ole Wachtel.
*/
public HitResponse (int typeIndex, Point point) {
if (typeIndex >= 0 && typeIndex < HitResponseType.values().length) {
this.type = HitResponseType.values()[typeIndex];
this.point = point;
} else {
throw new IllegalArgumentException();
}
}
/**
* returns the type of the HitResponse
* @return the type of the HitResponse
* @author Florian Hantzschel
*/
public HitResponseType getHitResponse() {
return this.type;
}
/**
* returns the point of the HitResponse
* @return the point of the HitResponse
* @author Florian Hantzschel
*/
public Point getPoint() {
return this.point;
}
/**
* Setter für den type
* @param type auf den die HitResponse gesetzt werden soll.
* @author Peer Ole Wachtel
*/
public void setType(HitResponseType type) {
this.type = type;
}
/**
* Gibt den passenden string nach Netzwerkstandard für eine HitResponse zurück.
* @return den passenden string nach Netzwerkstandard für eine HitResponse.
* @author Peer Ole Wachtel.
*/
@Override
public String toString() {
return this.getPoint().toString() + " " + this.type.ordinal();
}
/**
* Getter für den typ der HitResponse.
* @return den typ der HitRespnse.
* @author Peer Ole Wachtel.
*/
public HitResponseType getType() {
return type;
}
}

View File

@ -1,3 +1,7 @@
/**
* Stellt die verschiedenen möglichkeiten einer HitResponse als typ dar.
* @author Peer Ole Wachtel
*/
public enum HitResponseType {
MISS, HIT, SUNK, VICTORY
}

18
src/HumanPlayer.java Normal file
View File

@ -0,0 +1,18 @@
/**
* Repräsentiert einen menschlichen Spieler
* @author Luca Conte, Florian Hantzschel
*/
public class HumanPlayer extends LocalPlayer {
/**
* shoots a shot onto the provided point on the enemy board
* if it is not the players turn, this method does nothing.
* @param point the location to be shot
* @author Luca Conte
*/
@Override
public void shoot(Point point) {
if (!this.myTurn) return;
enemy.receiveShoot(point);
}
}

132
src/JoinGame.java Normal file
View File

@ -0,0 +1,132 @@
import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.IOException;
import java.net.InetSocketAddress;
/**
* Das JoinGame Panel dient zum setzten des Ports/IP-Adresse.
* Anschließend kann das Verbinden Panel gezeigt werden.
* @author Lucas Bronson
*/
public class JoinGame extends JPanel {
// Funktionshilfen
String standardPort = "51525";
// Grafiken
ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
// Labels
JLabel spielBeitretenLabel;
JLabel ipLabel = new JLabel("IP-Adresse");
JLabel portLabel = new JLabel("Port");
// Textfelder
JTextField ipTextField = new JTextField(20);
JTextField portTextField = new JTextField(20);
// Buttons
JButton losButton = new JButton("Los!");
JButton backButton = new JButton(backButtonIcon);
// Font
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
/**
* Erstellt mittels Funktionsaufrufen das Panel.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @param g int-Anzeige, ob es sich um "spiel erstellen" oder "spiel beitreten" handelt.
* @param playerType int-Anzeige, ob es sich um einen HumanPlayer,AIEasy... handelt.
* @param playerName Name des Spielers
* @author Lucas Bronson, Joshua Kuklok
*/
public JoinGame(MainFrame frame,int g,int playerType,String playerName, int semesterCounter) {
setLayout(null);
buildPanel(frame,g,playerType,playerName, semesterCounter);
}
/**
* Erstellt das Panel.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @param g int-Anzeige, ob es sich um "spiel erstellen" oder "spiel beitreten" handelt.
* @param playerType int-Anzeige, ob es sich um einen HumanPlayer,AIEasy... handelt.
* @param playerName Name des Spielers
* @author Lucas Bronson, Joshua Kuklok
*/
private void buildPanel(MainFrame frame,int g,int playerType,String playerName, int semesterCounter) {
System.out.println("semesterzahl in JoinGame" + semesterCounter);
if(g==1){
spielBeitretenLabel= new JLabel("Spiel beitreten");
}else{
spielBeitretenLabel= new JLabel("Spiel erstellen");
}
spielBeitretenLabel.setBounds(20,20,700, 100);
losButton.setBounds(320, 225, 100, 50);
backButton.setBounds(1380, 20, 80, 80);
portLabel.setBounds(50, 200, 200, 30);
if(g==1) { // Wenn man Spiel erstellen will, werden IP-Felder nicht angezeigt.
ipLabel.setBounds(50, 125, 200, 30);
ipTextField.setBounds(50, 150, 250, 50);
}
portTextField.setBounds(50, 225, 250, 50);
portTextField.setText(standardPort);
spielBeitretenLabel.setFont(robotoFont.deriveFont(50f));
add(spielBeitretenLabel);
add(ipLabel);
add(portLabel);
add(losButton);
add(ipTextField);
add(portTextField);
add(backButton);
// ActionListener für Buttons.
// Um in das MultiplayerGame zurückzuwechseln.
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanel("MultiplayerGame");
}
});
// Um das Verbinden Panel anzuzeigen und Daten an Backend weiterzureichen.
losButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
String ipAddress = ipTextField.getText();
if (ipAddress.isEmpty()) {
ipAddress = "0.0.0.0";
}
System.out.println(portTextField.getText());
String portText = portTextField.getText();
int port = Integer.parseInt(portText);
InetSocketAddress address = new InetSocketAddress(ipAddress, port);
frame.showPanel("Verbinden");
try {
if(playerType == 0) {
GameController.startOnlineGame(HumanPlayer.class, playerName, address,GameController.semesterToBoardSize(semesterCounter));
} else if(playerType == 1) {
GameController.startOnlineGame(SpecificAiPlayerEasy.class, playerName, address,GameController.semesterToBoardSize(semesterCounter));
} else if (playerType == 2) {
GameController.startOnlineGame(SpecificAiPlayerMedium.class, playerName, address,GameController.semesterToBoardSize(semesterCounter));
} else if (playerType == 3) {
GameController.startOnlineGame(SpecificAiPlayerHard.class, playerName, address,GameController.semesterToBoardSize(semesterCounter));
}
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
});
}
}

104
src/LocalPlayer.java Normal file
View File

@ -0,0 +1,104 @@
import java.util.Random;
/**
* repräsentiert einen Player, der Lokal an dem Gerät spielt,
* auf dem dieses Programm läuft
* @author Luca Conte, Peer Ole Wachtel, Florian Hantzschel
*/
public class LocalPlayer extends Player {
/**
* erstellt einen LocalPlayer und setzt myCoin random
* @author Peer Ole Wachtel
*/
public LocalPlayer(){
super();
Random random = new Random();
this.myCoin = random.nextBoolean();
}
/**
* receives a shot onto a point from the enemy
* @param point the location to be shot
* @author Luca Conte, Peer Ole Wachtel
*/
@Override
public synchronized void receiveShoot(Point point) {
if (!this.enemy.myTurn) {
System.out.println("enemy tried to fire when not their turn!");
return;
}
this.enemy.myTurn = false;
HitResponse hitResponse = board.getHitResponseOnPoint(point);
if (!(hitResponse == null)){
enemy.receiveHit(hitResponse);
} else {
hitResponse = this.board.hit(point);
enemy.receiveHit(hitResponse);
}
switch (hitResponse.getType()) {
case HIT, SUNK -> this.myTurn = false;
case MISS -> this.myTurn = true;
case VICTORY -> this.lose();
}
GameController.getMainFrame().refreshGameBoard();
}
/**
* receives a hit response from the enemy as a response to a receiveShoot call
* @param hitResponse the hitresponse
* @author Peer Ole Wachtel
*/
@Override
public synchronized void receiveHit(HitResponse hitResponse) {
enemy.board.addHits(hitResponse);
switch (hitResponse.getType()) {
case HIT, SUNK -> this.myTurn = true;
case MISS -> this.myTurn = false;
case VICTORY -> this.win();
}
GameController.getMainFrame().refreshGameBoard();
}
/**
* receives the enemies coin toss result
* this method does nothing if the player has already received the enemies coin
* it will also call `determineCoinToss`
* @param coin the coin of the enemy player
* @author Luca Conte
*/
@Override
public synchronized void receiveCoin(boolean coin) {
if (!this.hasReceivedCoin) {
this.hasReceivedCoin = true;
this.determineCoinToss();
}
}
/**
* sends shot to enemy player.
* should ONLY be called on HumanPlayer
* @author Luca Conte
*/
@Override
public void shoot(Point point){
return;
}
/**
* marks the player as ready, if all ships have been placed
* @author Luca Conte
*/
@Override
public synchronized void ready() {
for (Ship ship : this.board.getShips()) {
if (!ship.isPlaced()) return;
}
super.ready();
}
}

48
src/LoseScreen.java Normal file
View File

@ -0,0 +1,48 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/**
* Klasse für Erstellung von looseScreen Objekten
* Dient zur Anzeige das ein Spiel verloren wurde
* @author Joshua Kuklok, Luca Bronson
*/
public class LoseScreen extends JPanel {
JLabel loseLabel = new JLabel("Du hast Verloren");
JButton okButton = new JButton("Zurück zum Hauptmenü");
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
/**
* Konstruktor der LoseScreen Klasse
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
public LoseScreen(MainFrame frame) {
setLayout(null);
buildPanel(frame);
}
/**
* Panel bauen/Objekte hinzufügen
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson, Joshua Kuklok
*/
public void buildPanel(MainFrame frame) {
add(loseLabel);
okButton.setBounds(625,525,200,50);
loseLabel.setBounds(550,450,500,50);
loseLabel.setFont(robotoFont);
SoundHandler.playSound("loose");
// Zurückkehren zum Hauptmenü, wenn okButton gedrückt wird
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanel("MainMenu");
}
});
add(loseLabel);
add(okButton);
}
}

181
src/MainFrame.java Normal file
View File

@ -0,0 +1,181 @@
import javax.swing.*;
import java.awt.*;
/**
* Der MainFrame dient als Hub und Übergreifendes Fenster auf dem alle weiteren Panel angezeigt werden.
* Dadurch werden keine weiteren Fenster geöffnet.
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public class MainFrame extends JFrame {
private CardLayout cardLayout;
private JPanel mainPanel;
// ---------- //
// Diverse Hilfsvariablen (für Parameterübergabe etc.)
// Von startMultiplayerGame an JoinGame
int localMult;
// Von startLocalGame an startLocalGameLoadingScreen
// Von startLocalGameLoadingScreen an GameBoard
int semesterCounter;
// ---------- //
private GameBoard gameBoard;
/**
* Konstruktor von MainFrame.
* Ermöglicht es Panel anzuzeigen.
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public MainFrame() {
GameController.setMainFrame(this);
setTitle("Studium Versenken");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(1500, 1000);
setLocationRelativeTo(null);
// CardLayout und Hauptpanel erstellen
cardLayout = new CardLayout();
mainPanel = new JPanel(cardLayout);
// Panels erstellen
MainMenuView mainMenuView = new MainMenuView(this);
startLocalGame localGame = new startLocalGame(this);
startMultiplayerGame multiplayerGame = new startMultiplayerGame(this);
Verbinden verbinden = new Verbinden(this);
// Panels hinzufügen
mainPanel.add(mainMenuView, "MainMenu");
mainPanel.add(localGame, "LocalGame");
mainPanel.add(multiplayerGame, "MultiplayerGame");
mainPanel.add(verbinden, "Verbinden");
// mainPanel.add(winLooseScreen, "WinLooseScreen");
// Hauptpanel in JFrame hinzufügen
add(mainPanel);
// Hauptmenü anzeigen
cardLayout.show(mainPanel, "MainMenu");
}
/**
* Methode, um die Ansicht zu wechseln
* @param panelName Name des anzuzeigenden Panels
* @author Joshua Kuklok
*/
public void showPanel(String panelName) {
cardLayout.show(mainPanel, panelName);
}
/**
* Spezifische ShowPanel-Funktion der startMultiplayerGame Klasse
* @param panelName Name des anzuzeigenden Panels
* @param num Hilfsvariable um abzugleichen, ob "Spiel erstellen" oder "Spiel beitreten" ausgewählt wurde
* @param playerType Spielertyp(HumanPlayer, AIEasy etc.)
* @param playerName Name des Spielers
* @author Lucas Bronson, Joshua Kuklok
*/
public void showPanelSMG(String panelName, int num, int playerType,String playerName, int semesterCounter) {
this.localMult = num;
JoinGame joinGame = new JoinGame(this, localMult, playerType, playerName, semesterCounter);
mainPanel.add(joinGame, panelName);
mainPanel.revalidate();
mainPanel.repaint();
cardLayout.show(mainPanel, panelName);
}
/**
* Spezifische ShowPanel der startLocalGameLoadingScreen Klasse (DURCH BACKEND AUFGERUFEN)
* @param panelName Name des anzuzeigenden Panels
* @param semesterCounter Ausgewähltes Semester
* @param p1 Erstes Spielerobjekt
* @param p2 Zweites Spielerobjekt
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public void showPanelSLG(String panelName,int semesterCounter, Player p1, Player p2) {
this.semesterCounter = semesterCounter;
this.gameBoard = new GameBoard(this, semesterCounter, p1, p2);
mainPanel.add(gameBoard, panelName);
mainPanel.revalidate();
mainPanel.repaint();
cardLayout.show(mainPanel, panelName); // Panel anzeigen
}
/**
* Spezifische ShowPanel der startLocalGame Klasse
* @param panelName Name des anzuzeigenden Panels
* @param semesterCounter Ausgewähltes Semester
* @author Joshua Kuklok
*/
public void showPanelSLGLS(String panelName,int semesterCounter) {
this.semesterCounter = semesterCounter;
startLocalGameLoadingScreen LocalGameLoadingScreen = new startLocalGameLoadingScreen(this, semesterCounter);
mainPanel.add(LocalGameLoadingScreen, panelName);
mainPanel.revalidate();
mainPanel.repaint();
cardLayout.show(mainPanel, panelName); // Panel anzeigen
}
/**
* Spezifische ShowPanel für WinScreen Klasse
* @param panelName Name des anzuzeigenden Panels
* @param player Player von dem die funktion aufgerufen worden ist
* @author Lucas Bronson, Peer Ole Wachtel, Luca Conte
*/
public void showPanelWin(String panelName, Player player){
if(gameBoard == null || player != gameBoard.getP1()){
return;
}
this.gameBoard.getP1().destroy();
this.gameBoard.getP2().destroy();
this.gameBoard.removeAll();
this.gameBoard = null;
WinScreen winScreen = new WinScreen(this);
mainPanel.add(winScreen, panelName);
mainPanel.revalidate();
mainPanel.repaint();
cardLayout.show(mainPanel, panelName);
}
/**
* Spezifische ShowPanel für LooseScreen Klasse
* @param panelName Name des anzuzeigenden Panels
* @param player Player von dem die funktion aufgerufen worden ist
* @author Lucas Bronson, Peer Ole Wachtel, Luca Conte
*/
public void showPanelLose(String panelName, Player player){
if(gameBoard == null || player != gameBoard.getP1()){
return;
}
this.gameBoard.getP1().destroy();
this.gameBoard.getP2().destroy();
this.gameBoard.removeAll();
this.gameBoard = null;
LoseScreen looseScreen = new LoseScreen(this);
mainPanel.add(looseScreen,panelName);
mainPanel.revalidate();
mainPanel.repaint();
cardLayout.show(mainPanel, panelName);
}
/**
* Aktualisiert das Spielfeld
* @author Luca Conte
*/
public void refreshGameBoard() {
if(this.gameBoard == null) {
return;
}
this.gameBoard.refresh();
}
}

View File

@ -1,31 +0,0 @@
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MainMenuController implements ActionListener {
private MainMenuView view;
private MainMenuModel model;
public MainMenuController(MainMenuModel model, MainMenuView view) {
this.view = view;
this.model = model;
this.view.getLocalButton().addActionListener(this);
this.view.getMultiButton().addActionListener(this);
this.view.getSoundButton().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == view.getMultiButton()) {
view.closeWindOw();
MultiMenuModel model = new MultiMenuModel();
MultiMenuView view = new MultiMenuView();
MultiMenuController controller2 = new MultiMenuController(model, view);
} else if (e.getSource() == view.getMultiButton()) {
model.setGameMode("Multiplayer");
JOptionPane.showMessageDialog(view.getFrame(), "Multiplayer game selected.");
}else if (e.getSource() == view.getSoundButton()) {
view.toggleMute();
}
}
}

View File

@ -1,11 +0,0 @@
public class MainMenuModel {
private String gameMode;
public void setGameMode(String mode) {
this.gameMode = mode;
}
public String getGameMode() {
return gameMode;
}
}

View File

@ -1,73 +1,95 @@
import java.awt.*;
import javax.swing.JFrame;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MainMenuView {
ImageIcon SoundIcon = new ImageIcon("Grafik/sound button.png");
private JFrame frame = new JFrame();
/**
* Klasse zum Erstellen von MainMenu Objekten
* Dient als Hauptmenü für die Anwendung
* @author Lucas Bronson
*/
public class MainMenuView extends JPanel {
private JLabel titelLabel = new JLabel("Studium versenken");
private JButton lokalButton = new JButton("Lokal");
private JButton multiButton= new JButton("Multiplayer");
private JButton soundButton = new JButton(SoundIcon);
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
public MainMenuView() {
buildFrame();
buildComponents();
private JButton multiButton = new JButton("Multiplayer");
private JButton soundButton;
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
private ImageIcon soundIcon = new ImageIcon("graphics/sound button.png");
private ImageIcon muteIcon = new ImageIcon("graphics/sound button muted.png");
/**
* Konstruktor der MainMenuView Klasse
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
public MainMenuView(MainFrame frame) {
setLayout(null);
buildPanel(frame);
}
/**
* Methode zum Füllen des Panels, Objekte werden dem frame hinzugefügt
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
private void buildPanel(MainFrame frame) {
lokalButton.setBounds(200, 200, 500, 500);
multiButton.setBounds(800, 200, 500, 500);
titelLabel.setBounds(550, 10, 700, 100);
soundButton = new JButton(soundIcon);
soundButton.setBounds(20, 20, 128, 128);
public void buildComponents(){
lokalButton.setBounds(200,200,500,500);
multiButton.setBounds(800,200,500,500);
titelLabel.setBounds(550,10,700,100);
soundButton.setBounds(20,20,128,128);
titelLabel.setFont(robotoFont);
lokalButton.setFont(robotoFont.deriveFont(50f));
multiButton.setFont(robotoFont.deriveFont(50f));
add(titelLabel);
add(lokalButton);
add(multiButton);
add(soundButton);
// ActionListener um vom Hauptmenü zum LocalGame Menü zu wechseln
lokalButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Lokales Spiel ausgewählt.");
frame.showPanel("LocalGame"); // Panel wechseln
}
});
// ActionListener um vom Hauptmenü zum MultiPlayerGame Menü zu wechseln
multiButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Multiplayer-Spiel ausgewählt.");
frame.showPanel("MultiplayerGame"); // Panel wechseln
}
});
//Aufruf von toggleMute, falls der soundButton geklickt wird
soundButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Soundbutton geklickt.");
toggleMute();
}
});
}
public void buildFrame() {
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1500,1000);
frame.setVisible(true);
frame.getContentPane().setBackground( Color.decode("#98F5FF"));
JLabel backgroundLabel = new JLabel(new ImageIcon("Grafik/mainmenubackground.png"));
frame.setContentPane(backgroundLabel);
frame.add(titelLabel);
frame.add(lokalButton);
frame.add(multiButton);
frame.add(soundButton);
frame.setLocationRelativeTo(null);
}
public void toggleMute(){
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(soundButton.getIcon()==SoundIcon) {
soundButton.setIcon(MuteIcon);
}else{
soundButton.setIcon(SoundIcon);
/**
* Setzt Sound auf Stumm/Laut und ändert Grafik, sodass
* der aktuelle Stand der Grafik entspricht
* @author Lucas Bronson, Joshua Kuklok
*/
private void toggleMute() {
if (soundButton.getIcon() == soundIcon) {
soundButton.setIcon(muteIcon);
SoundHandler.setSoundOn(false);
} else {
soundButton.setIcon(soundIcon);
SoundHandler.setSoundOn(true);
}
}
public void closeWindOw(){
frame.dispose();
}
public JFrame getFrame() {
return frame;
}
public JButton getLocalButton() {
return lokalButton;
}
public JButton getMultiButton() {
return multiButton;
}
public JButton getSoundButton() {
return soundButton;
}
}
}

View File

@ -1,21 +0,0 @@
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class MultiMenuController implements ActionListener {
private MultiMenuView view;
private MultiMenuModel model;
public MultiMenuController(MultiMenuModel model, MultiMenuView view) {
this.view = view;
this.model = model;
this.view.getSoundButton().addActionListener(this);
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == view.getSoundButton()) {
view.toggleMute();
}
}
}

View File

@ -1,11 +0,0 @@
public class MultiMenuModel {
private String gameMode;
public void setGameMode(String mode) {
this.gameMode = mode;
}
public String getGameMode() {
return gameMode;
}
}

View File

@ -1,53 +0,0 @@
import java.awt.*;
import javax.swing.JFrame;
import javax.swing.*;
public class MultiMenuView {
ImageIcon SoundIcon = new ImageIcon("Grafik/sound button.png");
private JFrame frame = new JFrame();
private JButton soundButton = new JButton(SoundIcon);
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
public MultiMenuView() {
buildFrame();
buildComponents();
}
public void buildComponents(){
soundButton.setBounds(20,20,128,128);
}
public void buildFrame() {
frame.setLayout(null);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1500,1000);
frame.setVisible(true);
frame.getContentPane().setBackground( Color.decode("#98F5FF"));
JLabel backgroundLabel = new JLabel(new ImageIcon("Grafik/mainmenubackground.png"));
frame.setContentPane(backgroundLabel);
frame.add(soundButton);
frame.setLocationRelativeTo(null);
}
public void toggleMute(){
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(soundButton.getIcon()==SoundIcon) {
soundButton.setIcon(MuteIcon);
}else{
soundButton.setIcon(SoundIcon);
}
}
public void closeWindOw(){
frame.dispose();
}
public JFrame getFrame() {
return frame;
}
public JButton getSoundButton() {
return soundButton;
}
}

View File

@ -1,5 +1,57 @@
import java.net.Socket;
/**
* Abstrakte Repräsentation eines Spielers, der an einem anderen gerät spielt
* und durch eine Online Verbindung mit dieser Instanz kommuniziert
* @author Luca Conte, Peer Ole Wachtel
*/
public abstract class OnlinePlayer extends Player implements AsyncSocketListener {
protected AsyncSocket socket;
protected int wantedBoardSize;
protected boolean hasReceivedCoinPackage;
/**
* Constructor
* @param size the size of the board the enemy player wants to play with
* the actual board size will be determined once the semester of the online partner is known
* @param socket an AsyncSocket to communicate with the enemy through
* @author Peer Ole Wachtel, Luca Conte
*/
public OnlinePlayer(Integer size, AsyncSocket socket) {
this.socket = socket;
this.wantedBoardSize = size;
this.myCoin = null;
socket.setHandler(this);
}
/**
* sends the IAM Package for introduction
* @author Luca Conte
*/
public abstract void sendIAM();
/**
* receives a message from the AsyncSocket
* satisfies AsyncSocketListener interface
* @author Luca Conte
*/
public abstract void receive(String message);
/**
* receives the coin toss result from the enemy
* @param coin the result of the coin toss
* @author Peer Ole Wachtel
*/
@Override
public abstract void receiveCoin(boolean coin);
/**
* closes the socket and does player cleanup work
* @author Luca Conte
*/
@Override
public void destroy() {
super.destroy();
this.socket.close();
}
public abstract class OnlinePlayer extends Player{
private Socket socket;
}

188
src/OnlinePlayer_1_1_0.java Normal file
View File

@ -0,0 +1,188 @@
import java.util.List;
/**
* eine Implementierung des Kommunikationsprotokoll nach Version 1.1.0 des Netzwerkstandards
* https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
* @author Peer Ole Wachtel, Luca Conte
*/
public class OnlinePlayer_1_1_0 extends OnlinePlayer {
/**
* Erstellt einen Online Player
* @param size die maximale Größe des Spielfelds
* @param socket der Socket zur Kommunikation mit dem Online Partner
*/
public OnlinePlayer_1_1_0(Integer size, AsyncSocket socket) {
super(size, socket);
}
/**
* receives a message from the AsyncSocket
* implemented according to version 1.1.0 of https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
* @param message the message from the socket
* @author Peer Ole Wachtel, Luca Conte, Florian Hantzschel
*/
@Override
public void receive(String message) {
SocketPackage p = new SocketPackage(message);
List<String> data = p.splitData();
switch (p.getName()) {
case "IAM":
if (data.size() < 2) break;
if (this.board != null) break;
int semester = Integer.parseInt(data.get(0));
String username = p.getData().substring(data.get(0).length() + 1);
int usedBoardSize = Math.min(GameController.semesterToBoardSize(semester), this.wantedBoardSize);
this.setName(username);
this.createBoard(usedBoardSize);
this.enemy.createBoard(usedBoardSize);
GameController.startGameWithInstancedPlayers((LocalPlayer)this.enemy, (Player)this, usedBoardSize);
break;
// TODO: IAMU
case "COIN":
if(!this.hasReceivedCoinPackage && (p.getData().equals("1") || p.getData().equals("0"))){
this.myCoin = p.getData().equals("1");
this.hasReceivedCoinPackage = true;
this.ready();
}
break;
case "SHOOT":
if (Point.isValidSyntax(p.getData())){
Point point = new Point(p.getData());
this.enemy.receiveShoot(point);
}
break;
case "HIT":
if (data.size()==2){
Point point = new Point(data.get(0));
int typeIndex = Integer.parseInt(data.get(1));
if (Point.isValidSyntax(data.get(0)) && typeIndex >= 0 && typeIndex < HitResponseType.values().length){
HitResponse hitResponse = new HitResponse(typeIndex, point);
this.enemy.receiveHit(hitResponse);
switch (hitResponse.getType()) {
case HIT, SUNK:
this.myTurn = false;
break;
case MISS:
this.myTurn = true;
break;
case VICTORY:
// GameController.getMainFrame().showPanelWin("", this.enemy);
break;
}
}
}
break;
case "CHAT":
//TODO CHAT
break;
case "WITHDRAW":
this.withdraw();
break;
default:
//nichts passier da Paket ungültig
break;
}
}
/**
* sends introduction package IAM to online partner.
* @author Luca Conte
*/
@Override
public synchronized void sendIAM() {
if (this.enemy == null) throw new RuntimeException("enemy has not yet been defined");
socket.send(new SocketPackage("IAM", GameController.boardSizeToSemester(this.wantedBoardSize) + " " + this.enemy.name));
}
/**
* receives a shot from the enemy and sends it to the online partner
* if it is not the enemies turn, this method does nothing.
* @param point the point to be shot
* @author Peer Ole Wachtel, Luca Conte
*/
@Override
public synchronized void receiveShoot(Point point){
if (!this.enemy.myTurn) return;
super.socket.send(new SocketPackage("SHOOT",point.toString()));
}
/**
* receives a hitresponse from the enemy player and sends it to the online partner
* @param hitResponse the hitresponse to be sent
* @author Peer Ole Wachtel, Luca Conte
*/
@Override
public synchronized void receiveHit(HitResponse hitResponse) {
switch (hitResponse.getType()) {
case HIT, SUNK:
this.myTurn = true;
break;
case MISS:
this.myTurn = false;
break;
case VICTORY:
// GameController.getMainFrame().showPanelLose("", this.enemy);
break;
}
super.socket.send(new SocketPackage("HIT", hitResponse.toString()));
}
/**
* receives the coin toss result from the enemy player and sends it to the online partner
* if this player has already received the enemies coin, this method does nothing.
* @param coin the result of the coin toss
* @author Peer Ole Wachtel, Luca Conte
*/
@Override
public synchronized void receiveCoin(boolean coin) {
if (!this.hasReceivedCoin) {
super.socket.send(new SocketPackage("COIN", String.valueOf(coin ? 1 : 0)));
this.hasReceivedCoin = true;
this.determineCoinToss();
}
}
/**
* für Online Player nicht zu implementieren
* nur für HumanPlayer relevant
* @author Luca Conte, Peer Ole Wachtel
*/
@Override
public synchronized void shoot(Point point) {
// SHOULD NEVER BE CALLED ON ONLINE PLAYER. ONLY ON HUMAN PLAYER
return;
}
/**
* empfängt Withdraw vom Gegner und leitet es an den Online Partner weiter
* beendet das Spiel
* @author Luca Conte
*/
@Override
public void receiveWithdraw() {
this.socket.send(new SocketPackage("WITHDRAW"));
super.receiveWithdraw();
}
}

View File

@ -1,26 +1,211 @@
import java.awt.*;
/**
* abstrakte repräsentation eines Spielers
* @author Peer Ole Wachtel, Luca Conte, Lucas Bronson
*/
public abstract class Player {
private boolean myTurn;
private boolean isServer;
private boolean waitingForResponse;
private Player enemy;
private String name;
private Board board;
protected boolean myTurn;
protected boolean isServer;
protected boolean waitingForResponse;
protected Player enemy;
protected String name;
protected Board board;
protected Boolean myCoin;
protected boolean gameRunning;
public void receiveShoot(Point point) {
protected boolean sentCoin;
protected boolean hasReceivedCoin;
/**
* Konstruktor
* @author Peer Ole Wachtel, Luca Conte
*/
public Player() {
this.setName("Player");
this.hasReceivedCoin = false;
this.sentCoin = false;
this.myTurn = false;
this.gameRunning = false;
}
public void receiveHit(HitResponse hitResponse) {
/**
* initialises this players board
* @param size the size of the board to be created
* @author Peer Ole Wachtel
*/
public void createBoard(int size) {
this.board = new Board(size);
}
public void click(Point point) {
/**
* receives a shot onto a point from the enemy
* @param point the location to be shot
* @author Luca Conte, Peer Ole Wachtel
*/
public abstract void receiveShoot(Point point);
/**
* receives a hit response from the enemy as a response to a receiveShoot call
* @param hitResponse the hitresponse
* @author Peer Ole Wachtel
*/
public abstract void receiveHit(HitResponse hitResponse);
/**
* sends shot to enemy player.
* should ONLY be called on HumanPlayer
* @author Luca Conte
*/
public abstract void shoot(Point point);
/**
* only relevant for AI Players.
* starts the first turn
* @author Luca Conte
*/
public void beginTurn() {
System.out.println("issa my turn-a");
}
public void beginTrun() {
/**
* sets the enemy Player
* @author Peer Ole Wachtel
*/
public void setEnemy(Player enemy) {
this.enemy = enemy;
}
/**
* sets the name of this player
* @param name the name of this player
* @author Luca Conte
*/
public void setName(String name) {
this.name = name;
}
/**
* returns the name of this player
* @return the name of this player
* @author Luca Conte
*/
public String getName() {
return this.name;
}
/**
* returns the board of this player
* @return the board of this player
* @author Lucas Bronson
*/
public Board getBoard() {
return this.board;
}
/**
* marks the player as ready by sending their coin to the enemy player
* calls determineCoinToss if the enemy coin has already been received
* @author Luca Conte
*/
public void ready() {
this.enemy.receiveCoin(this.myCoin);
this.sentCoin = true;
if (hasReceivedCoin) {
this.determineCoinToss();
}
};
/**
* determines the result of the coin toss
* this method does nothing if either player is not ready yet or has not yet sent their coin
* @author Luca Conte, Peer Ole Wachtel
*/
protected void determineCoinToss() {
if (!this.sentCoin || this.myCoin == null || !this.hasReceivedCoin || this.enemy.myCoin == null) return;
boolean result = this.enemy.myCoin ^ this.myCoin; // XOR
this.myTurn = result == this.isServer;
if (this.myTurn) {
this.beginTurn();
}
this.gameRunning = true;
GameController.getMainFrame().refreshGameBoard();
}
/**
* receives the coin toss from the enemy player
* @param coin the coin of the enemy player
* @author Peer Ole Wachtel
*/
public abstract void receiveCoin(boolean coin);
/**
* returns whether the game this player is in has started, meaning both players are ready and have sent their coins
* @return the game's running state
* @author Luca Conte
*/
public boolean isGameRunning() {
return this.gameRunning;
}
/**
* returns whether this player is ready and has sent their coin to the enemy player
* @return the player's ready state
* @author Lucas Bronson
*/
public boolean isReady() {
return this.sentCoin;
}
/**
* removes connections to the enemy and its board as well as setting myTurn and gameRunning to false
* this stops the AI Players from making more moves and allows the garbage collector to remove the boards
* and players
*
* This method should be called at the end of a game
*
* @author Luca Conte
*/
public void destroy() {
this.myTurn = false;
this.gameRunning = false;
this.board = null;
this.enemy = null;
}
/**
* the player wins
* ends the game
* @author Luca Conte
*/
public void win() {
GameController.getMainFrame().showPanelWin("", this);
}
/**
* the player loses
* ends the game
* @author Luca Conte
*/
public void lose() {
GameController.getMainFrame().showPanelLose("", this);
}
/**
* the player loses by withdrawal
* ends the game
* @author Luca Conte
*/
public void withdraw() {
this.enemy.receiveWithdraw();
this.lose();
}
/**
* the enemy player withdraws
* ends the game
* @author Luca Conte
*/
public void receiveWithdraw(){
this.win();
}
}

131
src/Point.java Normal file
View File

@ -0,0 +1,131 @@
/**
* repräsentation der Koordinaten eines Feldes auf dem Spielfeld
* @author Peer Ole Wachtel, Luca Conte
*/
public class Point {
private int x;
private int y;
/**
* initialises a point using X and Y coordinates starting at 0
* @param x the x coordinate of the point starting at 0
* @param y the y coordinate of the point starting at 0
* @author Peer Ole Wachtel
*/
public Point (int x, int y) {
this.setX(x);
this.setY(y);
}
/**
* initialises a Point using a coordinate provided in the format of a letter followed by a number
* this coordinate is checked using `isValidSyntax`
* If the coordinate is not in a valid syntax, an `IllegalArgumentException` will be thrown, stating as such
* The number part of the coordinate starts at 1 instead of 0 so for example, the
* string A1 will result in the X and Y coordinates of (0, 0)
* @param str the coordinate in alphanumeric format
* @throws IllegalArgumentException if the coordinate is invalid according to `isValidSyntax`
* @author Peer Ole Wachtel, Luca Conte
*/
public Point (String str) {
if (Point.isValidSyntax(str)) {
this.setX(str.charAt(0));
this.setY(Integer.parseInt(str.substring(1)) - 1);
} else {
throw new IllegalArgumentException("String ist keine gültige Koordinate");
}
}
/**
* returns this point as a string in its alphanumeric format
* @return this point as a string in its alphanumeric format
* @author Luca Conte, Peer Ole Wachtel
*/
@Override
public String toString() {
return (char) ('A' + this.x) + String.valueOf(this.y + 1);
}
/**
* returns the X coordinate of the point starting at 0
* @return the X coordinate of the point starting at 0
* @author Peer Ole Wachtel
*/
public int getX() {
return x;
}
/**
* returns the Y coordinate of the point starting at 0
* @return the Y coordinate of the point starting at 0
* @author Peer Ole Wachtel
*/
public int getY() {
return y;
}
/**
* sets the X coordinate of the point starting at 0
* @param x the X coordinate of the point starting at 0
* @author Peer Ole Wachtel
*/
public void setX(int x) {
this.x = x;
}
/**
* sets the Y coordinate of the point starting at 0
* @param y the Y coordinate of the point starting at 0
* @author Peer Ole Wachtel
*/
public void setY(int y) {
this.y = y;
}
/**
* sets the X coordinate of the from its character value in alphanumeric form
* @param c the character to be transformed into
* @author Peer Ole Wachtel
*/
public void setX(char c) {
this.x = c - 'A';
}
/**
* checks whether a string is a valid alphanumeric point coordinate
* @param str the string to be tested
* @return whether the string is valid according to the regular expression `^[A-Z]\\d+$`
* @author Peer Ole Wachtel
*/
public static boolean isValidSyntax(String str) {
return str.matches("^[A-Z]\\d+$");
}
/**
* returns whether two points are equal
* two points with equivalent coordinates are considered equal
* @param o the other object/Point to compare this one to
* @return whether the objects are equal
* @author Luca Conte
*/
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || this.getClass() != o.getClass()) return false;
Point p = (Point)o;
return p.getX() == this.getX() && p.getY() == this.getY();
}
/**
* determines whether two points are neighbours
* points are considered neighbours if their positions are equal or within a difference of 1 on both X and Y axis
* @param other the point to check for neighbourship
* @return whether the points are neighbours
* @author Luca Conte
*/
public boolean neighbours(Point other) {
if (other == null) return false;
return (int)Math.abs(this.getX() - other.getX()) <= 1 && (int)Math.abs(this.getY() - other.getY()) <= 1;
}
}

284
src/Ship.java Normal file
View File

@ -0,0 +1,284 @@
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
record ShipData (int size, String name){}
/**
* repräsentation eines Schiffes auf dem Spielfeld
* @author Peer Ole Wachtel, Lucas Bronson, Florian Hanzschel
*/
public class Ship {
static List<List<ShipData>> semeterList =
Arrays.asList(
Arrays.asList(
new ShipData(2, "PRG 1"),
new ShipData(2, "GDI"),
new ShipData(2, "MAT 1"),
new ShipData(2, "THI"),
new ShipData(4, "STP"),
new ShipData(6, "ENG")
),
Arrays.asList(
new ShipData(2, "PRG 2"),
new ShipData(2, "DBS 1"),
new ShipData(2, "MAT 2"),
new ShipData(2, "STA"),
new ShipData(2, "AUD")
),
Arrays.asList(
new ShipData(2, "PRG 3"),
new ShipData(2, "DBS 2"),
new ShipData(2, "MAT 3"),
new ShipData(2, "BSN 1"),
new ShipData(4, "PRP"),
new ShipData(6, "BWL")
),
Arrays.asList(
new ShipData(2, "WEB"),
new ShipData(2, "SE 1"),
new ShipData(2, "CG 1"),
new ShipData(2, "BSN 2"),
new ShipData(4, "SEM"),
new ShipData(6, "E BWL")
),
Arrays.asList(
new ShipData(2, "WPF 1"),
new ShipData(2, "SE 2"),
new ShipData(2, "CG 2"),
new ShipData(2, "PXP 1"),
new ShipData(6, "EF 1")
),
Arrays.asList(
new ShipData(2, "WPF 2"),
new ShipData(1, "PXP 2"),
new ShipData(8, "BAA")
)
);
private int size;
private boolean horizontal;
private Point position;
private String name;
private int hitsOnMe;
private boolean sunk;
/**
* initialises a Ship with a given size and name
* @param size the size of the ship
* @param name the name of the ship
* @author Peer Ole Wachtel
*/
public Ship (int size, String name) {
this.size = size;
this.name = name;
this.horizontal = false; //true = von Punkt aus nach rechts; false = von Punkt aus nach unten
this.position = null;
this.hitsOnMe = 0;
this.sunk = false;
}
/**
* resets the position of this ship
* @author Luca Conte
*/
public void resetPosition() {
this.position = null;
}
/**
* sets the position of this ship, provided it is valid
* @param pos the position to move the ship to
* @param horizontal whether the ship is horizontal or not
* @param shipsList the list of other ships on this board. It will be checked whether the ship is touching any of them
* @param boardSize the size of the board the ship is to be placed on
* @return true if the position was set successfully. false if the ship is out of the bounds of the board or touches a different ship
* @author Luca Conte
*/
public boolean setPosition(Point pos, boolean horizontal, List<Ship> shipsList, int boardSize) {
if (!this.checkValidPlacement(pos, horizontal, shipsList, boardSize)) return false;
// kein ueberlappen also setze das Schiff
this.position = pos;
this.horizontal = horizontal;
return true;
}
/**
* checks whether a position is valid for ship placement
* @param pos the position to check the ship placement at
* @param horizontal whether the ship is to be placed horizontally or not
* @param shipsList the list of other ships on this board. It will be checked whether the ship is touching any of them
* @param boardSize the size of the board the ship is to be placed on
* @return true if the position is valid. false if the ship is out of the bounds of the board or touches a different ship
* @author Florian Hantzschel, Peer Ole Wachtel, Luca Conte
*/
public boolean checkValidPlacement(Point pos, boolean horizontal, List<Ship> shipsList, int boardSize) {
// ueberpruefe boundaries
if (pos.getX() < 0 || pos.getY() < 0 || pos.getX() >= boardSize || pos.getY() >= boardSize) {
return false;
}
// bestimme die Endposition anhand der Ausrichtung
int endX = pos.getX();
int endY = pos.getY();
if (horizontal) { // rechts links
endX = pos.getX() + this.size - 1;
if (endX >= boardSize) {
return false;
}
} else { // oben unten
endY = pos.getY() + this.size - 1;
if (endY >= boardSize) {
return false;
}
}
// Liste an Punkten die das Schiff einnehmen wuerde
List<Point> shipPoints = this.getVirtualOccupiedPoints(pos, horizontal);
// ueberlappen mit anderen Schiffen pruefen
for (Ship otherShip : shipsList) {
// eigenes Schiff ueberspringen
if (otherShip == this) {
continue;
}
// ueberspringe falls noch nicht gesetzt
if (otherShip.position == null) {
continue;
}
// Punkte die das andere Schiff besetzt
List<Point> otherShipPoints = otherShip.getOccupiedPoints();
// ueberlappen checken
for (Point p : shipPoints) {
for (Point otherPoint : otherShipPoints) {
if (otherPoint.neighbours(p)) return false;
}
}
}
return true;
}
/**
* Returns the Points on the ship if it were to be placed at position `pos` in orientation defined by `horizontal`
* @param pos the position where the ship should be placed
* @param horizontal whether the ship should be placed horizontally
* @return a list of points the ship would occupy, were it placed at position `pos` in orientation `horizontal`
* @author Florian Hantzschel, Luca Conte
*/
public List<Point> getVirtualOccupiedPoints(Point pos, boolean horizontal) {
List<Point> points = new ArrayList<>();
if (pos == null) {
return points;
}
for (int i = 0; i < this.size; i++) {
int x = horizontal ? pos.getX() + i : pos.getX();
int y = horizontal ? pos.getY() : pos.getY() + i;
points.add(new Point(x, y));
}
return points;
}
/**
* Returns the Points the ship occupies
* @return a list of points the ship occupies
* @author Florian Hantzschel, Luca Conte
*/
public List<Point> getOccupiedPoints() {
return this.getVirtualOccupiedPoints(this.position, this.horizontal);
}
/**
* returns the position of this ship
* @return the position of this ship
* @author Peer Ole Wachtel
*/
public Point getPosition() {
return position;
}
/**
* checks whether the ship occupies a certain point
* @param pos the point to be checkd
* @return whether the point provided is one of the points occupied by the ship
* @author Peer Ole Wachtel, Lucas Bronson
*/
public boolean isShipOnPos(Point pos){
if(this.position == null){
return false;
}
if ((this.horizontal && pos.getY() == this.position.getY() && pos.getX() >= this.position.getX() && pos.getX() < this.position.getX() + size) ||
(!(this.horizontal) && pos.getX() == this.position.getX() && pos.getY() >= this.position.getY() && pos.getY() < this.position.getY() + size)) {
return true;
}
return false;
}
/**
* "shoots" this ship.
* @return a hit response, depending on whether the ship was hit or not. If the amount of times
* the ship was hit is greater or equal to the size of the ship, the ship is considered sunk.
* @param pos the point where the ship is shot
* @author Peer Ole Wachtel
*/
public HitResponseType shootOnShip(Point pos) {
if (this.isShipOnPos(pos)) {
hitsOnMe++;
if (hitsOnMe >= size) {
this.sunk = true;
return HitResponseType.SUNK;
} else {
return HitResponseType.HIT;
}
} else {
return HitResponseType.MISS;
}
}
/**
* returns whether the ship has been sunk or not
* @return whether the ship has been sunk or not
* @author Peer Ole Wachtel
*/
public boolean isSunk() {
return sunk;
}
/**
* sets the orientation of the ship
* @param horizontal whether the ship is to be placed in a horizontal orientation
* @author Lucas Bronson
*/
public void setHorizontal(boolean horizontal) {
this.horizontal = horizontal;
}
/**
* returns the size of the ship
* @return the size of the ship
* @author Lucas Bronson
*/
public int getSize() {
return size;
}
/**
* returns the name of the ship
* @return the name of the ship
* @author Lucas Bronson
*/
public String getName() {
return name;
}
/**
* returns whether the ship has been placed or not
* @return whether the ship has been placed or not
* @author Lucas Bronson
*/
public boolean isPlaced(){
return this.position != null;
}
}

44
src/ShipButton.java Normal file
View File

@ -0,0 +1,44 @@
import javax.swing.*;
import java.awt.*;
/**
* Das ShipButton Panel dient dem Erstellen eines lokalen Spiels.
* Hier kann der Benutzer Spieler inklusive Namen und das Semester, in dem sich der Benutzer befindet, einstellen.
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public class ShipButton extends JButton {
private Ship ship;
private BoardDisplay boardDisplay;
/**
* Erstellt Buttons für die beiden Spieler (Module/Schiffe)
* @param ship Schiff von welchem der Name genommen wird
* @param boardDisplay Klasse für Interaktion
* @author Lucas Bronson, Luca Conte, Joshua Kuklok
*/
public ShipButton(Ship ship, BoardDisplay boardDisplay) {
super(ship.getName());
this.ship = ship;
this.boardDisplay = boardDisplay;
this.addActionListener((e) -> {
boardDisplay.selectCurrentShip(this.ship);
});
}
/**
* Setzt Farbe der Modulbuttons.
* Verschiedene Farben für:
* Modul ausgewählt, platziert nicht platziert.
* @author Joshua Kuklok
*/
public void refreshButtonState() {
if (ship.isPlaced()) {
setBackground(Color.LIGHT_GRAY);
} else {
setBackground(Color.WHITE);
}
if (boardDisplay.getCurrentShip() == ship) {
setBackground(Color.CYAN);
}
}
}

111
src/SocketPackage.java Normal file
View File

@ -0,0 +1,111 @@
import java.util.Arrays;
import java.util.List;
/**
* beschreibt ein Package das durch einen AsyncSocket gesendet werden kann nach Netzwerkstandard
* https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
* @author Luca Conte
*/
public class SocketPackage {
private String name = "";
private String data = "";
/**
* initialises a socket package by prividing a package name and data
* @param name the name of the package
* @param data the data of the package
* @author Luca Conte
*/
public SocketPackage(String name, String data) {
this.setName(name);
this.setData(data);
}
/**
* initialises an empty socket package
* @author Luca Conte
*/
public SocketPackage() {
this("","");
}
/**
* initialises a socket package from a message
* the message is parsed according to https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
* @param message the message to be parsed
* @author Luca Conte
*/
public SocketPackage(String message) {
if (message.length() <= 0) {
throw new IllegalArgumentException("Socket message cannot be empty.");
}
String[] components = message.split(" ");
this.setName(components[0]);
if (components.length > 1) {
this.setData(message.substring(components[0].length() + 1));
} else {
this.setData("");
}
}
/**
* sets the package name
* the name is always stored in upper case
* @param name the new name of the package
* @author Luca Conte
*/
public void setName(String name) {
if (name == null) name = "";
this.name = name.toUpperCase();
}
/**
* sets the package data
* @param name the new data of the package
* @author Luca Conte
*/
public void setData(String data) {
if (data == null) data = "";
this.data = data;
}
/**
* returns the name of the package
* @return the name of the package
* @author Luca Conte
*/
public String getName() {
return this.name;
}
/**
* returns the data of the package
* @return the data of the package
* @author Luca Conte
*/
public String getData() {
return this.data;
}
/**
* parses the package into a string according to https://github.com/lgc-4/ProgProjekt-Netzwerkstandard
* the package name and data are joined using a space " " `0x20`
* @return the package in string format
* @author Luca Conte
*/
public String toString() {
if (this.data == null || this.data.length() == 0) {
return this.name;
} else {
return this.name + " " + this.data;
}
}
/**
* returns the data string as a list, split at every space " " `0x20`
* @return the data string as a list, split at every space " " `0x20`
* @author Luca Conte
*/
public List<String> splitData() {
return Arrays.asList(this.data.split(" "));
}
}

View File

@ -1,24 +1,43 @@
import javazoom.jl.decoder.JavaLayerException;
import javazoom.jl.player.Player;
import java.awt.List;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
/**
* Der SoundHandler dient zum Anlegen und Abspielen von Sounds
* @author Lucas Bronson, Luca Conte, Ole Wachtel, Joshua Kuklok
*/
public class SoundHandler {
private static boolean soundOn = true;
private static ArrayList<Thread> runningThreads = new ArrayList<Thread>();
// Wenn fehler beim erstellen von .jar mit sound hier gucken
private static HashMap<String, String> sounds = new HashMap<String, String>(Map.of(
"hit", "./Sound/water-drip.mp3"
"miss", "./Sound/water-drip.mp3",
"hit", "./Sound/hit.mp3",
"destroyed", "./Sound/hit.mp3",
"plop", "./Sound/plop.mp3",
"loose", "./Sound/loosescreenlaugh.mp3",
"win", "./Sound/win.mp3",
"yourturn", "./Sound/yourturn.mp3"
));
/**
* Erstellt neuen Thread, um ausgewählten Sound abzuspielen
* @param soundName Name der Audiodatei, welche abgespielt werden soll
* @author Ole Wachtel, Luca Conte
*/
public static void playSound(String soundName) {
if (soundOn) {
new Thread(new Runnable() {
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
@ -28,16 +47,42 @@ public class SoundHandler {
e.printStackTrace();
}
}
}).start();
});
thread.start();
runningThreads.add(thread);
}
Iterator<Thread> i = runningThreads.iterator();
while (i.hasNext()) {
Thread oldThread = i.next();
if (!oldThread.isAlive()) {
try {
oldThread.join();
i.remove();
System.out.println("cleared thread");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
/**
* fügt einen neuen Sound zum SoundHanlder hinzu
* @param soundName der intern zu verwendende Name des Sounds
* @param path der Dateipfad zur Sound Datei
* @author Ole Wachtel
*/
static void add(String soundName, String path){
sounds.put(soundName, path);
}
/**
* schaltet den Ton an oder aus
* @param sound ob der sound an ist
* @author Ole Wachtel
*/
static void setSoundOn(boolean sound){
soundOn= sound;
}

View File

@ -0,0 +1,17 @@
/**
* Diese Klasse implementiert den Einfachsten Ki Spieler.
* @author Florian Alexy und Florian Hantzschel
* */
public class SpecificAiPlayerEasy extends AiPlayer{
/**
* Bein einfachen Ki Spieler wird nur der AiPlayer initialisiert und der Name gesetzt,
* da in der Eltern-Klasse AiPlayer eine default implementierung für alle Methoden existieren.
* @author Florian Alexy und Florian Hantzschel
*/
public SpecificAiPlayerEasy() {
super();
this.setName("AI Player Easy");
}
}

View File

@ -0,0 +1,273 @@
import java.util.ArrayList;
// import java.util.Random; wird nicht mehr verwendet
/**
* Diese Klasse implementiert den Harten Ki Spieler.
* @author Florian Alexy und Florian Hantzschel
* */
public class SpecificAiPlayerHard extends AiPlayer{
private int gridSize;
private boolean[][] shotsFired;
private final ArrayList<Point> hitQueue;
//private final Random random; wird nicht mehr verwendet
private int nextChessRow;
private int nextChessCol;
// Enum für die Orientierung
private enum Orientierung {
UNBEKANNT,
HORIZONTAL,
VERTIKAL
}
private Orientierung orientierung;
// Speichert den ersten Treffer zur Bestimmung der Orientierung
private Point firstHit;
/**
* Eltern-Klasse wird initialisiert und alle lokalen variablen,
* die gesetzt werden können, werden initialisiert.
* @author Florian Alexy und Florian Hantzschel
*/
public SpecificAiPlayerHard() {
super();
this.setName("AI Player Hard");
/*this.gridSize = super.board.getSize();
this.shotsFired = new boolean[gridSize][gridSize];*/
this.gridSize = 0;
this.hitQueue = new ArrayList<>();
//this.random = new Random(); wird nicht mehr verwendet
this.nextChessRow = 0;
this.nextChessCol = 0;
this.orientierung = Orientierung.UNBEKANNT;
this.firstHit = null;
}
/**
* Prüft, ob auf den punkt schonmal geschossen wurde.
* @param p zu prüfender Punkt
* @return boolean
* @author Florian Alexy und Florian Hantzschel
*/
public boolean alreadyShot(Point p) {
return shotsFired[p.getX()][p.getY()];
}
/**
* Bestimmt den nächsten punkt, der beschossen werden soll.
* @return Position
* @author Florian Alexy und Florian Hantzschel
*/
public Point getNextMove() {
if(gridSize == 0) {
this.gridSize = super.board.getSize();
this.shotsFired = new boolean[gridSize][gridSize];
}
// Wenn wir noch Treffer in der Queue haben, diese priorisieren
while (!hitQueue.isEmpty()) {
Point target = hitQueue.remove(0);
if (!alreadyShot(target)) {
shotsFired[target.getX()][target.getY()] = true;
return target;
}
}
// Ansonsten weiterhin "Schachbrettmuster"
int row = nextChessRow;
int col = nextChessCol;
while (alreadyShot(new Point(row, col))) {
advanceChessPattern();
row = nextChessRow;
col = nextChessCol;
}
shotsFired[row][col] = true;
advanceChessPattern();
return new Point(row, col);
}
/**
* Nachdem receiveShoot beim gegner den schuss verarbeitet hat,
* wird diese Methode mit der antwort aufgerufen.
* @param hitResponse the hitresponse
* @author Florian Alexy und Florian Hantzschel
*/
@Override
public synchronized void receiveHit(HitResponse hitResponse) {
super.receiveHit(hitResponse);
// Wenn es ein Treffer ist, Adjacent-Punkte hinzufügen
if (hitResponse.getHitResponse() == HitResponseType.HIT) {
Point hitPoint = hitResponse.getPoint();
// Wenn wir noch keinen ersten Treffer haben, speicher ihn
if (firstHit == null) {
firstHit = hitPoint;
// Orientierung noch unbekannt: alle möglichen Richtungen hinzufügen
addAdjacentPoints(hitPoint);
} else {
// Wenn Orientierung noch nicht bestimmt, jetzt prüfen
if (this.orientierung == Orientierung.UNBEKANNT) {
// Prüfen, ob der zweite Treffer horizontal oder vertikal liegt
if (firstHit.getY() == hitPoint.getY()) {
this.orientierung = Orientierung.VERTIKAL;
} else if (firstHit.getX() == hitPoint.getX()) {
this.orientierung = Orientierung.HORIZONTAL;
}
// Sobald die Orientierung erkannt wurde, entferne alle unpassenden Punkte
if (this.orientierung != Orientierung.UNBEKANNT) {
cleanUpHitQueue();
}
}
// Für den aktuellen Treffer nur in passender Orientierung erweitern
addPointsByOrientation(hitPoint);
}
} else if (hitResponse.getHitResponse() == HitResponseType.SUNK) {
this.orientierung = Orientierung.UNBEKANNT;
firstHit = null;
hitQueue.clear();
}
}
/**
* Entfernt aus der hitQueue alle Punkte, die nicht der erkannten Orientierung entsprechen.
* @author Florian Alexy und Florian Hantzschel
*/
private void cleanUpHitQueue() {
if (firstHit == null || this.orientierung == Orientierung.UNBEKANNT) {
return;
}
ArrayList<Point> toRemove = new ArrayList<>();
for (Point p : hitQueue) {
if (this.orientierung == Orientierung.HORIZONTAL) {
// HORIZONTAL => gleiche Zeile wie firstHit
if (p.getX() != firstHit.getX()) {
toRemove.add(p);
}
} else if (this.orientierung == Orientierung.VERTIKAL) {
// VERTICAL => gleiche Spalte wie firstHit
if (p.getY() != firstHit.getY()) {
toRemove.add(p);
}
}
}
hitQueue.removeAll(toRemove);
}
/**
* Fügt benachbarte Felder in der erkannten Orientierung hinzu.
* Ist die Orientierung HORIZONTAL, so werden nur links/rechts hinzugefügt.
* Ist sie VERTICAL, so werden nur oben/unten hinzugefügt.
* @author Florian Alexy und Florian Hantzschel
*/
private void addPointsByOrientation(Point point) {
if (this.orientierung == Orientierung.UNBEKANNT) {
// Fallback: füge alle benachbarten Punkte hinzu
addAdjacentPoints(point);
return;
}
int x = point.getX();
int y = point.getY();
if (this.orientierung == Orientierung.HORIZONTAL) {
// Gleiche Zeile => links und rechts vom Point
Point left = new Point(x, y - 1);
Point right = new Point(x, y + 1);
if (isValidPoint(left) && !alreadyShot(left) && !hitQueue.contains(left)) {
hitQueue.add(left);
}
if (isValidPoint(right) && !alreadyShot(right) && !hitQueue.contains(right)) {
hitQueue.add(right);
}
} else if (this.orientierung == Orientierung.VERTIKAL) {
// Gleiche Spalte => oben und unten
Point up = new Point(x - 1, y);
Point down = new Point(x + 1, y);
if (isValidPoint(up) && !alreadyShot(up) && !hitQueue.contains(up)) {
hitQueue.add(up);
}
if (isValidPoint(down) && !alreadyShot(down) && !hitQueue.contains(down)) {
hitQueue.add(down);
}
}
}
/**
* Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten.
* @param point
* @author Florian Alexy und Florian Hantzschel
*/
private void addAdjacentPoints(Point point) {
int x = point.getX();
int y = point.getY();
// Possible adjacent positions (up, down, left, right)
Point[] adjacentPoints = {
new Point(x, y - 1),
new Point(x, y + 1),
new Point(x - 1, y),
new Point(x + 1, y)
};
for (Point p : adjacentPoints) {
if (isValidPoint(p) && !alreadyShot(p) && !hitQueue.contains(p)) {
hitQueue.add(p);
}
}
}
/**
* Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean)
* @param point Punkt der geprüft werden soll
* @return Ist auf dem Board oder nicht.
* @author Florian Alexy und Florian Hantzschel
*/
private boolean isValidPoint(Point point) {
return point.getX() >= 0 && point.getX() < gridSize &&
point.getY() >= 0 && point.getY() < gridSize;
}
/**
* Ki Methode um zu schießen.
* @author Florian Alexy und Florian Hantzschel
*/
@Override
public void aiShoot() {
this.enemy.receiveShoot(getNextMove());
}
/**
* Die Zeilen und spalten variable wird hier angepasst, sodass beim nächsten schuss im Muster geschossen wird.
* @author Florian Alexy und Florian Hantzschel
*/
private void advanceChessPattern() {
nextChessCol += 2;
if (nextChessCol >= gridSize) {
nextChessRow += 1;
nextChessCol = (nextChessRow % 2 == 0) ? 0 : 1; // Alternate starting points for chess pattern
}
if (nextChessRow >= gridSize) {
nextChessRow = 0;
nextChessCol = 0; // Reset if pattern wraps around
}
}
// Adds adjacent cells to the hit queue
/* public void processHit(int row, int col) {
if (row > 0 && !alreadyShot(row - 1, col)) {
hitQueue.add(new int[]{row - 1, col});
}
if (row < gridSize - 1 && !alreadyShot(row + 1, col)) {
hitQueue.add(new int[]{row + 1, col});
}
if (col > 0 && !alreadyShot(row, col - 1)) {
hitQueue.add(new int[]{row, col - 1});
}
if (col < gridSize - 1 && !alreadyShot(row, col + 1)) {
hitQueue.add(new int[]{row, col + 1});
}
}*/
}

View File

@ -0,0 +1,119 @@
import java.util.ArrayList;
import java.util.List;
/**
* Diese Klasse implementiert den Medium Ki Spieler.
* @author Florian Alexy und Florian Hantzschel
* */
public class SpecificAiPlayerMedium extends AiPlayer{
/**
* Liste an Punkten die beschossen werden sollen. (Mögliche weitere Segmente vom schiff)
*/
private List<Point> hitsQueue = new ArrayList<>();
/**
* Eltern-Klasse wird initialisiert und der Name wird gesetzt.
* @author Florian Alexy und Florian Hantzschel
*/
public SpecificAiPlayerMedium() {
super();
this.setName("AI Player Medium");
}
/**
* Ki Methode um zu schießen.
* @author Florian Alexy und Florian Hantzschel
*/
@Override
public void aiShoot() {
Point nextShot = ComputeNextShot();
// Shoot at the enemy and receive the hit response
enemy.receiveShoot(nextShot);
}
/**
* Nachdem receiveShoot beim gegner den schuss verarbeitet hat,
* wird diese Methode mit der antwort aufgerufen.
* @param hitResponse the hitresponse
* @author Florian Alexy und Florian Hantzschel
*/
@Override
public synchronized void receiveHit(HitResponse hitResponse) {
super.receiveHit(hitResponse);
// If it's a hit or sunk, add adjacent cells to the hitsQueue
if (hitResponse.getHitResponse() == HitResponseType.HIT) {
addAdjacentPoints(hitResponse.getPoint());
}
}
/**
* Die Methode bestimmt welche Position als nächstes beschossen werden soll.
* @return der Punkt auf den als nächtest geschossen werden soll
* @author Florian Alexy und Florian Hantzschel
*/
public Point ComputeNextShot() {
Point nextShot;
// Prioritize shots from the hitsQueue
while (!hitsQueue.isEmpty()) {
nextShot = hitsQueue.remove(0);
if (!alreadyShot(nextShot)) {
return nextShot;
}
}
// If hitsQueue is empty, pick a random point that hasn't been shot
do {
nextShot = RandomPoint();
} while (alreadyShot(nextShot));
return nextShot;
}
/**
* Diese Methode erweitert die hitsQueue um die umliegenden Punkte die Schiffe seien könnten.
* @param point der Punkt dessen nachbarn zur hitQueue hinzugefügt werden sollen
* @author Florian Alexy und Florian Hantzschel
*/
private void addAdjacentPoints(Point point) {
int x = point.getX();
int y = point.getY();
// Possible adjacent positions (up, down, left, right)
Point[] adjacentPoints = {
new Point(x, y - 1),
new Point(x, y + 1),
new Point(x - 1, y),
new Point(x + 1, y)
};
for (Point p : adjacentPoints) {
if (isValidPoint(p) && !alreadyShot(p) && !hitsQueue.contains(p)) {
hitsQueue.add(p);
}
}
}
/**
* Diese Methode gibt zurück, ob eine Position schon beschossen wurde. (Boolean)
* @param p Punkt der geprüft werden soll
* @return wurde schon beschossen oder nicht.
* @author Florian Alexy und Florian Hantzschel
*/
private boolean alreadyShot(Point p) {
return this.enemy.board.getHitResponseOnPoint(p) != null;
}
/**
* Die Methode gibt zurück, ob eine Position auf dem Board ist. (Boolean)
* @param point Punkt der geprüft werden soll
* @return Ist auf dem Board oder nicht.
* @author Florian Alexy und Florian Hantzschel
*/
private boolean isValidPoint(Point point) {
return point.getX() >= 0 && point.getX() < board.getSize() &&
point.getY() >= 0 && point.getY() < board.getSize();
}
}

37
src/Verbinden.java Normal file
View File

@ -0,0 +1,37 @@
import javax.swing.*;
import java.awt.*;
/**
* Das Verbinden Panel dient als "Überblende", während im Backend das Spiel erstellt/ eine Verbindung hergestellt wird.
* @author Lucas Bronson
*/
public class Verbinden extends JPanel{
//ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
JLabel verbindenLabel = new JLabel("Verbinde . . .",SwingConstants.CENTER);
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
/**
* Konstruktor der Verbinden Klasse.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
public Verbinden(MainFrame frame) {
setLayout(null);
buildPanel(frame);
}
/**
* Baut Panel auf.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
private void buildPanel(MainFrame frame) {
setLayout(new BorderLayout());
verbindenLabel.setFont(robotoFont.deriveFont(50f));
add(verbindenLabel, BorderLayout.CENTER);
}
}

65
src/WinScreen.java Normal file
View File

@ -0,0 +1,65 @@
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
/**
* Klasse für Erstellung von winScreen Objekten
* Dient zur Anzeige des Sieges nachdem ein Spiel
* @author Lucas Bronson
*/
public class WinScreen extends JPanel {
JLabel winLabel = new JLabel("Du hast Gewonnen!");
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
JButton okButton = new JButton("Zurück zum Hauptmenü");
/**
* Konstruktor der WinScreen Klasse
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson
*/
public WinScreen(MainFrame frame) {
setLayout(null);
buildPanel(frame);
}
/**
* Panel bauen/Objekte hinzufuegen
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson, Joshua Kuklok
*/
public void buildPanel(MainFrame frame) {
Timer timer = new Timer(5, new ActionListener() {
private float hue = 0; // Farbton-Wert für HSB-Farbmodell
@Override
public void actionPerformed(ActionEvent e) {
// Farbe basierend auf dem Farbton-Wert berechnen
Color pulsierendeFarbe = Color.getHSBColor(hue, 0.8f, 0.8f); // Sättigung und Helligkeit fix
winLabel.setForeground(pulsierendeFarbe);
// Farbton leicht verändern (Zyklus zwischen 0 und 1)
hue += 0.01f;
if (hue > 1) {
hue = 0;
}
}
});
okButton.setBounds(650,525,200,50);
winLabel.setBounds(500,450,500,50);
timer.start(); // Timer starten
winLabel.setFont(robotoFont);
winLabel.setHorizontalAlignment(SwingConstants.CENTER);
SoundHandler.playSound("win");
// Zurückkehren zum Hauptmenü, wenn okButton gedrückt wird
okButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanel("MainMenu");
}
});
add(winLabel);
add(okButton);
}
}

View File

@ -1,26 +1,35 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
/**
* Das startLocalGame Panel dient dem Erstellen eines lokalen Spiels.
* Hier kann der Benutzer Spieler inklusive Namen und das Semester, in dem sich der Benutzer befindet, einstellen.
* @author Lucas Bronson, Joshua Kuklok, Luca Conte
*/
public class startLocalGame extends JPanel {
public class startLocalGame {
// Funktionshilfen
int semesterCounter = 1; // Semester Counter Label
String leftPlayerNickname = "Spieler 1";
String rightPlayerNickname = "Einfach";
// Grafiken
ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
ImageIcon humanPlayerIcon = new ImageIcon("graphics/humanPlayer.png");
ImageIcon aiPlayerIcon = new ImageIcon("graphics/aiPlayer.png");
// Frame
JFrame frame = new JFrame("Lokales Spiel");
ImageIcon aiPlayerEasyIcon = new ImageIcon("graphics/botPlayerEasy.png");
ImageIcon aiPlayerNormalIcon = new ImageIcon("graphics/botPlayerNormal.png");
ImageIcon aiPlayerHardIcon = new ImageIcon("graphics/botPlayerHard.png");
// Labels
JLabel frameTitle = new JLabel("Lokales Spiel");
JLabel semesterlable = new JLabel("Semester");
JLabel semesterLabel = new JLabel("Semester");
JLabel leftPlayerName = new JLabel("Name");
JLabel rightPlayerName = new JLabel("KI-Level");
JLabel leftPlayerIcon = new JLabel(humanPlayerIcon);
JLabel rightPlayerIcon = new JLabel(aiPlayerIcon);
JLabel rightPlayerIcon = new JLabel(aiPlayerEasyIcon);
JLabel semesterCounterLabel = new JLabel(String.valueOf(semesterCounter));
// Buttons
@ -36,138 +45,277 @@ public class startLocalGame {
// Textfelder
JTextField leftPlayerTextField = new JTextField(20);
JTextField rightPlayerTextField = new JTextField(20);
startLocalGame() {
// Erstelle Frame
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(1500, 1000);
// Layout Manager (absolute ositionierung)
frame.setLayout(null);
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
/**
* Konstruktor der startLocalGame.
* Fügt Buttons, Textfelder und Label hinzu.
* Fügt ebenfalls ActionListeners hinzu, damit Buttons etc. ihre gewünschte Funktion haben
*
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Lucas Bronson, Joshua Kuklok
*/
startLocalGame(MainFrame frame) {
// Layout des Panels
setLayout(null);
// Erstelle Label
frameTitle.setBounds(20, 20, 200, 30);
frame.add(frameTitle);
// Setze Komponentenpositionen
frameTitle.setBounds(20, 20, 500, 60);
frameTitle.setFont(robotoFont.deriveFont(50f));
add(frameTitle);
semesterlable.setBounds(700, 300, 200, 30);
frame.add(semesterlable);
semesterLabel.setBounds(700, 300, 200, 30);
add(semesterLabel);
leftPlayerName.setBounds(50, 625, 200, 30);
frame.add(leftPlayerName);
add(leftPlayerName);
rightPlayerName.setBounds(1200, 625, 200, 30);
frame.add(rightPlayerName);
add(rightPlayerName);
leftPlayerIcon.setBounds(75, 400, 200, 128);
frame.add(leftPlayerIcon);
add(leftPlayerIcon);
rightPlayerIcon.setBounds(1225, 400, 200, 128);
frame.add(rightPlayerIcon);
add(rightPlayerIcon);
semesterCounterLabel.setBounds(725, 475, 50, 50); // zwischen den Up/Down-Buttons
semesterCounterLabel.setBounds(705, 475, 50, 50);
semesterCounterLabel.setHorizontalAlignment(SwingConstants.CENTER);
frame.add(semesterCounterLabel);
add(semesterCounterLabel);
// Erstellt Buttons
backButton.setBounds(1380, 20, 80, 80);
frame.add(backButton);
add(backButton);
leftPlayerLeftButton.setBounds(50, 450, 50, 50);
frame.add(leftPlayerLeftButton);
add(leftPlayerLeftButton);
leftPlayerRightButton.setBounds(250, 450, 50, 50);
frame.add(leftPlayerRightButton);
add(leftPlayerRightButton);
semesterUpButton.setBounds(725, 400, 50, 50);
frame.add(semesterUpButton);
semesterUpButton.setBounds(705, 400, 50, 50);
add(semesterUpButton);
semesterDownButton.setBounds(725, 550, 50, 50);
frame.add(semesterDownButton);
semesterDownButton.setBounds(705, 550, 50, 50);
add(semesterDownButton);
rightPlayerLeftButton.setBounds(1200, 450, 50, 50);
frame.add(rightPlayerLeftButton);
add(rightPlayerLeftButton);
rightPlayerRightButton.setBounds(1400, 450, 50, 50);
frame.add(rightPlayerRightButton);
add(rightPlayerRightButton);
startButton.setBounds(700, 750, 100, 50);
frame.add(startButton);
add(startButton);
// Erstellt Textfelder
leftPlayerTextField.setBounds(50, 650, 250, 50);
frame.add(leftPlayerTextField);
leftPlayerTextField.setText(leftPlayerNickname);
add(leftPlayerTextField);
rightPlayerTextField.setBounds(1200, 650, 250, 50);
frame.add(rightPlayerTextField);
rightPlayerTextField.setText(rightPlayerNickname);
add(rightPlayerTextField);
// ActionListener für die Buttons
semesterUpButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (semesterCounter < 6) {
semesterCounter++;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
// ActionListener für Buttons.
// Um das Semester zu erhöhen.
semesterUpButton.addActionListener(e -> {
if (semesterCounter < 6) {
semesterCounter++;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
});
semesterDownButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (semesterCounter > 1) { // Verhindert, dass der Wert unter 1 fällt
semesterCounter--;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
// Um das Semester zu senken.
semesterDownButton.addActionListener(e -> {
if (semesterCounter > 1) {
semesterCounter--;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
});
// Um linken Player nach links zu "rotieren".
leftPlayerLeftButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(leftPlayerIcon.getIcon()==humanPlayerIcon) {
leftPlayerIcon.setIcon(aiPlayerIcon);
}else{
leftPlayerIcon.setIcon(humanPlayerIcon);
}
toggleLeftPlayerIconLeft();
updateTextFields();
}
});
// Um linken Player nach rechts zu "rotieren".
leftPlayerRightButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(leftPlayerIcon.getIcon()==humanPlayerIcon) {
leftPlayerIcon.setIcon(aiPlayerIcon);
}else{
leftPlayerIcon.setIcon(humanPlayerIcon);
}
toggleLeftPlayerIconRight();
updateTextFields();
}
});
// Um rechten Player nach links zu "rotieren".
rightPlayerLeftButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(rightPlayerIcon.getIcon()==humanPlayerIcon) {
rightPlayerIcon.setIcon(aiPlayerIcon);
}else{
rightPlayerIcon.setIcon(humanPlayerIcon);
}
toggleRightPlayerIconLeft();
updateTextFields();
}
});
// Um den rechten Player nach rechts zu "rotieren".
rightPlayerRightButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
ImageIcon MuteIcon = new ImageIcon("Grafik/sound button muted.png");
if(rightPlayerIcon.getIcon()==humanPlayerIcon) {
rightPlayerIcon.setIcon(aiPlayerIcon);
}else{
rightPlayerIcon.setIcon(humanPlayerIcon);
}
toggleRightPlayerIconRight();
updateTextFields();
}
});
// Um Namen des linken Spielers zu speichern.
leftPlayerTextField.addActionListener(e -> {
leftPlayerNickname = leftPlayerTextField.getText();
System.out.println("Linker Spielername geändert zu: " + leftPlayerNickname); // Debugging-Ausgabe
});
// Um Namen des linken Spielers zu speichern, auch wenn nicht Enter gedrückt wird.
leftPlayerTextField.addFocusListener(new java.awt.event.FocusAdapter() {
@Override
public void focusLost(java.awt.event.FocusEvent evt) {
leftPlayerNickname = leftPlayerTextField.getText();
System.out.println("Linker Spielername geändert zu: " + leftPlayerNickname); // Debugging-Ausgabe
}
});
// Um zum MainMenu zu wechseln.
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanel("MainMenu");
}
});
// Um zum startLocalGameLoadingScreen zu wechseln und Daten an Backend weiterzureichen.
startButton.addActionListener(new ActionListener() {
@SuppressWarnings("unchecked")
@Override
public void actionPerformed(ActionEvent e) {
HashMap<ImageIcon, Class<? extends LocalPlayer>> playerClassMap = new HashMap<>();
playerClassMap.put(humanPlayerIcon, HumanPlayer.class);
playerClassMap.put(aiPlayerEasyIcon, SpecificAiPlayerEasy.class);
playerClassMap.put(aiPlayerNormalIcon, SpecificAiPlayerMedium.class);
playerClassMap.put(aiPlayerHardIcon, SpecificAiPlayerHard.class);
frame.showPanelSLGLS("startLocalGameLoadingScreen", semesterCounter);
Class<? extends LocalPlayer> leftPlayerClass = playerClassMap.get(leftPlayerIcon.getIcon());
Class<? extends AiPlayer> rightPlayerClass = (Class<? extends AiPlayer>) playerClassMap.get(rightPlayerIcon.getIcon());
GameController.startLocalGame(
leftPlayerClass, leftPlayerNickname,
rightPlayerClass,
GameController.semesterToBoardSize(semesterCounter)
);
}
});
frame.setVisible(true);
}
}
// Hilfsfunktionen
/**
* Setzt das jeweils "nächste" Icon, wenn der leftPlayerLeftButton gedrückt wird.
* @author Joshua Kuklok
*/
private void toggleLeftPlayerIconLeft() {
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {
leftPlayerIcon.setIcon(aiPlayerHardIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerEasyIcon){
leftPlayerIcon.setIcon(humanPlayerIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerNormalIcon) {
leftPlayerIcon.setIcon(aiPlayerEasyIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerHardIcon) {
leftPlayerIcon.setIcon(aiPlayerNormalIcon);
}
}
/**
* Setzt das jeweils "nächste" Icon, wenn der leftPlayerRightButton gedrückt wird.
* @author Joshua Kuklok
*/
private void toggleLeftPlayerIconRight() {
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {
leftPlayerIcon.setIcon(aiPlayerEasyIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerEasyIcon){
leftPlayerIcon.setIcon(aiPlayerNormalIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerNormalIcon) {
leftPlayerIcon.setIcon(aiPlayerHardIcon);
} else if (leftPlayerIcon.getIcon() == aiPlayerHardIcon) {
leftPlayerIcon.setIcon(humanPlayerIcon);
}
}
/**
* Setzt das jeweils "nächste" Icon, wenn der RightPlayerLeftButton gedrückt wird.
* @author Joshua Kuklok
*/
private void toggleRightPlayerIconLeft() {
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
rightPlayerIcon.setIcon(aiPlayerHardIcon);
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon){
rightPlayerIcon.setIcon(aiPlayerEasyIcon);
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
rightPlayerIcon.setIcon(aiPlayerNormalIcon);
}
}
/**
* Setzt das jeweils "nächste" Icon, wenn der RightPlayerRightButton gedrückt wird.
* @author Joshua Kuklok
*/
private void toggleRightPlayerIconRight() {
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon) {
rightPlayerIcon.setIcon(aiPlayerNormalIcon);
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon){
rightPlayerIcon.setIcon(aiPlayerHardIcon);
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
rightPlayerIcon.setIcon(aiPlayerEasyIcon);
}
}
/**
* Aktualisiert die Textfelder basierend auf den Icons
* @author Joshua Kuklok
*/
private void updateTextFields() {
// Für Linken Spieler
if (leftPlayerIcon.getIcon() == humanPlayerIcon) {
leftPlayerTextField.setText(leftPlayerNickname);
} else if (leftPlayerIcon.getIcon() == aiPlayerEasyIcon){
leftPlayerTextField.setText("Einfach");
} else if (leftPlayerIcon.getIcon() == aiPlayerNormalIcon) {
leftPlayerTextField.setText("Mittel");
} else if (leftPlayerIcon.getIcon() == aiPlayerHardIcon) {
leftPlayerTextField.setText("Schwer");
}
// Für Rechten Spieler
if (rightPlayerIcon.getIcon() == aiPlayerEasyIcon){
rightPlayerTextField.setText("Einfach");
} else if (rightPlayerIcon.getIcon() == aiPlayerNormalIcon) {
rightPlayerTextField.setText("Mittel");
} else if (rightPlayerIcon.getIcon() == aiPlayerHardIcon) {
rightPlayerTextField.setText("Schwer");
}
}
}

View File

@ -0,0 +1,32 @@
import javax.swing.*;
import java.awt.*;
/**
* Das startLocalGameLoadingScreen Panel dient als "Überblende", während im Backend das Spiel erstellt wird.
* Hier wird lediglich Text angezeigt
* @author Joshua Kuklok
*/
public class startLocalGameLoadingScreen extends JPanel{
/**
* Konstruktor der startLocalGameLoadingScreen.
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @param semesterCounter Ein Zähler, der das gewählte Semester speichert (hier unbenutzt)
* @author Joshua Kuklok
*/
startLocalGameLoadingScreen(MainFrame frame, int semesterCounter) {
// Layout des Panels
setLayout(new BorderLayout());
// Label mit dem Text erstellen
JLabel loadingLabel = new JLabel("Spiel wird gestartet, bitte warten...");
loadingLabel.setHorizontalAlignment(SwingConstants.CENTER); // Horizontal zentrieren
loadingLabel.setVerticalAlignment(SwingConstants.CENTER); // Vertikal zentrieren
// Schriftgröße anpassen
loadingLabel.setFont(new Font("Roboto", Font.BOLD, 45));
// Label zum Panel hinzufügen
add(loadingLabel, BorderLayout.CENTER);
}
}

View File

@ -0,0 +1,244 @@
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
/**
* Das startMultiplayerGame Panel dient dem Erstellen eines Online Spiels.
* Hier kann der Benutzer Spieler inklusive Namen und das Semester, in dem sich der Benutzer befindet, einstellen.
* @author Joshua Kuklok
*/
public class startMultiplayerGame extends JPanel {
// Funktionshilfen
int semesterCounter = 1;
String PlayerNickname = "Spieler 1";
// Grafiken
ImageIcon backButtonIcon = new ImageIcon("graphics/backButton.png");
ImageIcon humanPlayerIcon = new ImageIcon("graphics/humanPlayer.png");
ImageIcon aiPlayerEasyIcon = new ImageIcon("graphics/botPlayerEasy.png");
ImageIcon aiPlayerNormalIcon = new ImageIcon("graphics/botPlayerNormal.png");
ImageIcon aiPlayerHardIcon = new ImageIcon("graphics/botPlayerHard.png");
// Labels
JLabel frameTitle = new JLabel("Multiplayer Spiel");
JLabel semesterLabel = new JLabel("Semester");
JLabel PlayerName = new JLabel("Name");
JLabel PlayerIcon = new JLabel(humanPlayerIcon);
JLabel semesterCounterLabel = new JLabel(String.valueOf(semesterCounter));
// Buttons
JButton backButton = new JButton(backButtonIcon);
JButton PlayerLeftButton = new JButton("<-");
JButton PlayerRightButton = new JButton("->");
JButton semesterUpButton = new JButton("^");
JButton semesterDownButton = new JButton("v");
JButton createGameButton = new JButton("Spiel erstellen");
JButton joinGameButton = new JButton("Spiel beitreten");
// Textfelder
JTextField PlayerTextField = new JTextField(20);
Font robotoFont = new Font("Roboto", Font.BOLD, 45);
/**
* Konstruktor der startLocalGame.
* Fügt Buttons, Textfelder und Label hinzu.
* Fügt ebenfalls ActionListeners hinzu, damit Buttons etc. ihre gewünschte Funktion haben
* @param frame Der Mainframe der Anwendung über den alle Panels angezeigt werden.
* @author Joshua Kuklok, Lucas Bronson
*/
startMultiplayerGame(MainFrame frame) {
// Layout des Panels
setLayout(null);
// Setze Komponentenpositionen
frameTitle.setBounds(20, 20, 500, 60);
frameTitle.setFont(robotoFont.deriveFont(50f));
add(frameTitle);
semesterLabel.setBounds(700, 300, 200, 30);
add(semesterLabel);
PlayerName.setBounds(50, 625, 200, 30);
add(PlayerName);
PlayerIcon.setBounds(75, 400, 200, 128);
add(PlayerIcon);
semesterCounterLabel.setBounds(705, 475, 50, 50); // zwischen den Up/Down-Buttons
semesterCounterLabel.setHorizontalAlignment(SwingConstants.CENTER);
add(semesterCounterLabel);
backButton.setBounds(1380, 20, 80, 80);
add(backButton);
PlayerLeftButton.setBounds(50, 450, 50, 50);
add(PlayerLeftButton);
PlayerRightButton.setBounds(250, 450, 50, 50);
add(PlayerRightButton);
semesterUpButton.setBounds(705, 400, 50, 50);
add(semesterUpButton);
semesterDownButton.setBounds(705, 550, 50, 50);
add(semesterDownButton);
joinGameButton.setBounds(1100, 350, 200, 50);
add(joinGameButton);
createGameButton.setBounds(1100, 550, 200, 50);
add(createGameButton);
PlayerTextField.setBounds(50, 650, 250, 50);
PlayerTextField.setText(PlayerNickname);
add(PlayerTextField);
// ActionListener für Buttons
// Um das Semester zu erhöhen.
semesterUpButton.addActionListener(e -> {
if (semesterCounter < 6) {
semesterCounter++;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
});
// Um das Semester zu senken.
semesterDownButton.addActionListener(e -> {
if (semesterCounter > 1) {
semesterCounter--;
semesterCounterLabel.setText(String.valueOf(semesterCounter));
}
});
// Um Player nach links zu "rotieren".
PlayerLeftButton.addActionListener(e -> {
togglePlayerIconLeft();
updateTextFields();
});
// Um Player nach rechts zu "rotieren".
PlayerRightButton.addActionListener(e -> {
togglePlayerIconRight();
updateTextFields();
});
// Um Namen des linken Spielers zu speichern.
PlayerTextField.addActionListener(e -> {
PlayerNickname = PlayerTextField.getText();
System.out.println("Linker Spielername geändert zu: " + PlayerNickname); // Debugging-Ausgabe
});
// Um Namen des linken Spielers zu speichern, auch wenn nicht Enter gedrückt wird.
PlayerTextField.addFocusListener(new java.awt.event.FocusAdapter() {
@Override
public void focusLost(java.awt.event.FocusEvent evt) {
PlayerNickname = PlayerTextField.getText();
System.out.println("Linker Spielername geändert zu: " + PlayerNickname); // Debugging-Ausgabe
}
});
// Um zum MainMenu zu wechseln.
backButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
frame.showPanel("MainMenu");
}
});
// Um zu JoinGame mit richtigen Parametern zu wechseln.
joinGameButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if (PlayerIcon.getIcon() == humanPlayerIcon) {
frame.showPanelSMG("JoinGame",1,0, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerEasyIcon) {
frame.showPanelSMG("JoinGame",1,1, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerNormalIcon) {
frame.showPanelSMG("JoinGame",1,2, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerHardIcon) {
frame.showPanelSMG("JoinGame",1,3, PlayerNickname, semesterCounter);
}
}
});
// Um zu JoinGame mit richtigen Parametern zu wechseln.
createGameButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
//Parameter -> panelName, Spiel erstellen oder beitreten (int), Spielertyp(int 0-3), Spielername
if (PlayerIcon.getIcon() == humanPlayerIcon) {
frame.showPanelSMG("JoinGame",0,0, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerEasyIcon) {
frame.showPanelSMG("JoinGame",0,1, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerNormalIcon) {
frame.showPanelSMG("JoinGame",0,2, PlayerNickname, semesterCounter);
} else if ( PlayerIcon.getIcon() == aiPlayerHardIcon) {
frame.showPanelSMG("JoinGame",0,3, PlayerNickname, semesterCounter);
}
}
});
}
// Hilfsfunktionen
/**
* Setzt das jeweils "nächste" Icon, wenn der PlayerLeftButton gedrückt wird.
* @author Joshua Kuklok
*/
private void togglePlayerIconLeft() {
if (PlayerIcon.getIcon() == humanPlayerIcon) {
PlayerIcon.setIcon(aiPlayerHardIcon);
} else if (PlayerIcon.getIcon() == aiPlayerEasyIcon){
PlayerIcon.setIcon(humanPlayerIcon);
} else if (PlayerIcon.getIcon() == aiPlayerNormalIcon) {
PlayerIcon.setIcon(aiPlayerEasyIcon);
} else if (PlayerIcon.getIcon() == aiPlayerHardIcon) {
PlayerIcon.setIcon(aiPlayerNormalIcon);
}
}
/**
* Setzt das jeweils "nächste" Icon, wenn der PlayerRightButton gedrückt wird.
* @author Joshua Kuklok
*/
private void togglePlayerIconRight() {
if (PlayerIcon.getIcon() == humanPlayerIcon) {
PlayerIcon.setIcon(aiPlayerEasyIcon);
} else if (PlayerIcon.getIcon() == aiPlayerEasyIcon){
PlayerIcon.setIcon(aiPlayerNormalIcon);
} else if (PlayerIcon.getIcon() == aiPlayerNormalIcon) {
PlayerIcon.setIcon(aiPlayerHardIcon);
} else if (PlayerIcon.getIcon() == aiPlayerHardIcon) {
PlayerIcon.setIcon(humanPlayerIcon);
}
}
/**
* Aktualisiert die Textfelder basierend auf den Icons
* @author Joshua Kuklok
*/
private void updateTextFields() {
if (PlayerIcon.getIcon() == humanPlayerIcon) {
PlayerTextField.setText(PlayerNickname);
} else if (PlayerIcon.getIcon() == aiPlayerEasyIcon){
PlayerTextField.setText("Einfach");
} else if (PlayerIcon.getIcon() == aiPlayerNormalIcon) {
PlayerTextField.setText("Mittel");
} else if (PlayerIcon.getIcon() == aiPlayerHardIcon) {
PlayerTextField.setText("Schwer");
}
}
}