diff --git a/Deliverables/.DS_Store b/Deliverables/.DS_Store deleted file mode 100644 index 14ea2def..00000000 Binary files a/Deliverables/.DS_Store and /dev/null differ diff --git a/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.png b/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.png new file mode 100644 index 00000000..5418fe9b Binary files /dev/null and b/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.png differ diff --git a/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.uml b/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.uml new file mode 100644 index 00000000..740cdfb6 --- /dev/null +++ b/Deliverables/Obligatorisk Oppgave3/ClassDiagramMandatroyAssignment3.uml @@ -0,0 +1,389 @@ + + + JAVA + inf112.skeleton.app + + inf112.skeleton.app.cards.ProgramCard + inf112.skeleton.app.screens.YouWinScreen + inf112.skeleton.app.objects.Laser + inf112.skeleton.app.RallyGame + inf112.skeleton.app.Main + inf112.skeleton.app.cards.Deck + inf112.skeleton.app.Player + inf112.skeleton.app.PlayerSorter + inf112.skeleton.app.enums.Direction + inf112.skeleton.app.BoardLayers + inf112.skeleton.app.screens.GameScreen + inf112.skeleton.app.screens.StandardScreen + inf112.skeleton.app.screens.MenuScreen + inf112.skeleton.app.Board + inf112.skeleton.app.GifDecoder + inf112.skeleton.app.objects.Flag + inf112.skeleton.app.screens.LoadingScreen + inf112.skeleton.app.enums.TileID + inf112.skeleton.app.enums.Rotate + inf112.skeleton.app.objects.RotatePad + inf112.skeleton.app.screens.GifScreen + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Production + private + + diff --git a/Deliverables/Obligatorisk Oppgave3/ObligatoriskOppgave3.md b/Deliverables/Obligatorisk Oppgave3/ObligatoriskOppgave3.md new file mode 100644 index 00000000..361de8b9 --- /dev/null +++ b/Deliverables/Obligatorisk Oppgave3/ObligatoriskOppgave3.md @@ -0,0 +1,290 @@ +# Mandatory Assignment 3 +Team: error_no_brain_found + +## Task 1 - Team and project +### Meeting minutes +[Møte 4](https://github.com/inf112-v20/error_brain_not_found/wiki/Møte-4.) +[Møte 5](https://github.com/inf112-v20/error_brain_not_found/wiki/Møte-5.) +[Møte 6](https://github.com/inf112-v20/error_brain_not_found/wiki/Møte-6) +[Møte 7](https://github.com/inf112-v20/error_brain_not_found/wiki/Møte-7) + +The meeting minutes ended up looking a bit lack of words. Since we was more busy with doing code, explaining code to each +other, and handout `Issues` to everyone, in the meeting. + +### Roles +The roles in the team work ok. The teamleader takes responsibility of tasks like how to perform meetings in this new +situation, takes initiatives for making meeting minutes and so on. The teamleader and customer contact +have been developing code, the tester has been making tests to this code. Also the UX designer has started to work on his tasks. +We do not want to change teamlead or contact. +For more depth information on the roles see [ObligatoriskOppgave2](https://github.com/inf112-v20/error_brain_not_found/blob/develop/Deliverables/Obligatorisk%20Oppgave2/ObligatoriskOppgave2.md), +under `Roles`. + +### Experiences with the team or project-methods +We are getting better at using issues, tags in issues and the projectboard. When a task needs to be done, +we make user stories, acceptance criteria's and tasks. This is copied into the issue, and the tasks are made as +check boxes so that we can see progress in the issue. Also an own issue for tests for this task is made and is tagging the issue +it should be testing, with acceptance criteria as tests to be made. This gives us a great overview of who is doing what, +and a great workflow because we can always see what to do next. + +### Do you think you have made good choices? If not, explain +In general yes, we think it was smart to device the team into roles like Developers, Tester etc, because then everyone know +what to do. On the other hand, these roles have some overlap, for example that maybe the tester sees something that needs to be fixed, can not +reach some code, or that the developer/UX-designer needs a specific test. We are then assigning issues to each other and specify the task needs +to be done, but sometimes this results in a lot of waiting for the person requesting these changing and the person needs to get this done before +doing anything else. We have discussed how this can be handled, and agreed on that small fixes can be done even though it is not +your area of responsibility. + +### Retrospective +Working in this iteration has been different. We have not been able to meet in person and all our communication has moved +online. This have come with its own pros and cons. It took some time for everyone to get used to the new situation, so the first +week after the "campus-ban" wasn't the most productive. When everyone got in to the new situation we started to make the +best of it. When people need help about something, they send someone in the team a message. And they often get the +answer faster now then what they did before. Meetings are going fine for now, but it will be harder as longer this ban +keeps on. I think the way we parted the roles and made us survived the transition in a good way. Every role has one main +responsibility area. When you have to move closer to someone else's area and you meet a wall we are fast to help each other +out. Also we have agreed on that if it is small changes/additions, this can be fixed even though it is not you area. + +We have have some work to do on planing what specific elements of the project need, so every member of the group have what +they need. In some cases the test require specific methods, that the tester often has to ask for. So if we start planing better +when we get the idea, we think this could delete that obstacle. + +The group is more proactive now and uses the `Project Board` more to see what needs to be done. When they are finished with their +task, and have some time leftover, they find something on the board like a `Bug` or something in the `Backlog`. They also communicate +this to the team, so everyone in the team have an idea of what is going on at the same time. So we feel the communication in +the team is getting better. + +#### Improvement points from retrospective +* Make concrete tasks for each user story. +* Fix small changes even though it is not you area. +* Follow up issues on project board. + +### Prioritization in the future +This iteration we have prioritized, and are done with: +* Holes: when a player is on hole it is respawned +* Lasers: making them work properly (get stopped by player and let player take damage) +* Damage: Let player take damage +* Game loop: When space is pressed the players use their programcards. +* Menu-screen: Choose different boards for the game +* Flags: Let the player pick up flags so it can win +* Rotatepad: rotate a player on a rotatepad + +We have prioritized to get each component of the game to work properly (walls, lasers), so that we can make +a working game loop with all the different parts working together. + +Next iteration we will focus on: +* Show cards: Let the player see the cards on the screen +* Belts: Make belts +* Game loop: Get a working game loop + +![Screenshot Project board](ScreenshotProjectBoard.png) + +### Group dynamic and communication +In general communication works fine, we communicate over slack and assign tasks to each other by making +issues and add them to project board. As mentioned before, because some overlapping of the different roles in the team, +it can be a bit challenging to wait for others to respond when you are working on something. Most of the team are communicating +great over slack and are doing tasks assigned to them, but we can not get a hold of one of the team-members. We assign issues with tasks and +follow up with message over slack, but experience very little to no feedback. + +## Task 2 - Requirements +### User stories: +#### Holes + +User story: +As a player I want to respawn if I end up on a hole, so that I can continue the game from backup. + +Acceptance-criteria: +* If I go on a tile where there is a hole I want to be respawned at my backup. + +Tasks: +* Make a method that tells if you are on a hole +* Test that you are respawned when on a hole + +#### Laser +User-story: +As a player I want the laser to be able to hit me, so that I take damage. + +Acceptance-criteria: +* If a laser is activated and player is standing in its shooting line, it gives player damage. +* If a laser is activated and player is not standing in its shooting line, it does not give player damage. + +Tasks: +* Make a method that tells if a laser is hitting a player +* Make a method that makes the player take damage +* Make tests for when laser is hitting player + +User-story: +As a player I want the laser not to hit me when it is blocked by objects on the board, so that I do not take damage. + +Acceptance-criteria: +If a laser is activated and player is standing in its shooting line but is blocked, then player does not get damage. + +Tasks: +* Make a method to tell if a laser is blocked, or make laser object know how far it can go by checking board. +* Test if the range of the specific laser is correct. +* Test that a player is not damaged when out of range of laser. + +#### Belts +User-story: +As player standing on a belt, I want to be moved as many steps as the belt is moving, so that I can get closer to my goal. + +Acceptance-criteria: +* If a player is standing on a belt and the belt is moving, then the player will move. +* If a player is on a belt, it moves as many steps as the belt does (express or regular) + +Tasks: +* Make a method to tell if you are on a belt. +* Let the belt know if it should move or not and how fast it should go +* Make a method to move any player on the belt + +User-story: +As a player standing on a belt, I want to be moved in the same direction the belt is moving, so that I can stay on the belt. + +Acceptance-criteria: +* If a player is standing on the corner and the belt is moving, then the player changes direction with the belt. + +Task: +* Make a method to tell if player is on the corner of the belt and what direction it +should have + +**NOT FINNISHED**, will be continued to next sprint. + +#### RotatePads +User-story: +As a user I want to get turned if I walk on a rotate pad + +Acceptance-criteria: +when I move to a tile with a rotate-wheel I want to be turned in the direction of the rotate pad + +Tasks: +* make a method that tells if player i on rotate pad and then rotate player +* test that player is rotated in correct direction + +#### MenuScreen +User-Story: +As a user of the game I want to be able to choose different board layouts, so that I can have a new challenge in the game. + +Acceptance-criteria: +If I choose a board-layout, this is the layout that shows when I start the game + +Tasks: +* Make methods for choosing board +* Make graphics for choosing board + +#### Life on robots +User-Story: +As a player I want my robot to be able to take damage, so that my robot can die + +Acceptance-criteria: +If a laser hits me, I want to recieve damage + +Tasks: +Make methods for robots to take damage + +#### Damagetoken +User-Story: +As a player I want my robot to have a Token-bar, to see when or if my robot gets hurt + +Acceptance-criteria: +* When i get 10 damage tokens, I want my robot to die and respawn +* When i get 5 or more damage tokens, then the program cards will 'lock up' starting from register 5 +* When i get x damage tokens, I will get x less program cards + +Tasks: +* Make a GUI for visible damage tokens for the robots +* Make methods to recieve damage tokens +* Make methods to recieve less programs cards based on damage tokens + +#### Lifetoken +User-Story: +As a player I want to have Life tokens, to see how many lives I have left + +Acceptance-criteria: +* If my robot gets 10 damage tokens, I lose a life token +* If my life tokens are depleted, then im permanently out of the game + +Tasks: +* Make a GUI to visualize life tokens +* Make a method that removes life tokens when robots die. +* Make a method that robots do not respawn after losing all life tokens + +#### See the cards +User-story: +As a player I want to be able to see the cards, so that I can plan my program. + +Acceptance-citeria: +* When I have drawn the cards, the cards are displayed in front of me on the screen. + +Tasks: +* Make graphics for showing cards +* Manual test + +This is not done, will continue on next sprint + +#### Flags +User-story: +As a user I want to go on flags, so that I can win the game. + +Acceptance-criteria: +* If I go on a flag, this flag is picked up. +* If I pick up all flags in correct order, I win. +* If I pick up flags in incorrect order, the flag is not picked up. + +Tasks: +* Create a function to tell i you can pick up a flag +* Create flags with flagnumber and position +* Check if all flags are picked up in correct order +* Make tests for flags + +#### Game loop +User-story: +As a player I want the game to go in a loop, so that events happen in a specific order. + +Acceptance-criteria: +When the game starts, it goes through the fases and the rounds. + +Tasks: +* Make loop for the game. +* Test that events happen in right order +* Manual tests + +A testing version is up, but this is going to be continued on next sprint. + +#### Main criteria for MVP +*[x] The game should be able to run, show a board with starting robot and programcards to this robot. +*[ ] The player is able to pick programcards and place them so that the robot can move. +*[ ] The game should be able to do a round, and do the phases in the correct order in that round. +*[x] The robot should be able to win by going to the flags in a specific order. +*[x] The robot is stopped by walls, pushed by other players and respawned when outside board/on hole. +*[ ] The robot should be able to do a powerdown. +*[x] The laser can shoot the robots and the robots take damage. +*[ ] The belts move so the player can be moved by belts. + +## Task 3 - Productdelivery and codequality +### Manual tests +The start-screen goes away after clicking on it. +* start the game then click somewhere on the screen. Then the menu-screen should come. + +Game loop: +* When the game has started press space once. +* Then all robots will use one programcard in turn, 5 times. (5 rounds) +* Press space again after all robots have moved and the robots will do five more rounds. + +Laser: +* Press on of the keyboard-arrows and the lasers will be activated. +* Stear your player in front of a laser. The laser should be stopped by a player. + +Menu-screen: +* Click on the start-menu (a picture). Then a screen with a roll-down menu and start and exit buttons should show. +* Choose your board by choosing from the roll-down menu then click start. The board should show with players on it. + +### Bugs +Game sometimes crashes after clicking on start menu + +### Comment to automatic build tests +Travis does not support the language `Java` on their Windows Build Environment. But 3/5 in our group run windows and it +runs on their computer. + +### Comment to classdiagram +The project is getting big so the diagram is no only the classes, if you want to se the content of the classes in the UML +there is possible to put it on in the `ClassDiagramMandatoryAssignment3.uml` in the `Deliverables/Obligatorisk Oppgave3` +folder. diff --git a/Deliverables/Obligatorisk Oppgave3/ScreenshotProjectBoard.png b/Deliverables/Obligatorisk Oppgave3/ScreenshotProjectBoard.png new file mode 100644 index 00000000..db84c099 Binary files /dev/null and b/Deliverables/Obligatorisk Oppgave3/ScreenshotProjectBoard.png differ diff --git a/README.md b/README.md index 7d3436b9..0a4bdda0 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,11 @@ Simple skeleton with libgdx. ## How to run -Clone the repo from github to you computer then: -Open the repo and go to `src/main/java/inf112/skeleton/app/Main.java` and run `main` function. +The program runs `java` and `maven`, these need to be installed. +Every text-editor that can run version control system, can be used. We recommend IntelliJ IDEA. +Clone the repo from github to you computer: `git clone https://github.com/inf112-v20/error_brain_not_found.git` +Then open `pom.xml` in IntelliJ and the IntelliJ will build the project for you. +Then open the repo and go to `src/main/java/inf112/skeleton/app/Main.java` and run `main` function. ## Known bugs Currently throws "WARNING: An illegal reflective access operation has occurred", diff --git a/assets/Dizzy_Dash.tmx b/assets/Dizzy_Dash.tmx deleted file mode 100644 index cc221fd8..00000000 --- a/assets/Dizzy_Dash.tmx +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - -5,50,5,131,5,5,5,5,5,5,5,5,5,5,5,5, -5,50,129,5,5,19,14,14,20,5,5,19,14,14,20,5, -33,44,5,5,5,13,5,54,21,53,5,13,15,54,21,5, -50,123,5,5,5,13,54,7,21,5,5,13,54,5,21,5, -50,5,5,5,5,27,22,22,28,5,53,27,22,22,28,5, -121,5,5,5,5,5,5,5,53,5,5,5,5,53,5,5, -122,5,5,5,5,5,53,5,5,5,5,53,5,5,5,5, -49,5,5,5,5,19,14,14,20,53,5,19,14,14,20,5, -49,124,5,5,5,13,5,54,21,5,5,13,7,54,21,5, -43,34,5,5,5,13,54,15,21,5,53,13,54,5,21,5, -5,49,130,5,5,27,22,22,28,5,5,27,22,22,28,5, -5,49,5,132,5,5,5,5,5,5,5,5,5,5,5,5 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,39,39,39,39,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,47,0,0,0,0,47,0,0,0, -0,0,0,0,0,0,0,47,0,0,0,0,47,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,39,39,39,39,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - - -0,0,0,0,0,0,31,0,31,0,0,31,0,31,0,0, -0,0,31,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,31,23,30,0,0,0,0,0,0,0,0,0,0,23, -0,0,0,0,0,0,0,0,0,38,0,0,0,30,0,0, -0,0,0,16,30,0,0,0,0,0,0,0,0,0,0,23, -0,0,0,0,0,0,0,31,0,0,0,0,31,0,0,0, -31,31,0,0,0,0,0,29,0,0,0,0,29,0,0,0, -0,0,0,8,30,0,0,0,0,0,0,0,0,0,0,23, -0,0,0,0,0,0,23,0,0,0,46,0,0,0,0,0, -0,0,29,23,30,0,0,0,0,0,0,0,0,0,0,23, -0,0,29,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,29,0,29,0,0,29,0,29,0,0 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,71,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,63,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - diff --git a/assets/Risky_Exchange.tmx b/assets/Risky_Exchange.tmx deleted file mode 100644 index a8bfa9a8..00000000 --- a/assets/Risky_Exchange.tmx +++ /dev/null @@ -1,85 +0,0 @@ - - - - - - -5,50,5,131,5,6,5,49,5,5,49,5,50,5,49,15, -5,50,129,5,5,5,5,49,5,50,49,5,50,5,5,5, -33,44,5,5,5,5,5,49,5,50,49,5,50,5,5,5, -50,123,5,5,52,52,52,53,5,50,49,5,53,52,52,52, -50,5,5,5,5,5,5,5,5,50,49,5,5,5,5,5, -121,5,5,5,22,22,22,22,22,5,5,51,51,51,51,51, -122,5,5,5,5,52,52,52,52,5,5,52,52,52,52,52, -49,5,5,5,5,5,5,5,7,21,49,5,5,5,5,5, -49,124,5,5,51,51,51,53,5,21,49,5,51,51,51,51, -43,34,5,5,5,5,5,49,5,21,49,5,21,5,5,5, -5,49,130,5,52,54,5,49,5,21,49,5,21,5,54,52, -5,49,5,132,15,50,5,49,5,21,49,5,21,5,49,5 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,47,0,0 - - - - -0,0,0,0,0,0,31,0,31,0,0,31,0,31,0,0, -0,0,31,0,0,30,0,0,0,0,0,0,0,0,0,0, -0,0,31,23,30,0,0,0,0,0,0,0,0,0,0,23, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,16,30,0,0,0,8,0,0,32,0,0,0,23, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -31,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,8,30,0,0,0,16,0,0,24,0,0,0,23, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,23,30,0,0,0,0,0,0,0,0,31,0,23, -0,0,31,0,0,0,23,0,0,0,0,0,0,0,0,0, -0,0,31,0,0,0,29,0,29,0,0,29,0,37,0,0 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,71,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - - -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, -0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 - - - diff --git a/assets/Sound/ImpactWall.mp3 b/assets/Sound/ImpactWall.mp3 new file mode 100644 index 00000000..5b92c1c2 Binary files /dev/null and b/assets/Sound/ImpactWall.mp3 differ diff --git a/assets/Sound/LaserShot.mp3 b/assets/Sound/LaserShot.mp3 new file mode 100644 index 00000000..179795c1 Binary files /dev/null and b/assets/Sound/LaserShot.mp3 differ diff --git a/assets/Sound/Repair.mp3 b/assets/Sound/Repair.mp3 new file mode 100644 index 00000000..91826746 Binary files /dev/null and b/assets/Sound/Repair.mp3 differ diff --git a/assets/Sound/WilhelmScream.mp3 b/assets/Sound/WilhelmScream.mp3 new file mode 100644 index 00000000..f3065a5f Binary files /dev/null and b/assets/Sound/WilhelmScream.mp3 differ diff --git a/assets/Sound/laser.mp3 b/assets/Sound/laser.mp3 new file mode 100644 index 00000000..06b4115f Binary files /dev/null and b/assets/Sound/laser.mp3 differ diff --git a/assets/Sound/menu_music.mp3 b/assets/Sound/menu_music.mp3 new file mode 100644 index 00000000..5f5eb3b9 Binary files /dev/null and b/assets/Sound/menu_music.mp3 differ diff --git a/assets/Sound/wall_Collision.mp3 b/assets/Sound/wall_Collision.mp3 new file mode 100644 index 00000000..b9f4a54a Binary files /dev/null and b/assets/Sound/wall_Collision.mp3 differ diff --git a/assets/images/Exit_Button_Active.png b/assets/images/Exit_Button_Active.png new file mode 100644 index 00000000..6252df80 Binary files /dev/null and b/assets/images/Exit_Button_Active.png differ diff --git a/assets/images/Exit_Button_Inactive.png b/assets/images/Exit_Button_Inactive.png new file mode 100644 index 00000000..41a71772 Binary files /dev/null and b/assets/images/Exit_Button_Inactive.png differ diff --git a/assets/images/GUI_Edited.jpg b/assets/images/GUI_Edited.jpg new file mode 100644 index 00000000..430a0c1b Binary files /dev/null and b/assets/images/GUI_Edited.jpg differ diff --git a/assets/RoboRallyMenuScreen.png b/assets/images/RoboRallyMenuScreen.png similarity index 100% rename from assets/RoboRallyMenuScreen.png rename to assets/images/RoboRallyMenuScreen.png diff --git a/assets/images/Start_Button.png b/assets/images/Start_Button.png new file mode 100644 index 00000000..290a1e58 Binary files /dev/null and b/assets/images/Start_Button.png differ diff --git a/assets/images/Start_Button_Active.png b/assets/images/Start_Button_Active.png new file mode 100644 index 00000000..d2148be7 Binary files /dev/null and b/assets/images/Start_Button_Active.png differ diff --git a/assets/images/YouWin.png b/assets/images/YouWin.png new file mode 100644 index 00000000..c2f7385c Binary files /dev/null and b/assets/images/YouWin.png differ diff --git a/assets/images/damageToken.png b/assets/images/damageToken.png new file mode 100644 index 00000000..d73d1dd4 Binary files /dev/null and b/assets/images/damageToken.png differ diff --git a/assets/images/lifeToken.png b/assets/images/lifeToken.png new file mode 100644 index 00000000..2d470216 Binary files /dev/null and b/assets/images/lifeToken.png differ diff --git a/assets/images/optimusBoi.gif b/assets/images/optimusBoi.gif new file mode 100644 index 00000000..66b0cf60 Binary files /dev/null and b/assets/images/optimusBoi.gif differ diff --git a/assets/maps/Dizzy_Dash.tmx b/assets/maps/Dizzy_Dash.tmx new file mode 100644 index 00000000..e9b1eff7 --- /dev/null +++ b/assets/maps/Dizzy_Dash.tmx @@ -0,0 +1,86 @@ + + + + + + + 5,50,5,131,5,5,5,5,5,5,5,5,5,5,5,5, + 5,50,129,5,5,19,14,14,20,5,5,19,14,14,20,5, + 33,44,5,5,5,13,5,54,21,53,5,13,15,54,21,5, + 50,123,5,5,5,13,54,7,21,5,5,13,54,5,21,5, + 50,5,5,5,5,27,22,22,28,5,53,27,22,22,28,5, + 121,5,5,5,5,5,5,5,53,5,5,5,5,53,5,5, + 122,5,5,5,5,5,53,5,5,5,5,53,5,5,5,5, + 49,5,5,5,5,19,14,14,20,53,5,19,14,14,20,5, + 49,124,5,5,5,13,5,54,21,5,5,13,7,54,21,5, + 43,34,5,5,5,13,54,15,21,5,53,13,54,5,21,5, + 5,49,130,5,5,27,22,22,28,5,5,27,22,22,28,5, + 5,49,5,132,5,5,5,5,5,5,5,5,5,5,5,5 + + + + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + 0,0,0,0,0,0,31,0,31,0,0,31,0,31,0,0, + 0,0,31,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,31,23,30,0,0,0,0,0,0,0,0,0,0,23, + 0,0,0,0,0,0,0,0,0,38,0,0,0,30,0,0, + 0,0,0,16,30,0,0,0,0,0,0,0,0,0,0,23, + 0,0,0,0,0,0,0,31,0,0,0,0,45,0,0,0, + 31,31,0,0,0,0,0,37,0,0,0,0,29,0,0,0, + 0,0,0,8,30,0,0,0,0,0,0,0,0,0,0,23, + 0,0,0,0,0,0,23,0,0,0,46,0,0,0,0,0, + 0,0,29,23,30,0,0,0,0,0,0,0,0,0,0,23, + 0,0,29,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,29,0,29,0,0,29,0,29,0,0 + + + + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,71,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,63,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/assets/Island_Hop.tmx b/assets/maps/Island_Hop.tmx similarity index 81% rename from assets/Island_Hop.tmx rename to assets/maps/Island_Hop.tmx index 3ad54a39..b9777a45 100644 --- a/assets/Island_Hop.tmx +++ b/assets/maps/Island_Hop.tmx @@ -1,17 +1,18 @@ - + - + -5,131,5,5,15,5,5,5,5,5,5,5,5,5,5,5, -5,129,5,5,5,105,109,5,5,5,5,5,5,117,107,5, -5,5,5,5,5,110,54,52,52,52,52,52,52,52,110,5, -5,123,5,5,5,5,49,53,51,51,60,51,53,50,5,5, -5,5,5,5,5,5,49,50,105,109,49,5,49,50,5,5, -5,121,5,5,5,5,49,50,110,7,49,5,49,50,5,5, -5,122,5,5,5,5,49,50,5,50,5,118,49,50,5,5, -5,5,5,5,5,5,49,50,5,50,117,115,49,50,5,5, + 5,131,5,5,15,5,5,5,5,5,5,5,5,5,5,5, + 5,129,5,5,5,105,109,5,5,5,5,5,5,117,107,5, + 5,5,5,5,5,110,54,52,52,52,52,52,52,52,110,5, + 5,123,5,5,5,5,49,53,51,51,60,51,53,50,5,5, + 5,5,5,5,5,5,49,50,105,109,49,5,49,50,5,5, + 5,121,5,5,5,5,49,50,110,7,49,5,49,50,5,5, + 5,122,5,5,5,5,49,50,5,50,5,118,49,50,5,5, + 5,5,5,5,5,5,49,50,5,50,117,115,49,50,5,5, 5,124,5,5,5,5,49,53,52,58,52,52,53,50,5,5, 5,5,5,5,5,118,54,51,51,51,51,51,51,50,118,5, 5,130,5,5,5,113,109,5,5,5,5,5,5,117,115,5, diff --git a/assets/maps/Risky_Exchange.tmx b/assets/maps/Risky_Exchange.tmx new file mode 100644 index 00000000..84620ae2 --- /dev/null +++ b/assets/maps/Risky_Exchange.tmx @@ -0,0 +1,86 @@ + + + + + + + 5,50,5,131,5,6,5,49,5,5,49,5,50,5,49,15, + 5,50,129,5,5,5,5,49,5,50,49,5,50,5,5,5, + 33,44,5,5,5,5,5,49,5,50,49,5,50,5,5,5, + 50,123,5,5,52,52,52,53,5,50,49,5,53,52,52,52, + 50,5,5,5,5,5,5,5,5,50,49,5,5,5,5,5, + 121,5,5,5,22,22,22,22,22,5,5,51,51,51,51,51, + 122,5,5,5,5,52,52,52,52,5,5,52,52,52,52,52, + 49,5,5,5,5,5,5,5,7,21,49,5,5,5,5,5, + 49,124,5,5,51,51,51,53,5,21,49,5,51,51,51,51, + 43,34,5,5,5,5,5,49,5,21,49,5,21,5,5,5, + 5,49,130,5,52,54,5,49,5,21,49,5,21,5,54,52, + 5,49,5,132,15,50,5,49,5,21,49,5,21,5,49,5 + + + + + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + 0,0,0,0,0,0,31,0,31,0,0,31,0,31,0,0, + 0,0,31,0,0,30,0,0,0,0,0,0,0,0,0,0, + 0,0,31,23,30,0,0,0,0,0,0,0,0,0,0,23, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, + 0,0,0,16,30,0,0,0,8,0,0,32,0,0,0,23, + 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +31,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,8,30,0,0,0,16,0,0,24,0,0,0,23, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,23,30,0,0,0,0,0,0,0,0,31,0,23, +0,0,31,0,0,0,23,0,0,0,0,0,0,0,0,0, +0,0,31,0,0,0,29,0,29,0,0,29,0,37,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,71,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,63,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + diff --git a/assets/maps/robots.png b/assets/maps/robots.png new file mode 100644 index 00000000..dc5d9547 Binary files /dev/null and b/assets/maps/robots.png differ diff --git a/assets/maps/robots.tsx b/assets/maps/robots.tsx new file mode 100644 index 00000000..c1e12459 --- /dev/null +++ b/assets/maps/robots.tsx @@ -0,0 +1,4 @@ + + + + diff --git a/assets/tiles.png b/assets/maps/tiles.png similarity index 100% rename from assets/tiles.png rename to assets/maps/tiles.png diff --git a/assets/tiles.tsx b/assets/maps/tiles.tsx similarity index 100% rename from assets/tiles.tsx rename to assets/maps/tiles.tsx diff --git a/assets/player.png b/assets/player.png deleted file mode 100644 index dc3b2739..00000000 Binary files a/assets/player.png and /dev/null differ diff --git a/assets/player.tsx b/assets/player.tsx deleted file mode 100644 index 97b07778..00000000 --- a/assets/player.tsx +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/assets/programCards/Again.png b/assets/programCards/Again.png new file mode 100644 index 00000000..32ab0ecb Binary files /dev/null and b/assets/programCards/Again.png differ diff --git a/assets/programCards/BackUp.png b/assets/programCards/BackUp.png new file mode 100644 index 00000000..2e288812 Binary files /dev/null and b/assets/programCards/BackUp.png differ diff --git a/assets/programCards/EnergyRoutine.png b/assets/programCards/EnergyRoutine.png new file mode 100644 index 00000000..ac292014 Binary files /dev/null and b/assets/programCards/EnergyRoutine.png differ diff --git a/assets/programCards/LeftTurn.png b/assets/programCards/LeftTurn.png new file mode 100644 index 00000000..35d2edea Binary files /dev/null and b/assets/programCards/LeftTurn.png differ diff --git a/assets/programCards/Move1.png b/assets/programCards/Move1.png new file mode 100644 index 00000000..e224d005 Binary files /dev/null and b/assets/programCards/Move1.png differ diff --git a/assets/programCards/Move2.png b/assets/programCards/Move2.png new file mode 100644 index 00000000..ec6ce680 Binary files /dev/null and b/assets/programCards/Move2.png differ diff --git a/assets/programCards/Move3.png b/assets/programCards/Move3.png new file mode 100644 index 00000000..c8a94b10 Binary files /dev/null and b/assets/programCards/Move3.png differ diff --git a/assets/programCards/RightTurn.png b/assets/programCards/RightTurn.png new file mode 100644 index 00000000..f56d74f8 Binary files /dev/null and b/assets/programCards/RightTurn.png differ diff --git a/assets/programCards/SpeedRoutine.png b/assets/programCards/SpeedRoutine.png new file mode 100644 index 00000000..4a91af47 Binary files /dev/null and b/assets/programCards/SpeedRoutine.png differ diff --git a/assets/programCards/U-Turn.png b/assets/programCards/U-Turn.png new file mode 100644 index 00000000..e5282744 Binary files /dev/null and b/assets/programCards/U-Turn.png differ diff --git a/assets/skins/default.fnt b/assets/skins/default.fnt new file mode 100644 index 00000000..37e58940 --- /dev/null +++ b/assets/skins/default.fnt @@ -0,0 +1,101 @@ +info face="Droid Sans" size=17 bold=0 italic=0 charset="" unicode=0 stretchH=100 smooth=1 aa=1 padding=0,0,0,0 spacing=1,1 +common lineHeight=20 base=18 scaleW=256 scaleH=128 pages=1 packed=0 +page id=0 file="default.png" +chars count=95 +char id=32 x=0 y=0 width=0 height=0 xoffset=0 yoffset=16 xadvance=4 page=0 chnl=0 +char id=124 x=0 y=0 width=6 height=20 xoffset=1 yoffset=3 xadvance=9 page=0 chnl=0 +char id=106 x=6 y=0 width=9 height=20 xoffset=-4 yoffset=3 xadvance=4 page=0 chnl=0 +char id=81 x=15 y=0 width=15 height=19 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 +char id=74 x=30 y=0 width=11 height=19 xoffset=-5 yoffset=3 xadvance=4 page=0 chnl=0 +char id=125 x=41 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 +char id=123 x=51 y=0 width=10 height=18 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 +char id=93 x=61 y=0 width=8 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 +char id=91 x=69 y=0 width=8 height=18 xoffset=-2 yoffset=3 xadvance=5 page=0 chnl=0 +char id=41 x=77 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 +char id=40 x=86 y=0 width=9 height=18 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 +char id=64 x=95 y=0 width=18 height=17 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0 +char id=121 x=113 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 +char id=113 x=126 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 +char id=112 x=139 y=0 width=13 height=17 xoffset=-2 yoffset=6 xadvance=9 page=0 chnl=0 +char id=103 x=152 y=0 width=13 height=17 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 +char id=38 x=165 y=0 width=16 height=16 xoffset=-3 yoffset=3 xadvance=11 page=0 chnl=0 +char id=37 x=181 y=0 width=18 height=16 xoffset=-3 yoffset=3 xadvance=14 page=0 chnl=0 +char id=36 x=199 y=0 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=63 x=211 y=0 width=11 height=16 xoffset=-3 yoffset=3 xadvance=7 page=0 chnl=0 +char id=33 x=222 y=0 width=7 height=16 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 +char id=48 x=229 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=57 x=242 y=0 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=56 x=0 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=54 x=13 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=53 x=26 y=20 width=12 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=51 x=38 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=100 x=51 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=98 x=64 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=85 x=77 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 +char id=83 x=91 y=20 width=13 height=16 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 +char id=79 x=104 y=20 width=15 height=16 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 +char id=71 x=119 y=20 width=14 height=16 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 +char id=67 x=133 y=20 width=13 height=16 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 +char id=127 x=146 y=20 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 +char id=35 x=158 y=20 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0 +char id=92 x=173 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 +char id=47 x=184 y=20 width=11 height=15 xoffset=-3 yoffset=3 xadvance=6 page=0 chnl=0 +char id=59 x=195 y=20 width=8 height=15 xoffset=-3 yoffset=6 xadvance=4 page=0 chnl=0 +char id=55 x=203 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=52 x=216 y=20 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=50 x=230 y=20 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=49 x=243 y=20 width=9 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=116 x=0 y=36 width=10 height=15 xoffset=-3 yoffset=4 xadvance=5 page=0 chnl=0 +char id=108 x=10 y=36 width=6 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 +char id=107 x=16 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 +char id=105 x=28 y=36 width=7 height=15 xoffset=-2 yoffset=3 xadvance=4 page=0 chnl=0 +char id=104 x=35 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 +char id=102 x=47 y=36 width=11 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 +char id=90 x=58 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=89 x=71 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 +char id=88 x=84 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=87 x=98 y=36 width=19 height=15 xoffset=-3 yoffset=3 xadvance=15 page=0 chnl=0 +char id=86 x=117 y=36 width=14 height=15 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=84 x=131 y=36 width=13 height=15 xoffset=-3 yoffset=3 xadvance=8 page=0 chnl=0 +char id=82 x=144 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 +char id=80 x=157 y=36 width=12 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=78 x=169 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=12 page=0 chnl=0 +char id=77 x=183 y=36 width=17 height=15 xoffset=-2 yoffset=3 xadvance=14 page=0 chnl=0 +char id=76 x=200 y=36 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 +char id=75 x=211 y=36 width=13 height=15 xoffset=-2 yoffset=3 xadvance=9 page=0 chnl=0 +char id=73 x=224 y=36 width=10 height=15 xoffset=-3 yoffset=3 xadvance=5 page=0 chnl=0 +char id=72 x=234 y=36 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 +char id=70 x=0 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 +char id=69 x=11 y=51 width=11 height=15 xoffset=-2 yoffset=3 xadvance=8 page=0 chnl=0 +char id=68 x=22 y=51 width=14 height=15 xoffset=-2 yoffset=3 xadvance=11 page=0 chnl=0 +char id=66 x=36 y=51 width=13 height=15 xoffset=-2 yoffset=3 xadvance=10 page=0 chnl=0 +char id=65 x=49 y=51 width=15 height=15 xoffset=-3 yoffset=3 xadvance=10 page=0 chnl=0 +char id=58 x=64 y=51 width=7 height=13 xoffset=-2 yoffset=6 xadvance=4 page=0 chnl=0 +char id=117 x=71 y=51 width=12 height=13 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0 +char id=115 x=83 y=51 width=11 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 +char id=111 x=94 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 +char id=101 x=107 y=51 width=13 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 +char id=99 x=120 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 +char id=97 x=132 y=51 width=12 height=13 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 +char id=60 x=144 y=51 width=13 height=12 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0 +char id=122 x=157 y=51 width=11 height=12 xoffset=-3 yoffset=6 xadvance=7 page=0 chnl=0 +char id=120 x=168 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 +char id=119 x=181 y=51 width=17 height=12 xoffset=-3 yoffset=6 xadvance=12 page=0 chnl=0 +char id=118 x=198 y=51 width=13 height=12 xoffset=-3 yoffset=6 xadvance=8 page=0 chnl=0 +char id=114 x=211 y=51 width=10 height=12 xoffset=-2 yoffset=6 xadvance=6 page=0 chnl=0 +char id=110 x=221 y=51 width=12 height=12 xoffset=-2 yoffset=6 xadvance=10 page=0 chnl=0 +char id=109 x=233 y=51 width=17 height=12 xoffset=-2 yoffset=6 xadvance=15 page=0 chnl=0 +char id=94 x=0 y=66 width=13 height=11 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=62 x=13 y=66 width=13 height=11 xoffset=-3 yoffset=5 xadvance=9 page=0 chnl=0 +char id=42 x=26 y=66 width=13 height=10 xoffset=-3 yoffset=3 xadvance=9 page=0 chnl=0 +char id=43 x=39 y=66 width=13 height=10 xoffset=-3 yoffset=6 xadvance=9 page=0 chnl=0 +char id=61 x=52 y=66 width=13 height=8 xoffset=-3 yoffset=7 xadvance=9 page=0 chnl=0 +char id=39 x=65 y=66 width=6 height=8 xoffset=-2 yoffset=3 xadvance=3 page=0 chnl=0 +char id=34 x=71 y=66 width=9 height=8 xoffset=-2 yoffset=3 xadvance=6 page=0 chnl=0 +char id=44 x=80 y=66 width=8 height=7 xoffset=-3 yoffset=14 xadvance=4 page=0 chnl=0 +char id=126 x=88 y=66 width=13 height=6 xoffset=-3 yoffset=8 xadvance=9 page=0 chnl=0 +char id=46 x=101 y=66 width=7 height=6 xoffset=-2 yoffset=13 xadvance=4 page=0 chnl=0 +char id=96 x=108 y=66 width=8 height=6 xoffset=0 yoffset=2 xadvance=9 page=0 chnl=0 +char id=45 x=116 y=66 width=9 height=5 xoffset=-3 yoffset=10 xadvance=5 page=0 chnl=0 +char id=95 x=125 y=66 width=13 height=4 xoffset=-4 yoffset=17 xadvance=6 page=0 chnl=0 +kernings count=-1 diff --git a/assets/skins/default.png b/assets/skins/default.png new file mode 100644 index 00000000..ca368e07 Binary files /dev/null and b/assets/skins/default.png differ diff --git a/assets/skins/default_00.png b/assets/skins/default_00.png new file mode 100644 index 00000000..94ce570f Binary files /dev/null and b/assets/skins/default_00.png differ diff --git a/assets/skins/uiskin.atlas b/assets/skins/uiskin.atlas new file mode 100644 index 00000000..c1935816 --- /dev/null +++ b/assets/skins/uiskin.atlas @@ -0,0 +1,198 @@ + +uiskin.png +format: RGBA8888 +filter: Nearest,Nearest +repeat: none +default + rotate: false + xy: 1, 50 + size: 254, 77 + orig: 254, 77 + offset: 0, 0 + index: -1 +default-window + rotate: false + xy: 1, 20 + size: 27, 29 + split: 4, 3, 20, 3 + orig: 27, 29 + offset: 0, 0 + index: -1 +default-select + rotate: false + xy: 29, 29 + size: 27, 20 + split: 4, 14, 4, 4 + orig: 27, 20 + offset: 0, 0 + index: -1 +default-round-large + rotate: false + xy: 57, 29 + size: 20, 20 + split: 5, 5, 5, 4 + orig: 20, 20 + offset: 0, 0 + index: -1 +default-scroll + rotate: false + xy: 78, 29 + size: 20, 20 + split: 2, 2, 2, 2 + orig: 20, 20 + offset: 0, 0 + index: -1 +default-slider-knob + rotate: false + xy: 1, 1 + size: 9, 18 + orig: 9, 18 + offset: 0, 0 + index: -1 +default-round-down + rotate: false + xy: 99, 29 + size: 12, 20 + split: 5, 5, 5, 4 + orig: 12, 20 + offset: 0, 0 + index: -1 +default-round + rotate: false + xy: 112, 29 + size: 12, 20 + split: 5, 5, 5, 4 + pad: 4, 4, 1, 1 + orig: 12, 20 + offset: 0, 0 + index: -1 +check-off + rotate: false + xy: 11, 5 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +textfield + rotate: false + xy: 11, 5 + size: 14, 14 + split: 3, 3, 3, 3 + orig: 14, 14 + offset: 0, 0 + index: -1 +check-on + rotate: false + xy: 125, 35 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +tree-minus + rotate: false + xy: 140, 35 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +tree-plus + rotate: false + xy: 155, 35 + size: 14, 14 + orig: 14, 14 + offset: 0, 0 + index: -1 +default-slider + rotate: false + xy: 29, 20 + size: 8, 8 + split: 2, 2, 2, 2 + orig: 8, 8 + offset: 0, 0 + index: -1 +default-pane + rotate: false + xy: 11, 1 + size: 5, 3 + split: 1, 1, 1, 1 + orig: 5, 3 + offset: 0, 0 + index: -1 +default-rect-pad + rotate: false + xy: 11, 1 + size: 5, 3 + split: 1, 1, 1, 1 + orig: 5, 3 + offset: 0, 0 + index: -1 +default-splitpane + rotate: false + xy: 17, 1 + size: 5, 3 + split: 0, 5, 0, 0 + orig: 5, 3 + offset: 0, 0 + index: -1 +cursor + rotate: false + xy: 23, 1 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-splitpane-vertical + rotate: false + xy: 125, 29 + size: 3, 5 + split: 0, 0, 0, 5 + orig: 3, 5 + offset: 0, 0 + index: -1 +default-rect-down + rotate: false + xy: 170, 46 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-rect + rotate: false + xy: 38, 25 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-select-selection + rotate: false + xy: 26, 16 + size: 3, 3 + split: 1, 1, 1, 1 + orig: 3, 3 + offset: 0, 0 + index: -1 +default-pane-noborder + rotate: false + xy: 129, 33 + size: 1, 1 + split: 0, 0, 0, 0 + orig: 1, 1 + offset: 0, 0 + index: -1 +selection + rotate: false + xy: 170, 44 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 +white + rotate: false + xy: 174, 48 + size: 1, 1 + orig: 1, 1 + offset: 0, 0 + index: -1 diff --git a/assets/skins/uiskin.json b/assets/skins/uiskin.json new file mode 100644 index 00000000..e4d24292 --- /dev/null +++ b/assets/skins/uiskin.json @@ -0,0 +1,58 @@ +{ + "com.badlogic.gdx.graphics.g2d.BitmapFont": { "default-font": { "file": "default.fnt" } }, + "com.badlogic.gdx.graphics.Color": { + "green": { "a": 1, "b": 0, "g": 1, "r": 0 }, + "white": { "a": 1, "b": 1, "g": 1, "r": 1 }, + "red": { "a": 1, "b": 0, "g": 0, "r": 1 }, + "black": { "a": 1, "b": 0, "g": 0, "r": 0 } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Skin$TintedDrawable": { + "dialogDim": { "name": "white", "color": { "r": 0, "g": 0, "b": 0, "a": 0.45 } } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Button$ButtonStyle": { + "default": { "down": "default-round-down", "up": "default-round" }, + "toggle": { "down": "default-round-down", "checked": "default-round-down", "up": "default-round" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.TextButton$TextButtonStyle": { + "default": { "down": "default-round-down", "up": "default-round", "font": "default-font", "fontColor": "white" }, + "toggle": { "down": "default-round-down", "up": "default-round", "checked": "default-round-down", "font": "default-font", "fontColor": "white", "downFontColor": "red" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.SelectBox$SelectBoxStyle": { + "default": { + "scrollStyle": { "background": "default-rect" }, + "listStyle": { "font": "default-font", "selection": "default-select-selection" }, + "font": "default-font", "fontColor": "white", "background": "default-select" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.SplitPane$SplitPaneStyle": { + "default-vertical": { "handle": "default-splitpane-vertical" }, + "default-horizontal": { "handle": "default-splitpane" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.ScrollPane$ScrollPaneStyle": { + "default": { "vScroll": "default-scroll", "hScrollKnob": "default-round-large", "background": "default-rect", "hScroll": "default-scroll", "vScrollKnob": "default-round-large" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Window$WindowStyle": { + "default": { "titleFont": "default-font", "background": "default-window", "titleFontColor": "white" }, + "dialog": { "titleFont": "default-font", "background": "default-window", "titleFontColor": "white", "stageBackground": "dialogDim" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Slider$SliderStyle": { + "default-horizontal": { "background": "default-slider", "knob": "default-slider-knob" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Label$LabelStyle": { + "default": { "font": "default-font", "fontColor": "white" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.TextField$TextFieldStyle": { + "default": { "selection": "selection", "background": "textfield", "font": "default-font", "fontColor": "white", "cursor": "cursor" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.CheckBox$CheckBoxStyle": { + "default": { "checkboxOn": "check-on", "checkboxOff": "check-off", "font": "default-font", "fontColor": "white" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.List$ListStyle": { + "default": { "fontColorUnselected": "white", "selection": "default-rect-pad", "fontColorSelected": "white", "font": "default-font" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Touchpad$TouchpadStyle": { + "default": { "background": "default-pane", "knob": "default-round-large" } + }, + "com.badlogic.gdx.scenes.scene2d.ui.Tree$TreeStyle": { + "default": { "minus": "tree-minus", "plus": "tree-plus", "selection": "default-select-selection" } + } +} diff --git a/assets/skins/uiskin.png b/assets/skins/uiskin.png new file mode 100644 index 00000000..da012c5e Binary files /dev/null and b/assets/skins/uiskin.png differ diff --git a/assets/testMap.tmx b/assets/testMap.tmx deleted file mode 100644 index 1a00dda2..00000000 --- a/assets/testMap.tmx +++ /dev/null @@ -1,50 +0,0 @@ - - - - - - -5,5,5,5,5, -19,5,5,5,18, -13,5,6,5,13, -13,5,5,5,13, -121,5,5,5,122 - - - - -0,0,47,0,0, -0,0,47,0,0, -0,0,47,0,0, -0,0,47,0,0, -0,0,47,0,0 - - - - -0,0,31,0,0, -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0, -0,0,37,0,0 - - - - -55,0,71,0,63, -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0 - - - - -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0, -0,0,0,0,0 - - - diff --git a/pom.xml b/pom.xml index b841e501..e36f4c65 100644 --- a/pom.xml +++ b/pom.xml @@ -8,14 +8,14 @@ mvn-app 1.0-SNAPSHOT - mvn-app + RoboRally - http://www.example.com + https://github.com/inf112-v20/error_brain_not_found UTF-8 - 1.7 - 1.7 + 1.8 + 1.8 @@ -107,5 +107,16 @@ + + + + org.apache.maven.plugins + maven-compiler-plugin + + 8 + 8 + + + diff --git a/src/main/java/inf112/skeleton/app/Board.java b/src/main/java/inf112/skeleton/app/Board.java index c1e40330..c4adf502 100644 --- a/src/main/java/inf112/skeleton/app/Board.java +++ b/src/main/java/inf112/skeleton/app/Board.java @@ -1,6 +1,9 @@ package inf112.skeleton.app; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.audio.Sound; import com.badlogic.gdx.maps.tiled.TiledMap; +import com.badlogic.gdx.maps.tiled.TiledMapTile; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.maps.tiled.TiledMapTileSet; import com.badlogic.gdx.math.Vector2; @@ -9,241 +12,560 @@ import inf112.skeleton.app.objects.Flag; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; public class Board extends BoardLayers { - private final ArrayList flags; - private ArrayList players; + private final ArrayList players; - public Board() { - this("assets/testMap.tmx"); - } + private final Sound scream = Gdx.audio.newSound(Gdx.files.internal("assets/Sound/WilhelmScream.mp3")); + private final Sound wallImpact = Gdx.audio.newSound(Gdx.files.internal("assets/Sound/ImpactWall.mp3")); - public Board(String mapPath) { + public Board(String mapPath, int numberOfPlayers) { super(mapPath); this.players = new ArrayList<>(); - this.flags = new ArrayList<>(); - findFlags(); - addPlayersToStartPositions(2); + + addPlayersToStartPositions(numberOfPlayers); + } + + private TiledMapTile getRobotTile(Player player) { + TiledMapTileSet tileSet = this.tiledMap.getTileSets().getTileSet("robots"); + switch (player.getDirection()) { + case SOUTH: + return tileSet.getTile(TileID.PLAYER_SOUTH.getId()); + case NORTH: + return tileSet.getTile(TileID.PLAYER_NORTH.getId()); + case EAST: + return tileSet.getTile(TileID.PLAYER_EAST.getId()); + case WEST: + return tileSet.getTile(TileID.PLAYER_WEST.getId()); + default: + return null; + } + } + + /** + * @param number number of player + * @return true if player number is valid + */ + public boolean validPlayerNumber(int number) { + for (Player player : players) { + if (number == player.getPlayerNr()) { + return false; + } + } + return 0 < number && number < 9; } /** - * Finds the where the flags are on the board and makes {@link Flag} objects. - * And puts them in to the flag array. + * Make new player and add player to game and board + * + * @param x coordinate + * @param y coordinate + * @param playerNumber of player + */ + public void addPlayer(int x, int y, int playerNumber) { + if (!validPlayerNumber(playerNumber)) { + return; + } + Player player = new Player(new Vector2(x, y), playerNumber); + addPlayer(player); + } + + /** + * Add a player to the player layer in coordinate (x, y) and + * add that player to the list of players + * + * @param player to add to game and board */ - public void findFlags() { + public void addPlayer(Player player) { + TiledMapTileLayer.Cell cell = new TiledMapTileLayer.Cell(); + cell.setTile(getRobotTile(player)); + playerLayer.setCell((int) player.getPosition().x, (int) player.getPosition().y, cell); + if (!players.contains(player)) { + players.add(player); + } + } + + public Vector2 getStartPosition(int number) { for (int x = 0; x < groundLayer.getWidth(); x++) { for (int y = 0; y < groundLayer.getHeight(); y++) { - TiledMapTileLayer.Cell cell = flagLayer.getCell(x, y); - if (cell != null) { - int ID = cell.getTile().getId(); - if (ID == 55) { - flags.add(new Flag(1, x, y)); - } else if (ID == 63) { - flags.add(new Flag(2, x, y)); - } else if (ID == 71) { - flags.add(new Flag(3, x, y)); - } + TiledMapTileLayer.Cell cell = groundLayer.getCell(x, y); + int ID = cell.getTile().getId(); + if (number == 1 && ID == TileID.START_POS1.getId()) { + return new Vector2(x, y); + } else if (number == 2 && ID == TileID.START_POS2.getId()) { + return new Vector2(x, y); + } else if (number == 3 && ID == TileID.START_POS3.getId()) { + return new Vector2(x, y); + } else if (number == 4 && ID == TileID.START_POS4.getId()) { + return new Vector2(x, y); + } else if (number == 5 && ID == TileID.START_POS5.getId()) { + return new Vector2(x, y); + } else if (number == 6 && ID == TileID.START_POS6.getId()) { + return new Vector2(x, y); + } else if (number == 7 && ID == TileID.START_POS7.getId()) { + return new Vector2(x, y); + } else if (number == 8 && ID == TileID.START_POS8.getId()) { + return new Vector2(x, y); } } } + return null; } /** - * Check all cells on map for start positions got by {@link TileID} and add a new player to that + * Check all cells on map for start positions with {@link TileID} and add a new player to that * position based on number of players * * @param numPlayers number of robots playing, between 1-8 */ public void addPlayersToStartPositions(int numPlayers) { - for (int x = 0; x < groundLayer.getWidth(); x++) { - for (int y = 0; y < groundLayer.getHeight(); y++) { - TiledMapTileLayer.Cell cell = groundLayer.getCell(x, y); - int ID = cell.getTile().getId(); - if (ID == TileID.STARTPOS1.getId()) { - addPlayer(x, y, 1); - } else if (ID == TileID.STARTPOS2.getId() && numPlayers > 1) { - addPlayer(x, y, 2); - } else if (ID == TileID.STARTPOS3.getId() && numPlayers > 2) { - addPlayer(x, y, 3); - } else if (ID == TileID.STARTPOS4.getId() && numPlayers > 3) { - addPlayer(x, y, 4); - } else if (ID == TileID.STARTPOS5.getId() && numPlayers > 4) { - addPlayer(x, y, 5); - } else if (ID == TileID.STARTPOS6.getId() && numPlayers > 5) { - addPlayer(x, y, 6); - } else if (ID == TileID.STARTPOS7.getId() && numPlayers > 6) { - addPlayer(x, y, 7); - } else if (ID == TileID.STARTPOS8.getId() && numPlayers > 7) { - addPlayer(x, y, 8); - } + if (numPlayers == 0) { + return; + } + for (int playerNr = 1; playerNr <= numPlayers; playerNr++) { + Vector2 position = getStartPosition(playerNr); + addPlayer((int) position.x, (int) position.y, playerNr); + } + } + + /** + * Add laser in position in the right direction + * + * @param position to add laser + * @param direction of laser + */ + public void addLaser(Vector2 position, Direction direction) { + TiledMapTileLayer.Cell cell = laserLayer.getCell((int) position.x, (int) position.y); + TiledMapTileSet tileSet = tiledMap.getTileSets().getTileSet("tiles"); + if (cell == null) { + cell = new TiledMapTileLayer.Cell(); + } + if (direction == Direction.NORTH || direction == Direction.SOUTH) { + if (cell.getTile() == null) { + cell.setTile(tileSet.getTile(TileID.VERTICAL_LASER.getId())); + } else if (cell.getTile().getId() == TileID.HORIZONTAL_LASER.getId()) { + cell.setTile(tileSet.getTile(TileID.CROSSED_LASER.getId())); + } + } else { + if (cell.getTile() == null) { + cell.setTile(tileSet.getTile(TileID.HORIZONTAL_LASER.getId())); + } else if (cell.getTile().getId() == TileID.VERTICAL_LASER.getId()) { + cell.setTile(tileSet.getTile(TileID.CROSSED_LASER.getId())); + } + } + laserLayer.setCell((int) position.x, (int) position.y, cell); + } + + /** + * Checks if player moves on to a hole + * + * @param position that is checked + * @return true if the position contains a hole + */ + public boolean hasHole(Vector2 position) { + for (Vector2 vector : holes) { + if (vector.equals(position)) { + scream.play(); + return true; } } + return false; } + /** + * Check if player is outside of board + * + * @param player to check + */ + public boolean outsideBoard(Player player) { + return player.getPosition().x < 0 || + player.getPosition().x >= this.boardWidth || + player.getPosition().y < 0 || + player.getPosition().y >= this.boardHeight || + hasHole(player.getPosition()); + } /** - * Add a player to the player layer in coordinate (x, y) and - * add that player to the list of players + * Places a player in backup position or alternative position * - * @param x coordinate - * @param y coordinate + * @param player to respawn */ - public void addPlayer(int x, int y, int playerNumber) { - TiledMapTileLayer.Cell cell = new TiledMapTileLayer.Cell(); - TiledMapTileSet tileSet = tiledMap.getTileSets().getTileSet("player"); - cell.setTile(tileSet.getTile(137)); - playerLayer.setCell(x, y, cell); - Player player = new Player(new Vector2(x, y), playerNumber); - players.add(player); + public void respawn(Player player) { + removePlayerFromBoard(player); + if (hasPlayer(player.getBackupPosition())) { + player.chooseAlternativeBackupPosition(this, player.getBackupPosition()); + player.setPosition(new Vector2(player.getAlternativeBackupPosition().x, player.getAlternativeBackupPosition().y)); + player.setDirection(player.getAlternativeBackupDirection()); + } else { + player.setPosition(new Vector2(player.getBackupPosition().x, player.getBackupPosition().y)); + player.setDirection(player.getBackupDirection()); + } + addPlayer(player); + } + + public void respawnPlayers() { + for (Player player : players) { + if (outsideBoard(player)) { + player.decrementLifeTokens(); + respawn(player); + } + } + } + + public boolean validRespawnPosition(Vector2 position, Direction direction) { + Vector2 currPos = position; + for (int step = 0; step < 3; step++) { + if (hasPlayer(currPos)) { + return false; + } + currPos = getNeighbourPosition(currPos, direction); + } + return !hasHole(position); + } + + public List getDirectionRandomOrder() { + List directions = Arrays.asList(Direction.values()); + Collections.shuffle(directions); + return directions; } + /** + * @return player that should be moved with arrows + */ public Player getPlayer1() { for (Player player : players) { if (player.getPlayerNr() == 1) { return player; } } - return players.get(0); + return null; } - public boolean canGo(Player player) { - Vector2 position = player.getPosition(); - Direction direction = player.getDirection(); + /** + * @param position to go from + * @param direction to go in + * @return true if there is no wall blocking the way + */ + public boolean canGo(Vector2 position, Direction direction) { + TiledMapTileLayer.Cell cell = wallLayer.getCell((int) position.x, (int) position.y); + TiledMapTileLayer.Cell northCell = wallLayer.getCell((int) position.x, (int) position.y + 1); + TiledMapTileLayer.Cell southCell = wallLayer.getCell((int) position.x, (int) position.y - 1); + TiledMapTileLayer.Cell eastCell = wallLayer.getCell((int) position.x + 1, (int) position.y); + TiledMapTileLayer.Cell westCell = wallLayer.getCell((int) position.x - 1, (int) position.y); + + switch (direction) { + case NORTH: + if (hasNorthWall(cell) || hasSouthWall(northCell)) { + return false; + } + break; + case SOUTH: + if (hasSouthWall(cell) || hasNorthWall(southCell)) { + return false; + } + break; + case EAST: + if (hasEastWall(cell) || hasWestWall(eastCell)) { + return false; + } + break; + case WEST: + if (hasWestWall(cell) || hasEastWall(westCell)) { + return false; + } + break; + default: + break; + } + return true; + } + + /** + * @param cell to check for wall + * @return true if cell has a wall on west side + */ + public boolean hasWestWall(TiledMapTileLayer.Cell cell) { + if (cell != null) { + int tileID = cell.getTile().getId(); + return tileID == TileID.WEST_WALL.getId() || + tileID == TileID.NORTHWEST_WALL.getId() || + tileID == TileID.SOUTHWEST_WALL.getId() || + tileID == TileID.WEST_LASER_WALL.getId(); + } + return false; + } + + /** + * @param cell to check for wall + * @return true if cell has a wall on east side + */ + public boolean hasEastWall(TiledMapTileLayer.Cell cell) { + if (cell != null) { + int tileID = cell.getTile().getId(); + return tileID == TileID.EAST_WALL.getId() || + tileID == TileID.NORTHEAST_WALL.getId() || + tileID == TileID.SOUTHEAST_WALL.getId() || + tileID == TileID.EAST_LASER_WALL.getId(); + } + return false; + } + + /** + * @param cell to check for wall + * @return true if cell has a wall on south side + */ + public boolean hasSouthWall(TiledMapTileLayer.Cell cell) { + if (cell != null) { + int tileID = cell.getTile().getId(); + return tileID == TileID.SOUTH_WALL.getId() || + tileID == TileID.SOUTHWEST_WALL.getId() || + tileID == TileID.SOUTHEAST_WALL.getId() || + tileID == TileID.SOUTH_LASER_WALL.getId(); + } + return false; + } - shouldPush(position, direction); - if (direction == Direction.EAST) { - return position.x < boardWidth - 1; - } else if (direction == Direction.WEST) { - return position.x > 0; - } else if (direction == Direction.NORTH) { - return position.y < boardHeight - 1; - } else if (direction == Direction.SOUTH) { - return position.y > 0; + /** + * @param cell to check for wall + * @return true if cell has a wall on north side + */ + public boolean hasNorthWall(TiledMapTileLayer.Cell cell) { + if (cell != null) { + int tileID = cell.getTile().getId(); + return tileID == TileID.NORTH_WALL.getId() || + tileID == TileID.NORTHWEST_WALL.getId() || + tileID == TileID.NORTHEAST_WALL.getId() || + tileID == TileID.NORTH_LASER_WALL.getId(); } return false; } + /** - * Moves the player from current position one tile in the direction it's facing. - * Removes the cell its currently on and moves the content of that cell to the cell it moves to. - * Also updates the fields in player + * Add player to the board, so the direction is correct + * @param player that should be rotated + * + */ + public void rotatePlayer(Player player) { + addPlayer(player); + } + + /** + * Check if it is possible to move in the direction the player are facing. + * Check if player should and can push another player, if not return + * Remove player from board + * Update player position according to direction + * Add player to cell that corresponds to player position * * @param player that is suppose to move */ public void movePlayer(Player player) { - Vector2 playerPosition = player.getPosition(); - Direction playerDirection = player.getDirection(); + Vector2 position = player.getPosition(); + Direction direction = player.getDirection(); - shouldPush(playerPosition, playerDirection); - switch (playerDirection) { + if (!canGo(position, direction)) { + wallImpact.play(0.6f); + addPlayer(player); + return; + } + if (shouldPush(player)) { + Player enemyPlayer = getPlayer(getNeighbourPosition(player.getPosition(), direction)); + if (canPush(enemyPlayer, direction)) { + pushPlayer(enemyPlayer, direction); + } else { + addPlayer(player); + return; + } + } + + removePlayerFromBoard(player); + + switch (direction) { case NORTH: - playerPosition.set(playerPosition.x, playerPosition.y + 1); + position.y++; break; case EAST: - playerPosition.set(playerPosition.x + 1, playerPosition.y); + position.x++; break; case WEST: - playerPosition.set(playerPosition.x - 1, playerPosition.y); + position.x--; break; case SOUTH: - playerPosition.set(playerPosition.x, playerPosition.y - 1); + position.y--; break; default: - return; + break; + } + + player.setPosition(position); + addPlayer(player); + + if (hasFlag(player.getPosition())) { + pickUpFlag(player); } - player.setPosition(playerPosition); - updatePlayers(); + } + + public ArrayList getNeighbourhood(Vector2 position) { + ArrayList positions = new ArrayList<>(); + for (int yi = -1; yi <= 1; yi++) { + for (int xi = -1; xi <= 1; xi++) { + int x = (int) (position.x + xi); + int y = (int) (position.y + yi); + if (x >= 0 && x < boardWidth && y >= 0 && y < boardHeight) { + positions.add(new Vector2(x, y)); + } + } + } + return positions; } /** - * If player moved outside board, respawn them on last backup location - * @param player current player + * @param position to go from + * @param direction to go in + * @return neighbour position in direction from position */ - private void outsideBoard(Player player) { - if (player.getPosition().x < 0 || player.getPosition().x > 15 || player.getPosition().y < 0 || player.getPosition().y > 11) { - player.setPosition(new Vector2(player.getBackupPosition().x, player.getBackupPosition().y)); + public Vector2 getNeighbourPosition(Vector2 position, Direction direction) { + Vector2 neighbourPosition = new Vector2(position); + switch (direction) { + case EAST: + neighbourPosition.x++; + break; + case WEST: + neighbourPosition.x--; + break; + case NORTH: + neighbourPosition.y++; + break; + case SOUTH: + neighbourPosition.y--; + break; + default: + break; } + return neighbourPosition; + } + + public boolean hasPlayer(Vector2 position) { + for (Player enemyPlayer : players) { + if (enemyPlayer.getPosition().equals(position)) { + return true; + } + } + return false; } /** - * Check if the moving player should try to push another player - * @param position of the player that wants to move - * @param direction of the player that wants to move + * Return player if there is a player in that position + * + * @param position to check + * @return player in position */ - private void shouldPush(Vector2 position, Direction direction) { + public Player getPlayer(Vector2 position) { for (Player enemyPlayer : players) { - if (direction == Direction.EAST && enemyPlayer.getPosition().x == position.x + 1 && enemyPlayer.getPosition().y == position.y) { - pushPlayer(enemyPlayer, direction); - } else if (direction == Direction.WEST && enemyPlayer.getPosition().x == position.x - 1 && enemyPlayer.getPosition().y == position.y) { - pushPlayer(enemyPlayer, direction); - } else if (direction == Direction.NORTH && enemyPlayer.getPosition().x == position.x && enemyPlayer.getPosition().y == position.y + 1) { - pushPlayer(enemyPlayer, direction); - } else if (direction == Direction.SOUTH && enemyPlayer.getPosition().x == position.x && enemyPlayer.getPosition().y == position.y - 1) { - pushPlayer(enemyPlayer, direction); + if (enemyPlayer.getPosition().equals(position)) { + return enemyPlayer; } } + return null; + } + + /** + * Check if the moving player should try to push another player + * + * @param player trying to move + * @return true if player should push another player to move + */ + public boolean shouldPush(Player player) { + return hasPlayer(getNeighbourPosition(player.getPosition(), player.getDirection())); + } + + /** + * @param player that should be pushed + * @param direction to push in + * @return true if it is possible to push all enemies in a row + */ + private boolean canPush(Player player, Direction direction) { + if (hasPlayer(getNeighbourPosition(player.getPosition(), direction))) { + return canGo(player.getPosition(), direction) && + canPush(getPlayer(getNeighbourPosition(player.getPosition(), direction)), direction); + } + return canGo(player.getPosition(), direction); } /** - * @param enemyPlayer enemy player that should be pushed - * @param direction direction to push enemy player in + * Push all players in a row + * Remove player from board + * Update player position according to direction + * Add player to cell that corresponds to player position + * + * @param player that should be pushed + * @param direction to push player in */ - private void pushPlayer(Player enemyPlayer, Direction direction) { + private void pushPlayer(Player player, Direction direction) { + if (hasPlayer(getNeighbourPosition(player.getPosition(), direction))) { + pushPlayer(getPlayer(getNeighbourPosition(player.getPosition(), direction)), direction); + } + removePlayerFromBoard(player); switch (direction) { case SOUTH: - enemyPlayer.setPosition(new Vector2(enemyPlayer.getPosition().x, enemyPlayer.getPosition().y - 1)); + player.setPosition(new Vector2(player.getPosition().x, player.getPosition().y - 1)); break; case WEST: - enemyPlayer.setPosition(new Vector2(enemyPlayer.getPosition().x - 1, enemyPlayer.getPosition().y)); + player.setPosition(new Vector2(player.getPosition().x - 1, player.getPosition().y)); break; case EAST: - enemyPlayer.setPosition(new Vector2(enemyPlayer.getPosition().x + 1, enemyPlayer.getPosition().y)); + player.setPosition(new Vector2(player.getPosition().x + 1, player.getPosition().y)); break; case NORTH: - enemyPlayer.setPosition(new Vector2(enemyPlayer.getPosition().x, enemyPlayer.getPosition().y + 1)); + player.setPosition(new Vector2(player.getPosition().x, player.getPosition().y + 1)); break; default: break; } + addPlayer(player); } - //TODO: BUG when you are crashing with a player in the corner. Ist possible to only update the specific tile(?). - public void updatePlayers() { - for (int y = 0; y < boardHeight; y++) { - for (int x = 0; x < boardWidth; x++) { - playerLayer.setCell(x, y, null); + /** + * Remove player from board + * + * @param player to remove from board + */ + public void removePlayerFromBoard(Player player) { + playerLayer.setCell((int) player.getPosition().x, (int) player.getPosition().y, null); + } + + public boolean hasFlag(Vector2 position) { + return flagLayer.getCell((int) position.x, (int) position.y) != null; + } + + public Flag getFlag(Vector2 position) { + for (Flag flag : flags) { + if (flag.getPosition().equals(position)) { + return flag; } } - for (Player player : players) { - TiledMapTileLayer.Cell cell = new TiledMapTileLayer.Cell(); - TiledMapTileSet tileSet = tiledMap.getTileSets().getTileSet("player"); - cell.setTile(tileSet.getTile(137)); - outsideBoard(player); - playerLayer.setCell((int) player.getPosition().x, (int) player.getPosition().y, cell); - } + return null; } - /** - * @return list of all players - */ - public ArrayList getPlayers() { - return players; + public void pickUpFlag(Player player) { + Flag flag = getFlag(player.getPosition()); + player.pickUpFlag(getFlag(player.getPosition()), flag.getFlagnr()); } - /** - * @return {@link TiledMapTileLayer} of player layer - */ - public TiledMapTileLayer getPlayerLayer() { - return playerLayer; + public ArrayList getFlags(){ + return flags; } /** - * @return {@link TiledMapTileLayer} of flag layer + * @return list of all players */ - public TiledMapTileLayer getFlagLayer() { - return flagLayer; + public ArrayList getPlayers() { + return players; } /** @@ -260,13 +582,6 @@ public TiledMapTileLayer getWallLayer() { return wallLayer; } - /** - * @return {@link TiledMapTileLayer} of ground layer - */ - public TiledMapTileLayer getGroundLayer() { - return groundLayer; - } - /** * @return width of the board */ diff --git a/src/main/java/inf112/skeleton/app/BoardLayers.java b/src/main/java/inf112/skeleton/app/BoardLayers.java index c1732d1f..8ec81bdd 100644 --- a/src/main/java/inf112/skeleton/app/BoardLayers.java +++ b/src/main/java/inf112/skeleton/app/BoardLayers.java @@ -4,25 +4,35 @@ import com.badlogic.gdx.maps.tiled.TiledMap; import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; import com.badlogic.gdx.maps.tiled.TmxMapLoader; +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.enums.Direction; +import inf112.skeleton.app.enums.Rotate; +import inf112.skeleton.app.enums.TileID; +import inf112.skeleton.app.objects.Flag; +import inf112.skeleton.app.objects.Laser; +import inf112.skeleton.app.objects.RotatePad; import java.util.ArrayList; public abstract class BoardLayers { - public TiledMap tiledMap; + public final TiledMap tiledMap; - public TiledMapTileLayer playerLayer; - public TiledMapTileLayer flagLayer; - public TiledMapTileLayer wallLayer; - public TiledMapTileLayer laserLayer; - public TiledMapTileLayer groundLayer; + public final TiledMapTileLayer playerLayer; + public final TiledMapTileLayer flagLayer; + public final TiledMapTileLayer wallLayer; + public final TiledMapTileLayer laserLayer; + public final TiledMapTileLayer groundLayer; - public int boardWidth; - public int boardHeight; + public final ArrayList lasers; + public final ArrayList flags; + public final ArrayList rotatePads; + public final ArrayList holes; - private ArrayList players; + public final int boardWidth; + public final int boardHeight; - public BoardLayers(String mapPath){ + public BoardLayers(String mapPath) { this.tiledMap = new TmxMapLoader().load(mapPath); this.playerLayer = (TiledMapTileLayer) tiledMap.getLayers().get("Player"); @@ -34,11 +44,109 @@ public BoardLayers(String mapPath){ MapProperties properties = tiledMap.getProperties(); boardWidth = properties.get("width", Integer.class); boardHeight = properties.get("height", Integer.class); + + this.holes = new ArrayList<>(); + this.rotatePads = new ArrayList<>(); + this.flags = new ArrayList<>(); + this.lasers = new ArrayList<>(); + + findFlags(); + findRotatePadsAndHoles(); + findLasers(); } + /** + * Finds where there are {@link RotatePad} and Holes on the map. In the case of RotatePad adds a RotatePad object to + * the rotatePad list, in the case of a hole adds a {@link Vector2} to the holes list. + */ + public void findRotatePadsAndHoles() { + for (int x = 0; x < groundLayer.getWidth(); x++) { + for (int y = 0; y < groundLayer.getHeight(); y++) { + TiledMapTileLayer.Cell cell = groundLayer.getCell(x, y); + int ID = cell.getTile().getId(); + if (ID == TileID.NORMAL_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORMAL_HOLE2.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTHWEST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTH_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTHEAST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.EAST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTH_EAST_SOUTH_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.WEST_EAST_SOUTH_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.SOUTHWEST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.SOUTH_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.SOUTHEAST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.WEST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTH_WEST_SOUTH_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.NORTH_WEST_EAST_HOLE.getId()) { + holes.add(new Vector2(x, y)); + } else if (ID == TileID.ROTATE_PAD_LEFT.getId()) { + rotatePads.add(new RotatePad(Rotate.LEFT, new Vector2(x, y))); + } else if (ID == TileID.ROTATE_PAD_RIGHT.getId()) { + rotatePads.add(new RotatePad(Rotate.RIGHT, new Vector2(x, y))); + } + } + } + } + + /** + * Finds the where the flags are on the board, makes {@link Flag} objects + * and puts them in to the flag array. + */ + public void findFlags() { + for (int x = 0; x < flagLayer.getWidth(); x++) { + for (int y = 0; y < flagLayer.getHeight(); y++) { + TiledMapTileLayer.Cell cell = flagLayer.getCell(x, y); + if (cell != null) { + int ID = cell.getTile().getId(); + if (ID == TileID.FLAG_1.getId()) { + flags.add(new Flag(1, x, y)); + } else if (ID == TileID.FLAG_2.getId()) { + flags.add(new Flag(2, x, y)); + } else if (ID == TileID.FLAG_3.getId()) { + flags.add(new Flag(3, x, y)); + } else if (ID == TileID.FLAG_4.getId()) { + flags.add(new Flag(4, x, y)); + } + } + } + } + } + + public void findLasers() { + for (int x = 0; x < wallLayer.getWidth(); x++) { + for (int y = 0; y < wallLayer.getHeight(); y++) { + TiledMapTileLayer.Cell cell = wallLayer.getCell(x, y); + if (cell != null) { + int ID = cell.getTile().getId(); + if (ID == TileID.EAST_LASER_WALL.getId()) { + lasers.add(new Laser(x, y, Direction.WEST)); + } else if (ID == TileID.WEST_LASER_WALL.getId()) { + lasers.add(new Laser(x, y, Direction.EAST)); + } else if (ID == TileID.NORTH_LASER_WALL.getId()) { + lasers.add(new Laser(x, y, Direction.SOUTH)); + } else if (ID == TileID.SOUTH_LASER_WALL.getId()) { + lasers.add(new Laser(x, y, Direction.NORTH)); + } + } + } + } + } + public abstract TiledMap getMap(); - public abstract TiledMapTileLayer getPlayerLayer(); - public abstract TiledMapTileLayer getFlagLayer(); + public abstract TiledMapTileLayer getLaserLayer(); } diff --git a/src/main/java/inf112/skeleton/app/GifDecoder.java b/src/main/java/inf112/skeleton/app/GifDecoder.java new file mode 100644 index 00000000..3fa3f8b9 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/GifDecoder.java @@ -0,0 +1,738 @@ +package inf112.skeleton.app; + +/* Copyright by Johannes Borchardt */ +/* LibGdx conversion 2014 by Anton Persson */ +/* Released under Apache 2.0 */ +/* https://code.google.com/p/animated-gifs-in-android/ */ + +import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.Animation.PlayMode; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.utils.Array; + +import java.io.InputStream; +import java.util.Vector; + +public class GifDecoder { + /** + * File read status: No errors. + */ + public static final int STATUS_OK = 0; + /** + * File read status: Error decoding file (may be partially decoded) + */ + public static final int STATUS_FORMAT_ERROR = 1; + /** + * File read status: Unable to open source. + */ + public static final int STATUS_OPEN_ERROR = 2; + /** max decoder pixel stack size */ + protected static final int MAX_STACK_SIZE = 4096; + protected InputStream in; + protected int status; + protected int width; // full image width + protected int height; // full image height + protected boolean gctFlag; // global color table used + protected int gctSize; // size of global color table + protected int loopCount = 1; // iterations; 0 = repeat forever + protected int[] gct; // global color table + protected int[] lct; // local color table + protected int[] act; // active color table + protected int bgIndex; // background color index + protected int bgColor; // background color + protected int lastBgColor; // previous bg color + protected int pixelAspect; // pixel aspect ratio + protected boolean lctFlag; // local color table flag + protected boolean interlace; // interlace flag + protected int lctSize; // local color table size + protected int ix; // current image rectangle + protected int iy; // current image rectangle + protected int iw; // current image rectangle + protected int ih; // current image rectangle + protected int lrx; + protected int lry; + protected int lrw; + protected int lrh; + protected DixieMap image; // current frame + protected DixieMap lastPixmap; // previous frame + protected final byte[] block = new byte[256]; // current data block + protected int blockSize = 0; // block size last graphic control extension info + protected int dispose = 0; // 0=no action; 1=leave in place; 2=restore to bg; 3=restore to prev + protected int lastDispose = 0; + protected boolean transparency = false; // use transparent color + protected int delay = 0; // delay in milliseconds + protected int transIndex; // transparent color index + // LZW decoder working arrays + protected short[] prefix; + protected byte[] suffix; + protected byte[] pixelStack; + protected byte[] pixels; + protected Vector frames; // frames read from current file + protected int frameCount; + + /** + * Gets the image contents of frame n. + * + * @return BufferedPixmap representation of frame, or null if n is invalid. + */ + public DixieMap getFrame(int n) { + if (frameCount <= 0) + return null; + n %= frameCount; + return frames.elementAt(n).image; + } + + /** + * Reads GIF image from stream + * + * @param is containing GIF file. + */ + public void read(InputStream is) { + init(); + if (is != null) { + in = is; + readHeader(); + if (!err()) { + readContents(); + if (frameCount < 0) { + status = STATUS_FORMAT_ERROR; + } + } + } else { + status = STATUS_OPEN_ERROR; + } + try { + assert is != null; + is.close(); + } catch (Exception ignored) { + } + } + + /** + * Gets display duration for specified frame. + * + * @param n + * int index of frame + * @return delay in milliseconds + */ + public int getDelay(int n) { + delay = -1; + if ((n >= 0) && (n < frameCount)) { + delay = frames.elementAt(n).delay; + } + return delay; + } + + /** + * Gets the number of frames read from file. + * + * @return frame count + */ + public int getFrameCount() { + return frameCount; + } + + /** + * Creates new frame image from current data (and previous frames as specified by their disposition codes). + */ + protected void setPixels() { + // expose destination image's pixels as int array + int[] dest = new int[width * height]; + // fill in starting image contents based on last image's dispose code + if (lastDispose > 0) { + if (lastDispose == 3) { + // use image before last + int n = frameCount - 2; + if (n > 0) { + lastPixmap = getFrame(n - 1); + } else { + lastPixmap = null; + } + } + if (lastPixmap != null) { + lastPixmap.getPixels(dest, 0, width, width, height); + // copy pixels + if (lastDispose == 2) { + // fill last image rect area with background color + int c = 0; + if (!transparency) { + c = lastBgColor; + } + for (int i = 0; i < lrh; i++) { + int n1 = (lry + i) * width + lrx; + int n2 = n1 + lrw; + for (int k = n1; k < n2; k++) { + dest[k] = c; + } + } + } + } + } + // copy each source line to the appropriate place in the destination + int pass = 1; + int inc = 8; + int iline = 0; + for (int i = 0; i < ih; i++) { + int line = i; + if (interlace) { + if (iline >= ih) { + pass++; + switch (pass) { + case 2: + iline = 4; + break; + case 3: + iline = 2; + inc = 4; + break; + case 4: + iline = 1; + inc = 2; + break; + default: + break; + } + } + line = iline; + iline += inc; + } + line += iy; + if (line < height) { + int k = line * width; + int dx = k + ix; // start of line in dest + int dlim = dx + iw; // end of dest line + if ((k + width) < dlim) { + dlim = k + width; // past dest edge + } + int sx = i * iw; // start of line in source + while (dx < dlim) { + // map color and insert in destination + int index = ((int) pixels[sx++]) & 0xff; + int c = act[index]; + if (c != 0) { + dest[dx] = c; + } + dx++; + } + } + } + image = new DixieMap(dest, width, height); + //Pixmap.createPixmap(dest, width, height, Config.ARGB_4444); + } + + /** + * Decodes LZW image data into pixel array. Adapted from John Cristy's BitmapMagick. + */ + protected void decodeBitmapData() { + int nullCode = -1; + int npix = iw * ih; + int available; + int clear; + int code_mask; + int code_size; + int end_of_information; + int in_code; + int old_code; + int bits; + int code; + int count; + int i; + int datum; + int data_size; + int first; + int top; + int bi; + int pi; + if ((pixels == null) || (pixels.length < npix)) { + pixels = new byte[npix]; // allocate new pixel array + } + if (prefix == null) { + prefix = new short[MAX_STACK_SIZE]; + } + if (suffix == null) { + suffix = new byte[MAX_STACK_SIZE]; + } + if (pixelStack == null) { + pixelStack = new byte[MAX_STACK_SIZE + 1]; + } + // Initialize GIF data stream decoder. + data_size = read(); + clear = 1 << data_size; + end_of_information = clear + 1; + available = clear + 2; + old_code = nullCode; + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + for (code = 0; code < clear; code++) { + prefix[code] = 0; // XXX ArrayIndexOutOfBoundsException + suffix[code] = (byte) code; + } + // Decode GIF pixel stream. + datum = bits = count = first = top = pi = bi = 0; + for (i = 0; i < npix;) { + if (top == 0) { + if (bits < code_size) { + // Load bytes until there are enough bits for a code. + if (count == 0) { + // Read a new data block. + count = readBlock(); + if (count <= 0) { + break; + } + bi = 0; + } + datum += (((int) block[bi]) & 0xff) << bits; + bits += 8; + bi++; + count--; + continue; + } + // Get the next code. + code = datum & code_mask; + datum >>= code_size; + bits -= code_size; + // Interpret the code + if ((code > available) || (code == end_of_information)) { + break; + } + if (code == clear) { + // Reset decoder. + code_size = data_size + 1; + code_mask = (1 << code_size) - 1; + available = clear + 2; + old_code = nullCode; + continue; + } + if (old_code == nullCode) { + pixelStack[top++] = suffix[code]; + old_code = code; + first = code; + continue; + } + in_code = code; + if (code == available) { + pixelStack[top++] = (byte) first; + code = old_code; + } + while (code > clear) { + pixelStack[top++] = suffix[code]; + code = prefix[code]; + } + first = ((int) suffix[code]) & 0xff; + // Add a new string to the string table, + if (available >= MAX_STACK_SIZE) { + break; + } + pixelStack[top++] = (byte) first; + prefix[available] = (short) old_code; + suffix[available] = (byte) first; + available++; + if (((available & code_mask) == 0) && (available < MAX_STACK_SIZE)) { + code_size++; + code_mask += available; + } + old_code = in_code; + } + // Pop a pixel off the pixel stack. + top--; + pixels[pi++] = pixelStack[top]; + i++; + } + for (i = pi; i < npix; i++) { + pixels[i] = 0; // clear missing pixels + } + } + + /** + * Initializes or re-initializes reader + */ + protected void init() { + status = STATUS_OK; + frameCount = 0; + frames = new Vector<>(); + gct = null; + lct = null; + } + + /** + * Reads next variable length block from input. + * + * @return number of bytes stored in "buffer" + */ + protected int readBlock() { + blockSize = read(); + int n = 0; + if (blockSize > 0) { + try { + int count; + while (n < blockSize) { + count = in.read(block, n, blockSize - n); + if (count == -1) { + break; + } + n += count; + } + } catch (Exception e) { + e.printStackTrace(); + } + if (n < blockSize) { + status = STATUS_FORMAT_ERROR; + } + } + return n; + } + + /** + * Returns true if an error was encountered during reading/decoding + */ + protected boolean err() { + return status != STATUS_OK; + } + + /** + * Main file parser. Reads GIF content blocks. + */ + protected void readContents() { + // read GIF file content blocks + boolean done = false; + while (!(done || err())) { + int code = read(); + switch (code) { + case 0x2C: // image separator + readBitmap(); + break; + case 0x21: // extension + code = read(); + switch (code) { + case 0xf9: // graphics control extension + readGraphicControlExt(); + break; + case 0xff: // application extension + readBlock(); + StringBuilder app = new StringBuilder(); + for (int i = 0; i < 11; i++) { + app.append((char) block[i]); + } + if ("NETSCAPE2.0".equals(app.toString())) { + readNetscapeExt(); + } else { + skip(); // don't care + } + break; + // comment extension + // plain text extension + default: // uninteresting extension + skip(); + } + break; + case 0x3b: // terminator + done = true; + break; + case 0x00: // bad byte, but keep going and see what happens + break; + default: + status = STATUS_FORMAT_ERROR; + } + } + } + + /** + * Reads a single byte from the input stream. + */ + protected int read() { + int curByte = 0; + try { + curByte = in.read(); + } catch (Exception e) { + status = STATUS_FORMAT_ERROR; + } + return curByte; + } + + /** + * Reads GIF file header information. + */ + protected void readHeader() { + StringBuilder id = new StringBuilder(); + for (int i = 0; i < 6; i++) { + id.append((char) read()); + } + if (!id.toString().startsWith("GIF")) { + status = STATUS_FORMAT_ERROR; + return; + } + readLSD(); + if (gctFlag && !err()) { + gct = readColorTable(gctSize); + bgColor = gct[bgIndex]; + } + } + + /** + * Reads color table as 256 RGB integer values + * + * @param ncolors int number of colors to read + * @return int array containing 256 colors (packed ARGB with full alpha) + */ + protected int[] readColorTable(int ncolors) { + int nbytes = 3 * ncolors; + int[] tab = null; + byte[] c = new byte[nbytes]; + int n = 0; + try { + n = in.read(c); + } catch (Exception e) { + e.printStackTrace(); + } + if (n < nbytes) { + status = STATUS_FORMAT_ERROR; + } else { + tab = new int[256]; // max size to avoid bounds checks + int i = 0; + int j = 0; + while (i < ncolors) { + int r = ((int) c[j++]) & 0xff; + int g = ((int) c[j++]) & 0xff; + int b = ((int) c[j++]) & 0xff; + tab[i++] = 0xff000000 | (r << 16) | (g << 8) | b; + } + } + return tab; + } + + public Animation getAnimation(PlayMode playMode) { + int nrFrames = getFrameCount(); + Pixmap frame = getFrame(0); + int width = frame.getWidth(); + int height = frame.getHeight(); + int vzones = (int) Math.sqrt(nrFrames); + int hzones = vzones; + + while (vzones * hzones < nrFrames) vzones++; + + int v; + int h; + + Pixmap target = new Pixmap(width * hzones, height * vzones, Pixmap.Format.RGBA8888); + + for (h = 0; h < hzones; h++) { + for (v = 0; v < vzones; v++) { + int frameID = v + h * vzones; + if (frameID < nrFrames) { + frame = getFrame(frameID); + target.drawPixmap(frame, h * width, v * height); + } + } + } + + Texture texture = new Texture(target); + Array texReg = new Array<>(); + + for (h = 0; h < hzones; h++) { + for (v = 0; v < vzones; v++) { + int frameID = v + h * vzones; + if (frameID < nrFrames) { + TextureRegion tr = new TextureRegion(texture, h * width, v * height, width, height); + texReg.add(tr); + } + } + } + float frameDuration = (float) getDelay(0); + frameDuration /= 1000; // convert milliseconds into seconds + + return new Animation<>(frameDuration, texReg, playMode); + } + + /** + * Reads Graphics Control Extension values + */ + protected void readGraphicControlExt() { + read(); // block size + int packed = read(); // packed fields + dispose = (packed & 0x1c) >> 2; // disposal method + if (dispose == 0) { + dispose = 1; // elect to keep old image if discretionary + } + transparency = (packed & 1) != 0; + delay = readShort() * 10; // delay in milliseconds + transIndex = read(); // transparent color index + read(); // block terminator + } + + /** + * Reads next frame image + */ + protected void readBitmap() { + ix = readShort(); // (sub)image position & size + iy = readShort(); + iw = readShort(); + ih = readShort(); + int packed = read(); + lctFlag = (packed & 0x80) != 0; // 1 - local color table flag interlace + lctSize = (int) Math.pow(2, (packed & 0x07) + 1); + // 3 - sort flag + // 4-5 - reserved lctSize = 2 << (packed & 7); // 6-8 - local color + // table size + interlace = (packed & 0x40) != 0; + if (lctFlag) { + lct = readColorTable(lctSize); // read table + act = lct; // make local table active + } else { + act = gct; // make global table active + if (bgIndex == transIndex) { + bgColor = 0; + } + } + int save = 0; + if (transparency) { + save = act[transIndex]; + act[transIndex] = 0; // set transparent color if specified + } + if (act == null) { + status = STATUS_FORMAT_ERROR; // no color table defined + } + if (err()) { + return; + } + decodeBitmapData(); // decode pixel data + skip(); + if (err()) { + return; + } + frameCount++; + // create new image to receive frame data + image = new DixieMap(width, height); + setPixels(); // transfer pixel data to image + frames.addElement(new GifFrame(image, delay)); // add image to frame + // list + if (transparency) { + act[transIndex] = save; + } + resetFrame(); + } + + private static class DixieMap extends Pixmap { + DixieMap(int w, int h) { + super(w, h, Format.RGBA8888); + } + + DixieMap(int[] data, int w, int h) { + super(w, h, Format.RGBA8888); + + int x; + int y; + + for (y = 0; y < h; y++) { + for (x = 0; x < w; x++) { + int pxl_ARGB8888 = data[x + y * w]; + int pxl_RGBA8888 = + ((pxl_ARGB8888 >> 24) & 0x000000ff) | ((pxl_ARGB8888 << 8) & 0xffffff00); + // convert ARGB8888 > RGBA8888 + drawPixel(x, y, pxl_RGBA8888); + } + } + } + + private void getPixels(int[] pixels, int offset, int stride, int width, int height) { + java.nio.ByteBuffer bb = getPixels(); + + int k; + int l; + + for (k = 0; k < height; k++) { + int _offset = offset; + for (l = 0; l < width; l++) { + int pxl = bb.getInt(4 * (l + k * width)); + + // convert RGBA8888 > ARGB8888 + pixels[_offset++] = ((pxl >> 8) & 0x00ffffff) | ((pxl << 24) & 0xff000000); + } + offset += stride; + } + } + } + + /** + * Reads Logical Screen Descriptor + */ + protected void readLSD() { + // logical screen size + width = readShort(); + height = readShort(); + // packed fields + int packed = read(); + gctFlag = (packed & 0x80) != 0; // 1 : global color table flag + // 2-4 : color resolution + // 5 : gct sort flag + gctSize = 2 << (packed & 7); // 6-8 : gct size + bgIndex = read(); // background color index + pixelAspect = read(); // pixel aspect ratio + } + + /** + * Reads Netscape extenstion to obtain iteration count + */ + protected void readNetscapeExt() { + do { + readBlock(); + if (block[0] == 1) { + // loop count sub-block + int b1 = ((int) block[1]) & 0xff; + int b2 = ((int) block[2]) & 0xff; + loopCount = (b2 << 8) | b1; + } + } while ((blockSize > 0) && !err()); + } + + /** + * Reads next 16-bit value, LSB first + */ + protected int readShort() { + // read 16-bit value, LSB first + return read() | (read() << 8); + } + + /** + * Resets frame state for reading next image. + */ + protected void resetFrame() { + lastDispose = dispose; + lrx = ix; + lry = iy; + lrw = iw; + lrh = ih; + lastPixmap = image; + lastBgColor = bgColor; + dispose = 0; + transparency = false; + delay = 0; + lct = null; + } + + /** + * Skips variable length blocks up to and including next zero length block. + */ + protected void skip() { + do { + readBlock(); + } while ((blockSize > 0) && !err()); + } + + private static class GifFrame { + public final DixieMap image; + public final int delay; + + public GifFrame(DixieMap im, int del) { + image = im; + delay = del; + } + } + + public static Animation loadGIFAnimation(Animation.PlayMode playMode, InputStream is) { + GifDecoder gdec = new GifDecoder(); + gdec.read(is); + return gdec.getAnimation(playMode); + } +} diff --git a/src/main/java/inf112/skeleton/app/Main.java b/src/main/java/inf112/skeleton/app/Main.java index 9e64dcf5..bdafade1 100644 --- a/src/main/java/inf112/skeleton/app/Main.java +++ b/src/main/java/inf112/skeleton/app/Main.java @@ -10,6 +10,7 @@ public static void main(String[] args) { cfg.title = "robo-rally"; cfg.width = 960; cfg.height = 540; + //cfg.fullscreen = true; new LwjglApplication(new RallyGame(), cfg); } diff --git a/src/main/java/inf112/skeleton/app/Player.java b/src/main/java/inf112/skeleton/app/Player.java index a65ad98a..38b3b90c 100644 --- a/src/main/java/inf112/skeleton/app/Player.java +++ b/src/main/java/inf112/skeleton/app/Player.java @@ -2,32 +2,112 @@ import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.cards.Deck; +import inf112.skeleton.app.cards.ProgramCard; import inf112.skeleton.app.enums.Direction; +import inf112.skeleton.app.objects.Flag; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; public class Player { private final int playerNr; private Vector2 backupPosition; - private Vector2 position; + private Direction backupDirection; + private Vector2 alternativeBackupPosition; + private Direction alternativeBackupDirection; + private final Vector2 position; private Direction direction; + private final ArrayList flagsCollected; + private ArrayList selectedCards; + private final ArrayList allCards; + + private int damageTokens; + private int lifeTokens; public Player(Vector2 position, int playerNr) { this.position = position; this.direction = Direction.EAST; this.playerNr = playerNr; - setBackupPosition(position); + this.flagsCollected = new ArrayList<>(); + this.selectedCards = new ArrayList<>(); + this.allCards = new ArrayList<>(); + this.damageTokens = 0; + this.lifeTokens = 3; + + setBackup(position, Direction.EAST); + } + + public ArrayList getAllCards() { + return allCards; + } + + public ArrayList getSelectedCards() { + System.out.println(selectedCards); + return selectedCards; + } + + public void selectCards() { + while (selectedCards.size() < 5) { + selectedCards.add(allCards.remove(0)); + } + } + + public void drawCards(Deck deck) { + while (allCards.size() < 9) { + allCards.add(deck.drawCard()); + } } /** - * Set new backup position - * @param backupPosition respawn position when damaged + * a int on how many damageTokens + * + * @return your damageTokens */ - public void setBackupPosition(Vector2 backupPosition) { + public int getDamageTokens() { + return damageTokens; + } + + public int resetDamageTokens() { + return this.damageTokens = 0; + } + + public int getLifeTokens() { + return lifeTokens; + } + + public void decrementLifeTokens() { + this.lifeTokens--; + } + + public boolean isDead() { + return lifeTokens <= 0; + } + + public void handleDamage(RallyGame game) { + this.damageTokens++; + if (damageTokens >= 10) { + lifeTokens--; + resetDamageTokens(); + game.getBoard().respawn(this); + } + } + + /** + * Set new backup position and direction + * + * @param backupPosition respawn position when damaged + * @param backupDirection respawn direction when damaged + */ + public void setBackup(Vector2 backupPosition, Direction backupDirection) { if (this.backupPosition == null) { - this.backupPosition = new Vector2(backupPosition.x, backupPosition.y); + this.backupPosition = new Vector2(backupPosition); } else { this.backupPosition.set(backupPosition.x, backupPosition.y); } + this.backupDirection = backupDirection; } /** @@ -37,10 +117,60 @@ public Vector2 getBackupPosition() { return backupPosition; } + /** + * @return backup direction + */ + public Direction getBackupDirection() { + return backupDirection; + } + + public void setAlternativeBackup(Vector2 alternativeBackupPosition, Direction alternativeBackupDirection) { + if (this.alternativeBackupPosition == null) { + this.alternativeBackupPosition = new Vector2(alternativeBackupPosition); + } else { + this.alternativeBackupPosition.set(alternativeBackupPosition.x, alternativeBackupPosition.y); + } + this.alternativeBackupDirection = alternativeBackupDirection; + } + + /** + * @return alternative backup position + */ + public Vector2 getAlternativeBackupPosition() { + return alternativeBackupPosition; + } + + /** + * @return alternative backup direction + */ + public Direction getAlternativeBackupDirection() { + return alternativeBackupDirection; + } + + + public void chooseAlternativeBackupPosition(Board board, Vector2 position) { + ArrayList possiblePositions = board.getNeighbourhood(position); + Collections.shuffle(possiblePositions); + for (Vector2 pos : possiblePositions) { + for (Direction dir : board.getDirectionRandomOrder()) { + if (board.validRespawnPosition(pos, dir)) { + setAlternativeBackup(pos, dir); + return; + } + } + } + setAlternativeBackup(board.getStartPosition(getPlayerNr()), Direction.EAST); + if (board.hasPlayer(board.getStartPosition(getPlayerNr()))) { + chooseAlternativeBackupPosition(board, alternativeBackupPosition); + } + } + /** * @return number of player */ - public int getPlayerNr() {return playerNr; } + public int getPlayerNr() { + return playerNr; + } /** * @return the {@link Vector2} to the player @@ -69,4 +199,58 @@ public Direction getDirection() { public void setDirection(Direction direction) { this.direction = direction; } + + public void pickUpFlag(Flag flag, int flagNr) { + switch (flagNr) { + case 1: + if (!flagsCollected.contains(flag)) { + flagsCollected.add(flag); + } + break; + case 2: + if (!flagsCollected.contains(flag) && flagsCollected.size() == 1) { + flagsCollected.add(flag); + } + break; + case 3: + if (!flagsCollected.contains(flag) && flagsCollected.size() == 2) { + flagsCollected.add(flag); + } + break; + case 4: + if (!flagsCollected.contains(flag) && flagsCollected.size() == 3) { + flagsCollected.add(flag); + } + break; + default: + break; + } + } + + /** + * Update the selected cards for this player. + * Used for testing, so that we can decide what card the player is going to play, and then test that the player + * does what the card says. + * + * @param cards one or more cards (separated by comma) or a list of cards. + */ + public void setSelectedCards(ProgramCard... cards) { + this.selectedCards = new ArrayList<>(Arrays.asList(cards)); + } + + public ArrayList getFlagsCollected() { + return flagsCollected; + } + + public boolean hasAllFlags(int numberOfFlags) { + return flagsCollected.size() == numberOfFlags; + } + + public boolean equals(Player other) { + return this.getPlayerNr() == other.getPlayerNr(); + } + + public String toString() { + return "Player " + getPlayerNr(); + } } diff --git a/src/main/java/inf112/skeleton/app/PlayerSorter.java b/src/main/java/inf112/skeleton/app/PlayerSorter.java new file mode 100644 index 00000000..7c7bea8e --- /dev/null +++ b/src/main/java/inf112/skeleton/app/PlayerSorter.java @@ -0,0 +1,12 @@ +package inf112.skeleton.app; + +import java.util.Comparator; + +public class PlayerSorter implements Comparator { + + @Override + public int compare(Player player1, Player player2) { + return player2.getSelectedCards().get(0).getPriority() - + player1.getSelectedCards().get(0).getPriority(); + } +} diff --git a/src/main/java/inf112/skeleton/app/RallyGame.java b/src/main/java/inf112/skeleton/app/RallyGame.java index 31c16733..20cff3ce 100644 --- a/src/main/java/inf112/skeleton/app/RallyGame.java +++ b/src/main/java/inf112/skeleton/app/RallyGame.java @@ -4,50 +4,270 @@ import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Input; import com.badlogic.gdx.InputAdapter; -import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import com.badlogic.gdx.audio.Music; +import com.badlogic.gdx.audio.Sound; +import com.badlogic.gdx.math.Vector2; import inf112.skeleton.app.cards.Deck; +import inf112.skeleton.app.cards.ProgramCard; import inf112.skeleton.app.enums.Direction; -import inf112.skeleton.app.screens.MenuScreen; +import inf112.skeleton.app.enums.Rotate; +import inf112.skeleton.app.objects.Laser; +import inf112.skeleton.app.objects.RotatePad; +import inf112.skeleton.app.screens.GifScreen; +import inf112.skeleton.app.screens.LoadingScreen; + +import java.util.ArrayList; +import java.util.concurrent.Semaphore; public class RallyGame extends Game { public Board board; - public SpriteBatch batch; public Deck deck; + public ArrayList players; + public Semaphore waitForCards; + public boolean playing; + public Sound laserSound; + public Player mainPlayer; public void create() { - this.batch = new SpriteBatch(); - this.board = new Board("assets/Risky_Exchange.tmx"); - this.setScreen(new MenuScreen(this)); + this.setScreen(new LoadingScreen(this)); + startMusic(); + } + + public void setupGame(String mapPath) { + this.board = new Board(mapPath, 4); this.deck = new Deck(); + this.players = new ArrayList<>(); + this.players = board.getPlayers(); + this.mainPlayer = board.getPlayer1(); + + this.waitForCards = new Semaphore(1); + this.waitForCards.tryAcquire(); + this.playing = true; + this.laserSound = Gdx.audio.newSound(Gdx.files.internal("assets/Sound/LaserShot.mp3")); + + new Thread(this::doTurn).start(); + + setInputProcessor(); + dealCards(); + selectCards(); + } + + public void setInputProcessor() { Gdx.input.setInputProcessor(new InputAdapter() { @Override public boolean keyUp(int keycode) { - Player player = board.getPlayer1(); + if (mainPlayer.isDead()) { + return false; + } + + removeLasers(); + if (keycode == Input.Keys.RIGHT) { - player.setDirection(Direction.EAST); + mainPlayer.setDirection(Direction.EAST); + board.movePlayer(mainPlayer); } else if (keycode == Input.Keys.LEFT) { - player.setDirection(Direction.WEST); + mainPlayer.setDirection(Direction.WEST); + board.movePlayer(mainPlayer); } else if (keycode == Input.Keys.UP) { - player.setDirection(Direction.NORTH); + mainPlayer.setDirection(Direction.NORTH); + board.movePlayer(mainPlayer); } else if (keycode == Input.Keys.DOWN) { - player.setDirection(Direction.SOUTH); + mainPlayer.setDirection(Direction.SOUTH); + board.movePlayer(mainPlayer); + } else if (keycode == Input.Keys.ESCAPE) { + Gdx.app.exit(); + } else if (keycode == Input.Keys.SPACE) { + cardsReady(); + return super.keyDown(keycode); } else { return super.keyDown(keycode); } - board.movePlayer(player); + + if (mainPlayer.hasAllFlags(board.getFlags().size())) { + setWinScreen(); + } + board.respawnPlayers(); + fireLasers(); + removeDeadPlayers(); return super.keyDown(keycode); } }); } - public void render() { - super.render(); + public void startMusic() { + Music music = Gdx.audio.newMusic(Gdx.files.internal("assets/sound/menu_music.mp3")); + music.setLooping(true); + music.setVolume(1f); + music.play(); + } + + private void cardsReady() { + waitForCards.release(); + } + + public void doTurn() { + + // TODO: Alle velger kort + // TODO: Første kort spilles for alle i riktig rekkefølge + // TODO: Gears roterer + // TODO: Express belt flytter én + // TODO: Express belt og vanlig belt flytter én + // TODO: Spiller skyter + // TODO: Laser skyter + while (playing) { + try { + waitForCards.acquire(); + } catch (InterruptedException e) { + e.printStackTrace(); + } + if (Thread.interrupted()) { + return; + } + for (int i = 0; i < 5; i++) { + System.out.println("Runde " + (i + 1)); + allPlayersPlayCard(); + activateRotatePads(); + + fireLasers(); + try { + Thread.sleep(600); + } catch (InterruptedException e) { + e.printStackTrace(); + } + removeLasers(); + } + removeDeadPlayers(); + dealCards(); + selectCards(); + } + } + + public void selectCards() { + for (Player player : players) { + player.selectCards(); + } + } + + public void dealCards() { + for (Player player : players) { + player.drawCards(deck); + } + } + + public void removeDeadPlayers() { + ArrayList deadPlayers = new ArrayList<>(); + for (Player player : players) { + if (player.isDead()) { + board.removePlayerFromBoard(player); + deadPlayers.add(player); + } + } + players.removeAll(deadPlayers); + } + + public void allPlayersPlayCard() { + ArrayList playerOrder = new ArrayList<>(players); + // Add all players to order list, and remove players with no cards left + playerOrder.removeIf(p -> p.getSelectedCards().isEmpty()); + playerOrder.sort(new PlayerSorter()); + for (Player player : playerOrder) { + playCard(player); + // Wait 1 second for each player + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + + public void playCard(Player player) { + ProgramCard card = player.getSelectedCards().remove(0); + System.out.println(player.toString() + " played " + card.toString()); + switch (card.getRotate()) { + case RIGHT: + player.setDirection(player.getDirection().turnRight()); + board.rotatePlayer(player); + break; + case LEFT: + player.setDirection(player.getDirection().turnLeft()); + board.rotatePlayer(player); + break; + case UTURN: + player.setDirection(player.getDirection().turnAround()); + board.rotatePlayer(player); + break; + case NONE: + for (int i = 0; i < card.getDistance(); i++) { + board.movePlayer(player); + // Wait 500 ms for each move except last one + if (i < card.getDistance() - 1) { + try { + Thread.sleep(500); + } catch (Exception e) { + e.printStackTrace(); + } + } + } + break; + default: + break; + } + deck.addCardToDiscardPile(card); + } + + public void setWinScreen() { + this.dispose(); + this.setScreen(new GifScreen(this)); + } + + public void removeLasers() { + for (int y = 0; y < board.getHeight(); y++) { + for (int x = 0; x < board.getWidth(); x++) { + board.laserLayer.setCell(x, y, null); + } + } + } + + public void fireLasers() { + for (Laser laser : board.lasers) { + laser.fire(this); + } + laserSound.play(); + } + + public void activateRotatePads(){ + for(Player player : board.getPlayers()){ + for(RotatePad rotatePad : board.rotatePads){ + Vector2 playerPosition = player.getPosition(); + Vector2 rotePadPosition = rotatePad.getPosition(); + + if(playerPosition.equals(rotePadPosition)){ + Rotate rotateDirection = rotatePad.getRotate(); + Direction playerDirection = player.getDirection(); + + switch (rotateDirection){ + case LEFT: + player.setDirection(playerDirection.turnLeft()); + break; + case RIGHT: + player.setDirection(playerDirection.turnRight()); + break; + case UTURN: + player.setDirection(playerDirection.turnAround()); + break; + default: + // Will never happen + } + } + } + } } public void dispose() { - batch.dispose(); + this.screen.dispose(); } public Board getBoard() { diff --git a/src/main/java/inf112/skeleton/app/cards/CardHand.java b/src/main/java/inf112/skeleton/app/cards/CardHand.java deleted file mode 100644 index 9234cf98..00000000 --- a/src/main/java/inf112/skeleton/app/cards/CardHand.java +++ /dev/null @@ -1,15 +0,0 @@ -package inf112.skeleton.app.cards; - -import java.util.ArrayList; - -public class CardHand { - - private ArrayList hand = new ArrayList<>(); - - public CardHand(Deck deck, int slots) { - for (int i = 0; i < slots; i++) { - hand.add(deck.drawCard()); - } - } - -} diff --git a/src/main/java/inf112/skeleton/app/cards/Deck.java b/src/main/java/inf112/skeleton/app/cards/Deck.java index f665fa78..cc445670 100644 --- a/src/main/java/inf112/skeleton/app/cards/Deck.java +++ b/src/main/java/inf112/skeleton/app/cards/Deck.java @@ -7,9 +7,7 @@ public class Deck { private Stack deck; - - private ProgramCard card; - private int priority = 0; + private Stack discardPile; public Deck() { makeNewDeck(); @@ -17,13 +15,17 @@ public Deck() { } /** - * Makes all the programCards and puts them on the stack + * Make all the programCards and put them in the stack */ public void makeNewDeck() { deck = new Stack<>(); + discardPile = new Stack<>(); + makeRotateCards(); + makeMoveCards(); + } - priority = makeRotateCards(priority); - makeMoveCards(priority); + public void addCardToDiscardPile(ProgramCard programCard) { + discardPile.push(programCard); } /** @@ -44,62 +46,48 @@ public void shuffleDeck() { * @return the next {@link ProgramCard} in the stack / deck */ public ProgramCard drawCard() { - return deck.pop(); + ProgramCard card = deck.pop(); + if (deck.isEmpty()) { + deck.addAll(discardPile); + shuffleDeck(); + } + return card; } /** - * Makes all the rotating cards, RotateR (18), RotateL (18) and RotateU (6) cards. - * @param startPri is the priority number the last card made had. - * @return the priority number of the last card made + * Make all rotate cards, 18 Rotate right, 18 Rotate left and 6 Rotate U-turn + * with priority evenly spread between all cards */ - private int makeRotateCards(int startPri){ - int priority = startPri; - for (int i = 0; i < 36; i++) { - priority += 10; - if (i % 2 == 0) { - card = new ProgramCard(priority, 0, Rotate.LEFT, "Rotate Left"); + private void makeRotateCards() { + // Make 42 rotate cards + for (int priority = 1; priority <= 42; priority++) { + // Every seventh rotate card should be U-turn + if (priority % 7 == 0) { + deck.push(new ProgramCard(priority * 10, 0, Rotate.UTURN, "U-turn")); + } else if (priority % 2 == 0) { + deck.push(new ProgramCard(priority * 10, 0, Rotate.RIGHT, "Right rotate")); } else { - card = new ProgramCard(priority, 0, Rotate.RIGHT, "Rotate Right"); + deck.push(new ProgramCard(priority * 10, 0, Rotate.LEFT, "Left rotate")); } - deck.push(card); } - for (int i = 0; i < 6; i++) { - priority += 10; - card = new ProgramCard(priority, 0, Rotate.UTURN, "U-Turn"); - deck.push(card); - } - return priority; } /** - * Makes all the move cards, Move 1 (18), Move 2 (12) and Move 3 (6). - * @param startPri is the priority number of the last card made had. + * Make all move cards, 18 Move 1, 12 Move 2 and 6 Move 3 + * with priority evenly spread between all cards */ - private void makeMoveCards(int startPri){ - int priority = startPri; - boolean checker = true; - for (int i = 0; i < 30; i++) { - priority += 10; - - // This is so the move tre cards not all get in the same range of priority. - if (i % 3 == 0 && i < 18) { - card = new ProgramCard(priority, 3, Rotate.NONE, "Move 3"); + private void makeMoveCards() { + int startPriority = 420; + // Make 36 move cards + for (int priority = 1; priority <= 36; priority++) { + if (priority % 6 == 0) { + // For every sixth card there should be one move 3, two move 2 and three move 1 cards + deck.push(new ProgramCard(priority * 10 + startPriority, 3, Rotate.NONE, "Move 3")); + } else if ((priority + 1) % 6 == 0 || (priority + 2) % 6 == 0) { + deck.push(new ProgramCard(priority * 10 + startPriority, 2, Rotate.NONE, "Move 2")); } else { - if (checker) { - card = new ProgramCard(priority, 2, Rotate.NONE, "Move 2"); - checker = false; - } else { - card = new ProgramCard(priority, 1, Rotate.NONE, "Move 1"); - checker = true; - } + deck.push(new ProgramCard(priority * 10 + startPriority, 1, Rotate.NONE, "Move 1")); } - deck.push(card); - } - // Making the last 6 Move 1 cards - for (int i = 0; i < 6; i++) { - priority += 10; - card = new ProgramCard(priority, 1, Rotate.NONE, "Move 1"); - deck.push(card); } } } diff --git a/src/main/java/inf112/skeleton/app/cards/ProgramCard.java b/src/main/java/inf112/skeleton/app/cards/ProgramCard.java index 3e891c1f..0d9a226e 100644 --- a/src/main/java/inf112/skeleton/app/cards/ProgramCard.java +++ b/src/main/java/inf112/skeleton/app/cards/ProgramCard.java @@ -3,11 +3,11 @@ import inf112.skeleton.app.enums.Rotate; public class ProgramCard { - private int priority; - private int distance; - private String name; + private final int priority; + private final int distance; + private final String name; - private Rotate rotate; + private final Rotate rotate; public ProgramCard(int priority, int distance, Rotate rotate, String name) { this.priority = priority; @@ -28,7 +28,7 @@ public Rotate getRotate() { return rotate; } - public String getName() { - return name; + public String toString() { + return name + ": " + priority; } } diff --git a/src/main/java/inf112/skeleton/app/enums/Direction.java b/src/main/java/inf112/skeleton/app/enums/Direction.java index 44971933..efff143a 100644 --- a/src/main/java/inf112/skeleton/app/enums/Direction.java +++ b/src/main/java/inf112/skeleton/app/enums/Direction.java @@ -24,16 +24,25 @@ public Direction turnRight() { return getDirection(SOUTH, EAST, NORTH, WEST); } + /** + * Turns the {@link Direction} to opposite direction. + * + * @return {@link Direction} after opposite transformation. + */ + public Direction turnAround() { + return getDirection(WEST, SOUTH, EAST, NORTH); + } + /** * Help function instead of duplicate code * * @param baseCaseEAST The direction it's supposed to be if the case is EAST. * @param baseCaseNORTH The direction it's supposed to be if the case is NORTH. * @param baseCaseWEST The direction it's supposed to be if the case is WEST. - * @param baseCaseSOUT The direction it's supposed to be if the case is SOUTH. + * @param baseCaseSOUTH The direction it's supposed to be if the case is SOUTH. * @return The right facing after a given transformation. */ - private Direction getDirection(Direction baseCaseEAST, Direction baseCaseNORTH, Direction baseCaseWEST, Direction baseCaseSOUT) { + private Direction getDirection(Direction baseCaseEAST, Direction baseCaseNORTH, Direction baseCaseWEST, Direction baseCaseSOUTH) { switch (this) { case EAST: return baseCaseEAST; @@ -42,7 +51,7 @@ private Direction getDirection(Direction baseCaseEAST, Direction baseCaseNORTH, case WEST: return baseCaseWEST; case SOUTH: - return baseCaseSOUT; + return baseCaseSOUTH; default: return null; } diff --git a/src/main/java/inf112/skeleton/app/enums/TileID.java b/src/main/java/inf112/skeleton/app/enums/TileID.java index e47dd7ab..a49faa9c 100644 --- a/src/main/java/inf112/skeleton/app/enums/TileID.java +++ b/src/main/java/inf112/skeleton/app/enums/TileID.java @@ -1,44 +1,73 @@ package inf112.skeleton.app.enums; public enum TileID { - STARTPOS1(121), - STARTPOS2(122), - STARTPOS3(123), - STARTPOS4(124), - STARTPOS5(129), - STARTPOS6(130), - STARTPOS7(131), - STARTPOS8(133), - - RIGHT_WALL(23), - DOWN_WALL(29), - LEFT_WALL(30), - UP_WALL(31), - - RIGHT_LASER_WALL(46), - DOWN_LASER_WALL(37), - LEFT_LASER_WALL(38), - UP_LASER_WALL(45), - - SOUTHEASTWALL(8), - NORTHEASTWALL(16), - NORTHWESTWALL(24), - SOUTHWESTWALL(32), + START_POS1(121), + START_POS2(122), + START_POS3(123), + START_POS4(124), + START_POS5(129), + START_POS6(130), + START_POS7(131), + START_POS8(133), + + EAST_WALL(23), + SOUTH_WALL(29), + WEST_WALL(30), + NORTH_WALL(31), + + EAST_LASER_WALL(46), + SOUTH_LASER_WALL(37), + WEST_LASER_WALL(38), + NORTH_LASER_WALL(45), + + SOUTHEAST_WALL(8), + NORTHEAST_WALL(16), + NORTHWEST_WALL(24), + SOUTHWEST_WALL(32), VERTICAL_LASER(47), HORIZONTAL_LASER(39), + CROSSED_LASER(40), + + NORMAL_HOLE(6), + NORMAL_HOLE2(91), + NORTHWEST_HOLE(105), + NORTH_HOLE(106), + NORTHEAST_HOLE(107), + EAST_HOLE(108), + NORTH_EAST_SOUTH_HOLE(109), + WEST_EAST_SOUTH_HOLE(110), + SOUTHWEST_HOLE(113), + SOUTH_HOLE(114), + SOUTHEAST_HOLE(115), + WEST_HOLE(116), + NORTH_WEST_SOUTH_HOLE(117), + NORTH_WEST_EAST_HOLE(118), + + ROTATE_PAD_LEFT(53), + ROTATE_PAD_RIGHT(54), WRENCH(14), - DOUBLE_WRENCH(7); + DOUBLE_WRENCH(7), + + PLAYER_SOUTH(137), + PLAYER_NORTH(138), + PLAYER_EAST(139), + PLAYER_WEST(140), - private int id; + FLAG_1(55), + FLAG_2(63), + FLAG_3(71), + FLAG_4(79); + private final int id; + + TileID(int id) { + this.id = id; + } public int getId() { return this.id; } - private TileID(int id) { - this.id = id; - } } diff --git a/src/main/java/inf112/skeleton/app/objects/Flag.java b/src/main/java/inf112/skeleton/app/objects/Flag.java index d9c95143..708c176c 100644 --- a/src/main/java/inf112/skeleton/app/objects/Flag.java +++ b/src/main/java/inf112/skeleton/app/objects/Flag.java @@ -5,18 +5,18 @@ public class Flag { private final int flagnr; - private Vector2 position; - - public Flag(int flagnr, Vector2 position) { - this.flagnr = flagnr; - this.position = position; - } - + private final Vector2 position; public Flag(int flagnr, int x, int y) { this.flagnr = flagnr; this.position = new Vector2(x, y); } + public Vector2 getPosition() { + return position; + } + public int getFlagnr() { + return flagnr; + } } diff --git a/src/main/java/inf112/skeleton/app/objects/Laser.java b/src/main/java/inf112/skeleton/app/objects/Laser.java new file mode 100644 index 00000000..b8b697c1 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/objects/Laser.java @@ -0,0 +1,37 @@ +package inf112.skeleton.app.objects; + +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.RallyGame; +import inf112.skeleton.app.enums.Direction; + +public class Laser { + + final Vector2 startPosition; + final Direction direction; + + public Laser(int x, int y, Direction direction) { + this.startPosition = new Vector2(x, y); + this.direction = direction; + } + + public void fire(RallyGame game) { + fire(game, startPosition); + } + + public void fire(RallyGame game, Vector2 position) { + game.getBoard().addLaser(position, direction); + if (game.getBoard().hasPlayer(position)) { + game.getBoard().getPlayer(position).handleDamage(game); + } else if (game.getBoard().canGo(position, this.direction)) { + fire(game, game.getBoard().getNeighbourPosition(position, direction)); + } + } + + public Direction getDirection() { + return this.direction; + } + + public Vector2 getStartPosition() { + return this.startPosition; + } +} diff --git a/src/main/java/inf112/skeleton/app/objects/RotatePad.java b/src/main/java/inf112/skeleton/app/objects/RotatePad.java new file mode 100644 index 00000000..fa57ab57 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/objects/RotatePad.java @@ -0,0 +1,23 @@ +package inf112.skeleton.app.objects; + +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.enums.Rotate; + +public class RotatePad { + private final Rotate rotate; + private final Vector2 position; + + public RotatePad(Rotate rotate, Vector2 vector) { + this.rotate = rotate; + this.position = vector; + } + + public Rotate getRotate() { + return rotate; + } + + + public Vector2 getPosition() { + return position; + } +} diff --git a/src/main/java/inf112/skeleton/app/screens/GameScreen.java b/src/main/java/inf112/skeleton/app/screens/GameScreen.java index 4bdc9cf1..0328a27d 100644 --- a/src/main/java/inf112/skeleton/app/screens/GameScreen.java +++ b/src/main/java/inf112/skeleton/app/screens/GameScreen.java @@ -1,69 +1,62 @@ package inf112.skeleton.app.screens; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Screen; import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.maps.tiled.TiledMapRenderer; import com.badlogic.gdx.maps.tiled.renderers.OrthogonalTiledMapRenderer; -import inf112.skeleton.app.Board; import inf112.skeleton.app.RallyGame; -public class GameScreen implements Screen { +public class GameScreen extends StandardScreen { - private final RallyGame game; - private final Board board; - - private OrthographicCamera camera; - private TiledMapRenderer mapRenderer; + private final TiledMapRenderer mapRenderer; + private final Texture lifeTokens; + private final Texture damageTokens; + private float tokensX; + private float lifeTokensY; + private float damageTokensY; + private float tokensSize; public GameScreen(final RallyGame game) { - camera = new OrthographicCamera(); - - this.game = game; - this.board = game.getBoard(); - - camera.setToOrtho(false, board.getWidth() * 300, board.getHeight() * 300); + super(game); + lifeTokens = new Texture("assets/images/lifeToken.png"); + damageTokens = new Texture("assets/images/damageToken.png"); + super.camera.setToOrtho(false, game.board.getWidth() * 400, game.board.getHeight() * 400); this.mapRenderer = new OrthogonalTiledMapRenderer(game.getBoard().getMap()); mapRenderer.setView(camera); - } - - @Override - public void show() { - + updateTokens(); } @Override public void render(float v) { - Gdx.gl.glClearColor(v, v, v, 0); Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + renderSettings(v); - camera.update(); - game.batch.setProjectionMatrix(camera.combined); - - game.batch.begin(); + updateTokens(); mapRenderer.render(); - game.batch.end(); + batch.begin(); + renderLifeTokens(); + renderDamageTokens(); + batch.end(); } - @Override - public void resize(int i, int i1) { + public void updateTokens() { + tokensSize = camera.viewportHeight / 8; + tokensX = 10; + lifeTokensY = camera.viewportHeight - tokensSize; + damageTokensY = lifeTokensY - tokensSize; } - @Override - public void pause() { - } - - @Override - public void resume() { + public void renderDamageTokens() { + for (int i = 0; i < game.mainPlayer.getDamageTokens(); i++) { + batch.draw(damageTokens, tokensX + i * tokensSize, damageTokensY, tokensSize, tokensSize); + } } - @Override - public void hide() { - } - - @Override - public void dispose() { + public void renderLifeTokens() { + for (int i = 0; i < game.mainPlayer.getLifeTokens(); i++) { + batch.draw(lifeTokens, tokensX + i * tokensSize, lifeTokensY, tokensSize, tokensSize); + } } } diff --git a/src/main/java/inf112/skeleton/app/screens/GifScreen.java b/src/main/java/inf112/skeleton/app/screens/GifScreen.java new file mode 100644 index 00000000..0d353590 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/screens/GifScreen.java @@ -0,0 +1,32 @@ +package inf112.skeleton.app.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.g2d.Animation; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import inf112.skeleton.app.GifDecoder; +import inf112.skeleton.app.RallyGame; + +public class GifScreen extends StandardScreen { + + private final Animation animation; + private float elapsed; + + public GifScreen(final RallyGame game) { + super(game); + this.animation = GifDecoder.loadGIFAnimation(Animation.PlayMode.LOOP, Gdx.files.internal("assets/images/optimusBoi.gif").read()); + } + + @Override + public void render(float v) { + renderSettings(v); + + elapsed += Gdx.graphics.getDeltaTime(); + batch.begin(); + batch.draw(animation.getKeyFrame(elapsed), 0, 0, camera.viewportWidth, camera.viewportHeight); + batch.end(); + if (animation.isAnimationFinished(elapsed)) { + this.dispose(); + game.setScreen(new YouWinScreen(game)); + } + } +} diff --git a/src/main/java/inf112/skeleton/app/screens/LoadingScreen.java b/src/main/java/inf112/skeleton/app/screens/LoadingScreen.java new file mode 100644 index 00000000..0db8d3d1 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/screens/LoadingScreen.java @@ -0,0 +1,34 @@ +package inf112.skeleton.app.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.graphics.Texture; +import inf112.skeleton.app.RallyGame; + +public class LoadingScreen extends StandardScreen { + + private final Texture background; + public LoadingScreen(final RallyGame game) { + super(game); + background = new Texture("assets/images/RoboRallyMenuScreen.png"); + } + + @Override + public void render(float v) { + renderSettings(v); + + batch.begin(); + batch.draw(background, 0, 0, camera.viewportWidth, camera.viewportHeight); + batch.end(); + + if (Gdx.input.isTouched()) { + game.dispose(); + game.setScreen(new MenuScreen(game)); + } + } + + @Override + public void dispose() { + background.dispose(); + super.dispose(); + } +} diff --git a/src/main/java/inf112/skeleton/app/screens/MenuScreen.java b/src/main/java/inf112/skeleton/app/screens/MenuScreen.java index 5633e2d1..7b761eb3 100644 --- a/src/main/java/inf112/skeleton/app/screens/MenuScreen.java +++ b/src/main/java/inf112/skeleton/app/screens/MenuScreen.java @@ -1,66 +1,140 @@ package inf112.skeleton.app.screens; import com.badlogic.gdx.Gdx; -import com.badlogic.gdx.Screen; -import com.badlogic.gdx.graphics.GL20; -import com.badlogic.gdx.graphics.OrthographicCamera; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.scenes.scene2d.Stage; +import com.badlogic.gdx.scenes.scene2d.ui.SelectBox; +import com.badlogic.gdx.scenes.scene2d.ui.Skin; +import com.badlogic.gdx.utils.Array; import inf112.skeleton.app.RallyGame; -public class MenuScreen implements Screen { +import java.io.File; +import java.util.Objects; - private final RallyGame game; - private OrthographicCamera camera; - private Texture background; +public class MenuScreen extends StandardScreen { - public MenuScreen(final RallyGame game) { - this.game = game; - this.background = new Texture("assets/RoboRallyMenuScreen.png"); - camera = new OrthographicCamera(); - camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight()); + private float BUTTON_WIDTH; + private float BUTTON_HEIGHT; + private float BUTTON_X; + private float START_BUTTON_Y; + private float EXIT_BUTTON_Y; + + public final SelectBox selectMap; + + private final Texture background; + private final Texture startButtonInactive; + private final Texture startButtonActive; + private final Texture exitButtonInactive; + private final Texture exitButtonActive; + + private final Stage stage; + public String select; + + public MenuScreen(RallyGame game) { + super(game); + stage = new Stage(); + Skin skin = new Skin(Gdx.files.internal("assets/skins/uiskin.json")); + + updateButtons(); + + background = new Texture("assets/images/GUI_Edited.jpg"); + startButtonActive = new Texture("assets/images/Start_Button.png"); + startButtonInactive = new Texture("assets/images/Start_Button_Active.png"); + exitButtonInactive = new Texture("assets/images/Exit_Button_Active.png"); + exitButtonActive = new Texture("assets/images/Exit_Button_Inactive.png"); + + selectMap = new SelectBox<>(skin); + selectMap.setItems(getMaps()); + selectMap.setSelected("assets/maps/Risky_Exchange.tmx"); + selectMap.setWidth(BUTTON_WIDTH * .87f); + selectMap.setPosition(BUTTON_X - selectMap.getWidth(), START_BUTTON_Y - BUTTON_HEIGHT / 2); + + stage.addActor(selectMap); + } + + private Array getMaps() { + Array mapArray = new Array<>(); + File maps = new File("assets/maps"); + for (String fileType : Objects.requireNonNull(maps.list())) { + if (fileType.endsWith(".tmx")) { + mapArray.add(fileType.substring(0, fileType.length() - 4)); + } + } + return mapArray; + } + + public void updateButtons() { + BUTTON_WIDTH = (float) (Gdx.graphics.getWidth() / 4.0); + BUTTON_HEIGHT = (float) (Gdx.graphics.getHeight() / 4.0); + START_BUTTON_Y = (float) (Gdx.graphics.getHeight() / 2.0); + EXIT_BUTTON_Y = (float) (Gdx.graphics.getHeight() / 2.0 - BUTTON_HEIGHT); + BUTTON_X = (float) (Gdx.graphics.getWidth() / 2.0 - BUTTON_WIDTH / 2); } @Override public void show() { + Gdx.input.setInputProcessor(stage); + render(0); } @Override public void render(float v) { - Gdx.gl.glClearColor(255, 0, 0, 1); - Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + renderSettings(v); + updateButtons(); - camera.update(); - game.batch.setProjectionMatrix(camera.combined); + batch.begin(); + batch.draw(background, 0, 0, camera.viewportWidth, camera.viewportHeight); - game.batch.begin(); - game.batch.draw(background, 0, 0, camera.viewportWidth, camera.viewportHeight); - game.batch.end(); + if (mouseOnExit()) { + batch.draw(exitButtonActive, BUTTON_X, EXIT_BUTTON_Y, BUTTON_WIDTH, BUTTON_HEIGHT); + if (Gdx.input.isTouched()) { + Gdx.app.exit(); + } + } else { + batch.draw(exitButtonInactive, BUTTON_X, EXIT_BUTTON_Y, BUTTON_WIDTH, BUTTON_HEIGHT); + } - if (Gdx.input.isTouched()) { - game.setScreen(new GameScreen(game)); - dispose(); + if (mouseOnStart()) { + batch.draw(startButtonActive, BUTTON_X, START_BUTTON_Y, BUTTON_WIDTH, BUTTON_HEIGHT); + if (Gdx.input.isTouched()) { + game.setupGame("assets/maps/" + getBoard() + ".tmx"); + this.dispose(); + game.setScreen(new GameScreen(game)); + } + } else { + batch.draw(startButtonInactive, BUTTON_X, START_BUTTON_Y, BUTTON_WIDTH, BUTTON_HEIGHT); } + + batch.end(); + stage.act(v); + stage.draw(); } - @Override - public void resize(int i, int i1) { + public String getBoard() { + select = selectMap.getSelected(); + return select; } - @Override - public void pause() { + private boolean mouseOnButton(float buttonY) { + return Gdx.input.getX() < BUTTON_X + BUTTON_WIDTH && + Gdx.input.getX() > BUTTON_X && + camera.viewportHeight - Gdx.input.getY() < buttonY + BUTTON_HEIGHT && + camera.viewportHeight - Gdx.input.getY() > buttonY; } - @Override - public void resume() { + private boolean mouseOnExit() { + return mouseOnButton(EXIT_BUTTON_Y); } - @Override - public void hide() { + private boolean mouseOnStart() { + return mouseOnButton(START_BUTTON_Y); } @Override public void dispose() { + stage.dispose(); background.dispose(); + super.dispose(); } } diff --git a/src/main/java/inf112/skeleton/app/screens/StandardScreen.java b/src/main/java/inf112/skeleton/app/screens/StandardScreen.java new file mode 100644 index 00000000..a94322cb --- /dev/null +++ b/src/main/java/inf112/skeleton/app/screens/StandardScreen.java @@ -0,0 +1,65 @@ +package inf112.skeleton.app.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Screen; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.graphics.OrthographicCamera; +import com.badlogic.gdx.graphics.g2d.SpriteBatch; +import inf112.skeleton.app.RallyGame; + +public abstract class StandardScreen implements Screen { + protected final RallyGame game; + protected final OrthographicCamera camera; + protected final SpriteBatch batch; + + public StandardScreen(final RallyGame game) { + this.game = game; + this.batch = new SpriteBatch(); + this.camera = new OrthographicCamera(); + this.camera.setToOrtho(false); + } + + @Override + public void show() { + // Empty functions gives bad code quality + } + + @Override + public void render(float v) { + // Empty functions gives bad code quality + } + + public void renderSettings(float v) { + Gdx.gl.glClearColor(v, v, v, 1); + Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT); + + camera.setToOrtho(false); + camera.update(); + batch.setProjectionMatrix(camera.combined); + } + + @Override + public void resize(int i, int i1) { + // Empty functions gives bad code quality + } + + @Override + public void pause() { + // Empty functions gives bad code quality + } + + @Override + public void resume() { + // Empty functions gives bad code quality + } + + @Override + public void hide() { + // Empty functions gives bad code quality + } + + @Override + public void dispose() { + batch.dispose(); + } +} diff --git a/src/main/java/inf112/skeleton/app/screens/YouWinScreen.java b/src/main/java/inf112/skeleton/app/screens/YouWinScreen.java new file mode 100644 index 00000000..2c929d13 --- /dev/null +++ b/src/main/java/inf112/skeleton/app/screens/YouWinScreen.java @@ -0,0 +1,36 @@ +package inf112.skeleton.app.screens; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.Input; +import com.badlogic.gdx.graphics.Texture; +import inf112.skeleton.app.RallyGame; + +public class YouWinScreen extends StandardScreen { + + private final Texture background; + + public YouWinScreen(final RallyGame game) { + super(game); + + background = new Texture("assets/images/YouWin.png"); + } + + @Override + public void render(float v) { + renderSettings(v); + + batch.begin(); + batch.draw(background, 0, 0, camera.viewportWidth, camera.viewportHeight); + batch.end(); + + if (Gdx.input.isKeyPressed(Input.Keys.ESCAPE)) { + Gdx.app.exit(); + } + } + + @Override + public void dispose() { + background.dispose(); + super.dispose(); + } +} diff --git a/src/test/java/inf112/skeleton/app/BoardTest.java b/src/test/java/inf112/skeleton/app/BoardTest.java index 92dc42fc..4362d675 100644 --- a/src/test/java/inf112/skeleton/app/BoardTest.java +++ b/src/test/java/inf112/skeleton/app/BoardTest.java @@ -4,9 +4,14 @@ import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.math.Vector2; import inf112.skeleton.app.enums.Direction; +import inf112.skeleton.app.objects.Flag; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.Random; + import static org.junit.Assert.*; import static org.mockito.Mockito.mock; @@ -14,10 +19,14 @@ public class BoardTest { private Board board; - private final int NUMBER_OF_PLAYERS_WHEN_STARTING_GAME = 2; + private final int NUMBER_OF_PLAYERS_WHEN_STARTING_GAME = 0; private final int BOARD_WIDTH = 16; private final int BOARD_HEIGHT = 12; private Player player; + private Random random; + private ArrayList holes; + private Vector2 startPosition; + private ArrayList flags; @Before public void setUp() { @@ -26,43 +35,340 @@ public void setUp() { Gdx.gl = mock(GL20.class); //Make a headless application in order to initialize the board. Does not show. new HeadlessApplication(new EmptyApplication()); - this.board = new Board("assets/Risky_Exchange.tmx"); - this.player = new Player(new Vector2(0,0), 1); + this.board = new Board("assets/maps/Risky_Exchange.tmx", NUMBER_OF_PLAYERS_WHEN_STARTING_GAME); + // Random position + this.startPosition = new Vector2(5,5); + this.player = new Player(startPosition, 1); + this.holes = board.holes; + this.flags = board.flags; + // Sort the flags so player can go on them in correct order + flags.sort(Comparator.comparingInt(Flag::getFlagnr)); + this.random = new Random(); + } + + /** + * @param flag1 first flag + * @param flag2 second flag + * @return true if two flags are equal + */ + private boolean isEqualFlags(Flag flag1, Flag flag2) { + if (flag1 == null || flag2 == null) { + return false; + } + return flag1.getFlagnr() == flag2.getFlagnr() && flag1.getPosition().equals(flag2.getPosition()); + } + + /** + * @return a random hole position + */ + private Vector2 getRandomHolePosition() { + int randomIndex = random.nextInt(holes.size()); + return holes.get(randomIndex); + } + + /** + * @return Flag a random flag + */ + private Flag getRandomFlag() { + int randomIndex = random.nextInt(flags.size()); + return flags.get(randomIndex); + } + + /** + * + * @return true if player is on backupPosition and has backupDirection + */ + private boolean isInBackupState(Player player) { + return player.getPosition().equals(player.getBackupPosition()) && player.getDirection().equals(player.getBackupDirection()); } + @Test + public void canNotAddSamePlayerOnBoardTest() { + board.addPlayer(player); + board.addPlayer(player); + assertEquals(1, board.getPlayers().size()); + } @Test - public void whenBoardIsInitializedMapIsNotNullTest() { + public void boardHasAMapTest() { assertNotNull(board.getMap()); } @Test - public void whenBoardIsInitializedItHasCorrectNumberOfPlayersTest() { + public void correctNumbersOfPlayersOnBoardTest() { assertEquals(NUMBER_OF_PLAYERS_WHEN_STARTING_GAME, board.getPlayers().size()); } @Test - public void whenAPlayerIsAddedTheBoardHasIncrementedPlayersByOneTest() { - board.addPlayer(0,0, 1); + public void aPlayerIsAddedToTheBoardIncrementPlayersTest() { + board.addPlayer(player); assertEquals(NUMBER_OF_PLAYERS_WHEN_STARTING_GAME + 1, board.getPlayers().size()); } @Test - public void whenBoardIsInitBoardWidthIsTheSameAsExpectedTest() { + public void boardInitializedWithCorrectWidthTest() { assertEquals(BOARD_WIDTH, board.getWidth()); } @Test - public void whenBoardIsInitBoardHeightIsTheSameAsExpectedTest() { + public void boardInitializedWithCorrectHeightTest() { assertEquals(BOARD_HEIGHT, board.getHeight()); } + + @Test + public void playerIsOutsideOfUpperBorderTest() { + player.setPosition(new Vector2(0, BOARD_HEIGHT)); + assertTrue(board.outsideBoard(player)); + } + + @Test + public void playerIsOutsideOfRightBorderTest() { + player.setPosition(new Vector2(BOARD_WIDTH, 0)); + assertTrue(board.outsideBoard(player)); + } + + @Test + public void playerIsOutsideOfLeftBorderTest() { + player.setPosition(new Vector2(-1, 0)); + assertTrue(board.outsideBoard(player)); + } + + @Test + public void playerIsUnderBorderTest() { + player.setPosition(new Vector2(0, -1)); + assertTrue(board.outsideBoard(player)); + } + @Test - public void whenPlayerIsMovedPlayerHasChangedCoordinatesTest() { + public void playerOutsideBoardIsRespawnedTest() { + Vector2 outsideOfBoardPosition = new Vector2(-1, 0); + player.setPosition(outsideOfBoardPosition); + board.addPlayer(player); + board.respawnPlayers(); + assertTrue(isInBackupState(player)); + } + + + @Test + public void movedPlayerHasChangedCoordinatesTest() { Vector2 startPosition = new Vector2(player.getPosition().x, player.getPosition().y); player.setDirection(Direction.EAST); board.movePlayer(player); assertNotEquals(startPosition, player.getPosition()); } + @Test + public void whenPlayerIsMovedUpItHasMovedOneStepTest() { + Vector2 startPosition = new Vector2(player.getPosition().x, player.getPosition().y); + player.setDirection(Direction.NORTH); + board.movePlayer(player); + assertEquals((int) startPosition.y+1, (int) player.getPosition().y); + } + + @Test + public void thereAreHolesOnBoardTest() { + assertFalse(holes.isEmpty()); + } + + @Test + public void playerOnRandomHoleIsOutsideBoardTest() { + // Choose some random holes + for (int i = 0; i < 5; i++) { + Vector2 holePosition = getRandomHolePosition(); + player.setPosition(holePosition); + assertTrue(board.outsideBoard(player)); + } + } + + @Test + public void playerOnRandomHoleIsRespawnedTest() { + // Choose some random holes + for (int i = 0; i < 5; i++) { + Vector2 holePosition = getRandomHolePosition(); + player.setPosition(holePosition); + board.addPlayer(player); + board.respawnPlayers(); + assertTrue(isInBackupState(player)); + } + } + + @Test + public void getWestNeighbourPositionTest() { + Vector2 neighbourPosition = new Vector2(startPosition.x -1, startPosition.y); + assertEquals(neighbourPosition, board.getNeighbourPosition(startPosition, Direction.WEST)); + } + + @Test + public void getEastNeighbourPositionTest() { + Vector2 neighbourPosition = new Vector2(startPosition.x +1, startPosition.y); + assertEquals(neighbourPosition, board.getNeighbourPosition(startPosition, Direction.EAST)); + } + + @Test + public void getSouthNeighbourPositionTest() { + Vector2 neighbourPosition = new Vector2(startPosition.x, startPosition.y - 1); + assertEquals(neighbourPosition, board.getNeighbourPosition(startPosition, Direction.SOUTH)); + } + + @Test + public void getNorthNeighbourPositionTest() { + Vector2 neighbourPosition = new Vector2(startPosition.x, startPosition.y + 1); + assertEquals(neighbourPosition, board.getNeighbourPosition(startPosition, Direction.NORTH)); + } + + @Test + public void flagIsOnFlagPositionOnBoardTest() { + for (int i = 0; i < 5; i++) { + Flag flag = getRandomFlag(); + Vector2 flagPosition = flag.getPosition(); + assertTrue(board.hasFlag(flagPosition)); + } + } + + @Test + public void playerPicksUpFirstFlagTest() { + Flag flag = flags.get(0); + Vector2 flagPosition = flag.getPosition(); + player.setPosition(flagPosition); + board.pickUpFlag(player); + assertTrue(isEqualFlags(flag, player.getFlagsCollected().get(0))); + } + + @Test + public void canNotPickUpFlagNumberTwoBeforeFlagNumberOneTest() { + // Get flag nr. 2 + Flag flag = flags.get(1); + Vector2 flagPosition = flag.getPosition(); + player.setPosition(flagPosition); + board.pickUpFlag(player); + assertEquals(0, player.getFlagsCollected().size()); + } + + @Test + public void canNotPickUpFlagNumberThreeBeforeFlagNumberTwoTest() { + Flag firstFlag = flags.get(0); + player.setPosition(firstFlag.getPosition()); + board.pickUpFlag(player); + Flag thirdFlag = flags.get(2); + player.setPosition(thirdFlag.getPosition()); + board.pickUpFlag(player); + assertEquals(1, player.getFlagsCollected().size()); + } + + @Test + public void playerMovesOnFlagTest() { + Flag flag = flags.get(0); + Vector2 flagPosition = flag.getPosition(); + Vector2 playerPosition = new Vector2(flagPosition.x -1, flagPosition.y); + player.setPosition(playerPosition); + player.setDirection(Direction.EAST); + board.movePlayer(player); + assertTrue(isEqualFlags(flag, player.getFlagsCollected().get(0))); + } + + @Test + public void pickingUpAllFlagsInIncreasingOrderYouWinTest() { + // Visit flags 1, 2, and 3 + for (int flagNumber = 1; flagNumber <=3; flagNumber++) { + Flag flag = flags.get(flagNumber-1); + Vector2 flagPosition = flag.getPosition(); + player.setPosition(flagPosition); + board.pickUpFlag(player); + } + assertTrue(player.hasAllFlags(3)); + } + + @Test + public void facingNeighbourPlayerShouldPushTest() { + Vector2 playerToBePushedPosition = new Vector2(0,0); + player.setPosition(playerToBePushedPosition); + Vector2 playerTwoPos = new Vector2(1, 0); + Player player2 = new Player(playerTwoPos, 2); + player2.setDirection(Direction.WEST); + board.addPlayer(player); + assertTrue(board.shouldPush(player2)); + } + + @Test + public void pushedPlayerIsReplacedByPlayerThatIsPushingTest() { + Vector2 playerToBePushedPosition = new Vector2(1, 0); + player.setPosition(playerToBePushedPosition); + Vector2 playerTwoPos = new Vector2(0,0); + Player player2 = new Player(playerTwoPos, 2); + player2.setDirection(Direction.EAST); + board.addPlayer(player); + board.movePlayer(player2); + assertEquals(player2, board.getPlayer(playerToBePushedPosition)); + } + + @Test + public void pushedPlayerMovesInSameDirectionAsItIsPushedTest() { + Vector2 playerToBePushedPosition = new Vector2(1, 0); + Vector2 playerIsPushedToPosition = new Vector2(2,0); + player.setPosition(playerToBePushedPosition); + // Set different direction then it is pushed in + player.setDirection(Direction.NORTH); + Vector2 playerTwoPos = new Vector2(0,0); + Player player2 = new Player(playerTwoPos, 2); + player2.setDirection(Direction.EAST); + board.addPlayer(player); + board.movePlayer(player2); + assertEquals(player, board.getPlayer(playerIsPushedToPosition)); + } + + @Test + public void pushingTwoPlayersInSameDirectionTest() { + // line 6 from bottom up has no walls in Risky-Exchange: + Vector2 playerToBePushedPositionOne = new Vector2(2, 6); + Vector2 playerToBePushedPositionTwo = new Vector2(3, 6); + Vector2 playerPushingPosition = new Vector2(4, 6); + Vector2 positionToBePushedTo = new Vector2(1, 6); + Player player2 = new Player(playerToBePushedPositionOne, 2); + Player player3 = new Player(playerToBePushedPositionTwo, 3); + // Random directions + player2.setDirection(Direction.EAST); + player3.setDirection(Direction.SOUTH); + player.setPosition(playerPushingPosition); + player.setDirection(Direction.WEST); + board.addPlayer(player2); + board.addPlayer(player3); + board.movePlayer(player); + assertEquals(player2, board.getPlayer(positionToBePushedTo)); + } + + @Test + public void wallStopsPushingTest() { + // Found wall in Risky Exhange + Vector2 northWallPosition = new Vector2(0, 5); + Player player2 = new Player(northWallPosition, 2); + player2.setDirection(Direction.WEST); + Vector2 playerPushingPosition = new Vector2(0,4); + player.setPosition(playerPushingPosition); + player.setDirection(Direction.NORTH); + board.addPlayer(player2); + board.addPlayer(player); + board.movePlayer(player); + assertEquals(player2, board.getPlayer(northWallPosition)); + } + + @Test + public void wallStopsPushingSeveralPlayersTest() { + // Found wall in Risky Exhange + Vector2 northWallPosition = new Vector2(0, 5); + Vector2 middlePosition = new Vector2(0, 4); + Player playerToBeStoppedByWall = new Player(northWallPosition, 2); + Player playerInMiddle = new Player(middlePosition, 3); + playerToBeStoppedByWall.setDirection(Direction.WEST); + playerInMiddle.setDirection(Direction.SOUTH); + Vector2 playerPushingPosition = new Vector2(0,3); + player.setPosition(playerPushingPosition); + player.setDirection(Direction.NORTH); + board.addPlayer(playerToBeStoppedByWall); + board.addPlayer(playerInMiddle); + board.addPlayer(player); + board.movePlayer(player); + assertEquals(playerToBeStoppedByWall, board.getPlayer(northWallPosition)); + } + } diff --git a/src/test/java/inf112/skeleton/app/DeckTest.java b/src/test/java/inf112/skeleton/app/DeckTest.java index 3dd171b2..def5b97e 100644 --- a/src/test/java/inf112/skeleton/app/DeckTest.java +++ b/src/test/java/inf112/skeleton/app/DeckTest.java @@ -9,7 +9,6 @@ public class DeckTest { private Deck deck; - private final int NUMBER_OF_MOVE_ONE_CARDS = 6; private final int NUMBER_OF_CARDS = 78; @Before @@ -25,15 +24,7 @@ public void whenNewDeckIsMadeTheNumberOfProgramCardsInDeckIsNumberOfCardsTest() @Test public void whenNewDeckIsMadeButNotShuffledFirstCardIsAMove1CardTest() { deck.makeNewDeck(); - assertEquals(1, deck.drawCard().getDistance()); - } - - @Test - public void whenDeckIsNotShuffledTheFirstCardsAreOfTypeMoveOneCardTest() { - deck.makeNewDeck(); - for (int i = 0; i < NUMBER_OF_MOVE_ONE_CARDS; i++) { - assertEquals(1, deck.drawCard().getDistance()); - } + assertEquals(3, deck.drawCard().getDistance()); } @Test diff --git a/src/test/java/inf112/skeleton/app/DirectionTest.java b/src/test/java/inf112/skeleton/app/DirectionTest.java index 90040375..4465e2d9 100644 --- a/src/test/java/inf112/skeleton/app/DirectionTest.java +++ b/src/test/java/inf112/skeleton/app/DirectionTest.java @@ -5,7 +5,6 @@ import org.junit.Test; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; public class DirectionTest { diff --git a/src/test/java/inf112/skeleton/app/LaserTest.java b/src/test/java/inf112/skeleton/app/LaserTest.java new file mode 100644 index 00000000..22d361d3 --- /dev/null +++ b/src/test/java/inf112/skeleton/app/LaserTest.java @@ -0,0 +1,85 @@ +package inf112.skeleton.app; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.objects.Laser; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Random; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; + +public class LaserTest { + + private RallyGame game; + private Board board; + private ArrayList lasers; + + @Before + public void setUp() { + Gdx.gl = mock(GL20.class); + //Make a headless application in order to initialize the board. Does not show. + new HeadlessApplication(new EmptyApplication()); + this.game = new RallyGame(); + this.game.setupGame("assets/maps/Risky_Exchange.tmx"); + this.board = game.getBoard(); + this.lasers = board.lasers; + } + + /** + * @param lasers on board + * @return random laser laser from list given + */ + private Laser getRandomLaser(ArrayList lasers) { + Random random = new Random(); + int randomIndex = random.nextInt(lasers.size()); + return lasers.get(randomIndex); + } + + /** + * @param position to check for laser + * @return true if cell in this position from laserLayer has a laser on this cell. + */ + private boolean hasLaser(Vector2 position) { + TiledMapTileLayer laserLayer = board.getLaserLayer(); + TiledMapTileLayer.Cell cell = laserLayer.getCell((int) position.x, (int) position.y); + return cell != null; + } + + @Test + public void thereAreLasersOnBoardTest() { + assertFalse(lasers.isEmpty()); + } + + @Test + public void lasersFiredHasLasersInStartPositionTest() { + game.fireLasers(); + for (int i = 0; i < 3; i++) { + Laser laser = getRandomLaser(lasers); + Vector2 laserPosition = laser.getStartPosition(); + assertTrue(hasLaser(laserPosition)); + } + } + + @Test + public void playerBlockingLaserTest() { + for (int i = 0; i < 3; i++) { + Laser laser = getRandomLaser(lasers); + Vector2 blockingPosition = board.getNeighbourPosition(laser.getStartPosition(), laser.getDirection()); + //TODO: Let RallyGame take in number of players as arg + Player blockingPlayer = new Player(blockingPosition, 5); + board.addPlayer(blockingPlayer); + game.fireLasers(); + Vector2 noLaserPosition = board.getNeighbourPosition(blockingPosition, laser.getDirection()); + assertFalse(hasLaser(noLaserPosition)); + } + } + +} diff --git a/src/test/java/inf112/skeleton/app/ProgramCardTest.java b/src/test/java/inf112/skeleton/app/ProgramCardTest.java index 71edb020..4e0e42aa 100644 --- a/src/test/java/inf112/skeleton/app/ProgramCardTest.java +++ b/src/test/java/inf112/skeleton/app/ProgramCardTest.java @@ -1,24 +1,154 @@ package inf112.skeleton.app; +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.cards.Deck; import inf112.skeleton.app.cards.ProgramCard; +import inf112.skeleton.app.enums.Direction; import inf112.skeleton.app.enums.Rotate; import org.junit.Before; import org.junit.Test; +import java.util.ArrayList; + import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; public class ProgramCardTest { - private ProgramCard card; + private Deck deck; + private RallyGame game; + private Player player; + private ProgramCard right; + private ProgramCard left; + private ProgramCard uturn; + private ProgramCard moveOne; + private ProgramCard moveTwo; @Before public void setUp() { - card = new ProgramCard(1, 1, Rotate.NONE, "card1"); + Gdx.gl = mock(GL20.class); + //Make a headless application in order to initialize the board. Does not show. + new HeadlessApplication(new EmptyApplication()); + this.game = new RallyGame(); + this.game.setupGame("assets/maps/Risky_Exchange.tmx"); + + // Already 4 players on board. + //TODO: Let setupGame take in playerNumber as arg + player = new Player(new Vector2(0,0), 5); + player.setDirection(Direction.EAST); + Board board = game.getBoard(); + board.addPlayer(player); + this.deck = new Deck(); + this.left = new ProgramCard(10, 0, Rotate.LEFT, "left"); + this.right = new ProgramCard(10, 0, Rotate.RIGHT, "right"); + this.uturn = new ProgramCard(10, 0, Rotate.UTURN, "uturn"); + this.moveOne = new ProgramCard(10, 1, Rotate.NONE, "move 1"); + this.moveTwo = new ProgramCard(10, 2, Rotate.NONE, "move 2"); + } + + @Test + public void playerGetNineCardsWhenDrawingCardsTest() { + player.drawCards(deck); + assertEquals(9, player.getAllCards().size()); + } + + @Test + public void canChooseFiveCardsFromDrawnCardsTest() { + player.drawCards(deck); + player.selectCards(); + assertEquals(5, player.getSelectedCards().size()); + } + + @Test + public void playingUturnCardTest() { + player.setSelectedCards(uturn); + game.playCard(player); + assertEquals(Direction.WEST, player.getDirection()); + } + + @Test + public void playingRightRotateCardTest() { + player.setSelectedCards(right); + game.playCard(player); + assertEquals(Direction.SOUTH, player.getDirection()); + } + + @Test + public void playingLeftRotateCardTest() { + player.setSelectedCards(left); + game.playCard(player); + assertEquals(Direction.NORTH, player.getDirection()); + } + + @Test + public void playingMoveOneStepCardTest() { + player.setSelectedCards(moveOne); + Vector2 beforePosition = player.getPosition(); + Vector2 afterPosition = new Vector2(beforePosition.x + 1, beforePosition.y); + game.playCard(player); + assertEquals(afterPosition, player.getPosition()); + } + + @Test + public void firstRotateThenMoveToCorrectPositionTest() { + player.setSelectedCards(left, moveOne); + Vector2 beforePosition = player.getPosition(); + // Player is rotated left and therefore player will go up instead of to the right + Vector2 afterPosition = new Vector2(beforePosition.x, beforePosition.y+1); + game.playCard(player); + game.playCard(player); + assertEquals(afterPosition, player.getPosition()); + } + + @Test + public void firstMoveThenRotateToCorrectRotationTest() { + player.setSelectedCards(moveTwo, right); + game.playCard(player); + game.playCard(player); + assertEquals(Direction.SOUTH, player.getDirection()); + } + + @Test + public void prioritizedCardsArePlayedFirstTest() { + Player player2 = new Player(new Vector2(0, 1), 6); + ProgramCard highPrioCard = new ProgramCard(10, 0, Rotate.LEFT, "left"); + ProgramCard lowPrioCard = new ProgramCard(1, 0, Rotate.RIGHT, "right"); + ArrayList players = new ArrayList<>(); + player.setSelectedCards(lowPrioCard); + player2.setSelectedCards(highPrioCard); + players.add(player); + players.add(player2); + players.sort(new PlayerSorter()); + assertEquals(player2, players.get(0)); + } + + /** + * Starting at east, a sequence of right, left, left, uturn, right, uturn, right should give south. + */ + @Test + public void sequenceOfRotateCardsTest() { + player.setSelectedCards(right, left, left, uturn, right, uturn, right); + for (int playedCards = 0; playedCards <= 6; playedCards++) { + game.playCard(player); + } + assertEquals(Direction.SOUTH, player.getDirection()); } + /** + * Starting at (0,0) east, move one, rotate left, move two, rotate right, move one, turn around, move two should give + * (0, 2) + */ @Test - public void whenRotationIsSetToNoneItHasNoRotationTest() { - assertEquals(Rotate.NONE, card.getRotate()); + public void sequenceOfCardsTest() { + player.setSelectedCards(moveOne, left, moveTwo, right, moveOne, uturn, moveTwo); + Vector2 afterPosition = new Vector2(0,2); + for (int playedCards = 0; playedCards <= 6; playedCards++) { + game.playCard(player); + } + assertEquals(afterPosition, player.getPosition()); } } diff --git a/src/test/java/inf112/skeleton/app/RotatePadTest.java b/src/test/java/inf112/skeleton/app/RotatePadTest.java new file mode 100644 index 00000000..06d7ef73 --- /dev/null +++ b/src/test/java/inf112/skeleton/app/RotatePadTest.java @@ -0,0 +1,127 @@ +package inf112.skeleton.app; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.enums.Direction; +import inf112.skeleton.app.enums.Rotate; +import inf112.skeleton.app.objects.RotatePad; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Random; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.mockito.Mockito.mock; + +/** + * Test right and left rotate-wheels. Can not find any uturn-pads. + */ +public class RotatePadTest { + + private RallyGame game; + private ArrayList rotatePads; + private Player player; + + @Before + public void setUp() { + Gdx.gl = mock(GL20.class); + //Make a headless application in order to initialize the board. Does not show. + new HeadlessApplication(new EmptyApplication()); + this.game = new RallyGame(); + this.game.setupGame("assets/maps/Risky_Exchange.tmx"); + Board board = game.getBoard(); + this.rotatePads = board.rotatePads; + + // Already 4 players on board. + //TODO: Let setupGame take in playerNumber as arg + player = new Player(new Vector2(0,0), 5); + board.addPlayer(player); + } + + /** + * @return a random rotatePad from the list given + */ + private RotatePad getRandomRotatePad(ArrayList rotatePads) { + Random random = new Random(); + int randomIndex = random.nextInt(rotatePads.size()); + return rotatePads.get(randomIndex); + } + + /** + * Get only left rotate pads. + * + * @param rotatePads on board + * @return list of left rotate pads + */ + private ArrayList getLeftRotatePads(ArrayList rotatePads) { + ArrayList leftRotatePads = new ArrayList<>(); + for (RotatePad pad : rotatePads) { + if (pad.getRotate() == Rotate.LEFT) { + leftRotatePads.add(pad); + } + } + return leftRotatePads; + } + + /** + * Get only right rotate pads. + * + * @param rotatePads on board + * @return list of right rotate pads + */ + private ArrayList getRightRotatePads(ArrayList rotatePads) { + ArrayList rightRotatePads = new ArrayList<>(); + for (RotatePad pad : rotatePads) { + if (pad.getRotate() == Rotate.RIGHT) { + rightRotatePads.add(pad); + } + } + return rightRotatePads; + } + + @Test + public void rotatePadsIsNotEmptyTest() { + assertFalse(rotatePads.isEmpty()); + } + + @Test + public void onlyRotateWhenPadIsActivatedTest() { + for (int i = 0; i < 3; i++) { + RotatePad pad = getRandomRotatePad(rotatePads); + player.setDirection(Direction.EAST); + player.setPosition(pad.getPosition()); + assertEquals(Direction.EAST, player.getDirection()); + } + } + + @Test + public void playerOnLeftPadRotatesLeftTest() { + for (int i = 0; i < 3; i++) { + RotatePad pad = getRandomRotatePad(getLeftRotatePads(rotatePads)); + Vector2 padPosition = pad.getPosition(); + player.setPosition(padPosition); + player.setDirection(Direction.EAST); + game.activateRotatePads(); + assertEquals(Direction.NORTH, player.getDirection()); + } + } + + @Test + public void playerOnRightPadRotatesRightTest() { + for (int i = 0; i < 3; i++) { + RotatePad pad = getRandomRotatePad(getRightRotatePads(rotatePads)); + Vector2 padPosition = pad.getPosition(); + player.setPosition(padPosition); + player.setDirection(Direction.EAST); + game.activateRotatePads(); + assertEquals(Direction.SOUTH, player.getDirection()); + } + } + + + +} diff --git a/src/test/java/inf112/skeleton/app/WallTests.java b/src/test/java/inf112/skeleton/app/WallTests.java new file mode 100644 index 00000000..2e3df6fa --- /dev/null +++ b/src/test/java/inf112/skeleton/app/WallTests.java @@ -0,0 +1,522 @@ +package inf112.skeleton.app; + +import com.badlogic.gdx.Gdx; +import com.badlogic.gdx.backends.headless.HeadlessApplication; +import com.badlogic.gdx.graphics.GL20; +import com.badlogic.gdx.maps.tiled.TiledMapTileLayer; +import com.badlogic.gdx.math.Vector2; +import inf112.skeleton.app.enums.Direction; +import inf112.skeleton.app.enums.TileID; +import org.junit.Before; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Random; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.mockito.Mockito.mock; + +public class WallTests { + private Board board; + private Player player; + private Random random; + private ArrayList allNorthWalls; + private ArrayList allSouthWalls; + private ArrayList allEastWalls; + private ArrayList allWestWalls; + + @Before + public void setUp() { + //Mock OpenGL in order to use gdx.texture, gdx.tmxMapLoader etc without getting + // nullpointerexception + Gdx.gl = mock(GL20.class); + //Make a headless application in order to initialize the board. Does not show. + new HeadlessApplication(new EmptyApplication()); + int NUMBER_OF_PLAYERS_WHEN_STARTING_GAME = 2; + this.board = new Board("assets/maps/Risky_Exchange.tmx", NUMBER_OF_PLAYERS_WHEN_STARTING_GAME); + this.player = new Player(new Vector2(0,0), 1); + random = new Random(); + allNorthWalls = new ArrayList<>(); + allSouthWalls = new ArrayList<>(); + allEastWalls = new ArrayList<>(); + allWestWalls = new ArrayList<>(); + putPositionsToWallsInLists(); + } + + /** + * + * @param position of tile + * @return true if position is on tile before border + */ + private boolean onEastBorder(Vector2 position) { + return position.x >= board.getWidth()-1; + } + + /** + * + * @param position of tile + * @return true if position is on tile before border + */ + private boolean onWestBorder(Vector2 position) { + return position.x < 1; + } + + /** + * + * @param position of tile + * @return true if position is on tile before border + */ + private boolean onSouthBorder(Vector2 position) { + return position.y < 1; + } + + /** + * + * @param position of tile + * @return true if position is on tile before border + */ + private boolean onNorthBorder(Vector2 position) { + return position.y >= board.getHeight()-1; + } + + /** + * @param cell to check + * @return true if cell only has north wall + */ + private boolean isOnlyNorthWall(TiledMapTileLayer.Cell cell) { + if (cell == null) { + return false; + } + return cell.getTile().getId() == TileID.NORTH_WALL.getId(); + } + + /** + * @param cell to check + * @return true if cell only has south wall + */ + private boolean isOnlySouthWall(TiledMapTileLayer.Cell cell) { + if (cell == null) { + return false; + } + return cell.getTile().getId() == TileID.SOUTH_WALL.getId(); + } + + /** + * @param cell to check + * @return true if cell only has east wall + */ + private boolean isOnlyEastWall(TiledMapTileLayer.Cell cell) { + if (cell == null) { + return false; + } + return cell.getTile().getId() == TileID.EAST_WALL.getId(); + } + + /** + * @param cell to check + * @return true if cell only has west wall + */ + private boolean isOnlyWestWall(TiledMapTileLayer.Cell cell) { + if (cell == null) { + return false; + } + return cell.getTile().getId() == TileID.WEST_WALL.getId(); + } + + /** + * Give a random entry from given list + * + * @return a random position from the list given + */ + private Vector2 getRandomWallPosition(ArrayList listOfWalls) { + int randomIndex = random.nextInt(listOfWalls.size()); + return listOfWalls.get(randomIndex); + } + + /** + * Filter out walls like south-east, north-west etc. Is used + * so that we can test that a player can move when there is not a wall in + * front of the player, but on same tile. + * + * @param listOfWalls allNorthWalls + * @return list of only north walls + */ + private ArrayList getOnlyNorthWalls(ArrayList listOfWalls) { + ArrayList northWalls = new ArrayList<>(); + for (Vector2 wallPos : listOfWalls) { + TiledMapTileLayer.Cell cell = board.getWallLayer().getCell((int) wallPos.x, (int) wallPos.y); + if (isOnlyNorthWall(cell)) { + northWalls.add(wallPos); + } + } + return northWalls; + } + + /** + * Filter out walls like south-east, north-west etc. Is used + * so that we can test that a player can move when there is not a wall in + * front of the player, but on same tile. + * + * @param listOfWalls allSouthWalls + * @return list of only south walls + */ + private ArrayList getOnlySouthWalls(ArrayList listOfWalls) { + ArrayList southWalls = new ArrayList<>(); + for (Vector2 wallPos : listOfWalls) { + TiledMapTileLayer.Cell cell = board.getWallLayer().getCell((int) wallPos.x, (int) wallPos.y); + if (isOnlySouthWall(cell)) { + southWalls.add(wallPos); + } + } + return southWalls; + } + + /** + * Filter out walls like south-east, north-west etc. Is used + * so that we can test that a player can move when there is not a wall in + * front of the player, but on same tile. + * + * @param listOfWalls allEastWalls + * @return list of only east walls + */ + private ArrayList getOnlyEastWalls(ArrayList listOfWalls) { + ArrayList eastWalls = new ArrayList<>(); + for (Vector2 wallPos : listOfWalls) { + TiledMapTileLayer.Cell cell = board.getWallLayer().getCell((int) wallPos.x, (int) wallPos.y); + if (isOnlyEastWall(cell)) { + eastWalls.add(wallPos); + } + } + return eastWalls; + } + + /** + * Filter out walls like south-east, north-west etc. Is used + * so that we can test that a player can move when there is not a wall in + * front of the player, but on same tile. + * + * @param listOfWalls allWestWalls + * @return list of only west walls + */ + private ArrayList getOnlyWestWalls(ArrayList listOfWalls) { + ArrayList westWalls = new ArrayList<>(); + for (Vector2 wallPos : listOfWalls) { + TiledMapTileLayer.Cell cell = board.getWallLayer().getCell((int) wallPos.x, (int) wallPos.y); + if (isOnlyWestWall(cell)) { + westWalls.add(wallPos); + } + } + return westWalls; + } + + /** + * In order to test that a player can not move when facing a wall on a neighbour cell, + * player needs to be placed on the cell next to the wall. Then this cell can not have a wall + * facing towards the border, because then the player will be placed outside the board. + * + * @param listOfWalls a list of position to the walls + * @return a list of position for the walls, where the walls aligning the borderline is excluded + */ + private ArrayList filterWallsOnBorder(ArrayList listOfWalls) { + ArrayList wallsCopy = (ArrayList) listOfWalls.clone(); + for (Vector2 wallPosition : listOfWalls) { + TiledMapTileLayer.Cell wallCell = board.getWallLayer().getCell((int) wallPosition.x, (int) wallPosition.y); + if (onEastBorder(wallPosition) && board.hasEastWall(wallCell)) { + wallsCopy.remove(wallPosition); + } + if (onSouthBorder(wallPosition) && board.hasSouthWall(wallCell)) { + wallsCopy.remove(wallPosition); + } + if (onWestBorder((wallPosition)) && board.hasWestWall(wallCell)) { + wallsCopy.remove(wallPosition); + } + if (onNorthBorder(wallPosition) && board.hasNorthWall(wallCell)) { + wallsCopy.remove(wallPosition); + } + } + return wallsCopy; + } + + /** + * Put all position to the walls on board in lists. + */ + private void putPositionsToWallsInLists() { + TiledMapTileLayer wallLayer = board.getWallLayer(); + for (int x = 0; x < board.getWidth(); x++) { + for (int y = 0; y < board.getHeight(); y++) { + Vector2 pos = new Vector2(x, y); + TiledMapTileLayer.Cell wall = wallLayer.getCell(x, y); + if (board.hasSouthWall(wall)) { + allSouthWalls.add(pos); + } + if (board.hasNorthWall(wall)) { + allNorthWalls.add(pos); + } + if (board.hasEastWall(wall)) { + allEastWalls.add(pos); + } + if (board.hasWestWall(wall)) { + allWestWalls.add(pos); + } + } + } + } + + @Test + public void thereAreNorthWallsOnBoardTest() { + assertFalse(allNorthWalls.isEmpty()); + } + + @Test + public void thereAreSouthWallsOnBoardTest() { + assertFalse(allSouthWalls.isEmpty()); + } + + @Test + public void thereAreEastWallsOnBoardTest() { + assertFalse(allEastWalls.isEmpty()); + } + + @Test + public void thereAreWestWallsOnBoardTest() { + assertFalse(allWestWalls.isEmpty()); + } + + + @Test + public void playerIsOnCellWithNorthWallTest() { + // Found position in Risky_Exchange.tmx, North Wall has ID 31 + player.setPosition(new Vector2(2, 0)); + TiledMapTileLayer wallLayer = board.getWallLayer(); + TiledMapTileLayer.Cell playerCell = wallLayer.getCell((int) player.getPosition().x, (int) player.getPosition().y); + assertTrue(board.hasNorthWall(playerCell)); + } + + @Test + public void playerIsOnCellWithWestWallTest() { + // Found position in Risky_Exchange.tmx, SouthWest wall has ID 32 + player.setPosition(new Vector2(11, 7)); + TiledMapTileLayer wallLayer = board.getWallLayer(); + TiledMapTileLayer.Cell playerCell = wallLayer.getCell((int) player.getPosition().x, (int) player.getPosition().y); + assertTrue(board.hasWestWall(playerCell)); + } + + @Test + public void playerIsOnCellWithEastWallTestTest() { + // Found position in Risky_Exchange.tmx, East Wall ha ID 23 + player.setPosition(new Vector2(3, 2)); + TiledMapTileLayer wallLayer = board.getWallLayer(); + TiledMapTileLayer.Cell playerCell = wallLayer.getCell((int) player.getPosition().x, (int) player.getPosition().y); + assertTrue(board.hasEastWall(playerCell)); + } + + @Test + public void playerFacingRandomNorthWallCanNotGoTest() { + // Test for some random walls on board + for (int i = 0; i < 5; i++) { + assertFalse(board.canGo(getRandomWallPosition(allNorthWalls), Direction.NORTH)); + } + } + + @Test + public void playerFacingRandomEastWallCanNotGoTest() { + // Test for some random walls on board + for (int i = 0; i < 5; i++) { + assertFalse(board.canGo(getRandomWallPosition(allEastWalls), Direction.EAST)); + } + } + + @Test + public void playerFacingRandomSouthWallCanNotGoTest() { + // Test for some random walls on board + for (int i = 0; i < 5; i++) { + assertFalse(board.canGo(getRandomWallPosition(allSouthWalls), Direction.SOUTH)); + } + } + + @Test + public void playerFacingRandomWestWallCanNotGoTest() { + // Test for some random walls on board + for (int i = 0; i < 5; i++) { + assertFalse(board.canGo(getRandomWallPosition(allWestWalls), Direction.WEST)); + } + } + + @Test + public void playerFacingRandomNorthWallDoesNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(allNorthWalls)); + player.setDirection(Direction.NORTH); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerFacingRandomSouthWallDoesNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(allSouthWalls)); + player.setDirection(Direction.SOUTH); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerFacingRandomEastWallDoesNotMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(allEastWalls)); + player.setDirection(Direction.EAST); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerFacingRandomWestWallDoesNotMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(allWestWalls)); + player.setDirection(Direction.WEST); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerIsNotFacingRandomNorthWallButOnSameTileAsWallThenPlayerCanMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(getOnlyNorthWalls(allNorthWalls))); + player.setDirection(Direction.WEST); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertNotEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerIsNotFacingRandomWestWallButOnSameTileAsWallThenPlayerCanMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(getOnlyWestWalls(allWestWalls))); + player.setDirection(Direction.EAST); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertNotEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerIsNotFacingRandomEastWallButOnSameTileAsWallThenPlayerCanMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(getOnlyEastWalls(allEastWalls))); + player.setDirection(Direction.SOUTH); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertNotEquals(posBefore, player.getPosition()); + } + } + + @Test + public void playerIsNotFacingRandomSouthWallButOnSameTileAsWallThenPlayerCanMoveTest() { + // Test for several random walls + for (int i = 0; i < 5; i++) { + player.setPosition(getRandomWallPosition(getOnlySouthWalls(allSouthWalls))); + player.setDirection(Direction.NORTH); + Vector2 posBefore = new Vector2((int) player.getPosition().x, (int) player.getPosition().y); + board.movePlayer(player); + assertNotEquals(posBefore, player.getPosition()); + } + } + + /** + * A player can be on tile with no walls but still + * have a neighbouring tile with wall pointing against + * player. So when a player tries to go on this tile, it should + * be blocked even though it has no wall on the tile player is standing + * on. + */ + @Test + public void playerFacingRandomEastWallOnNeighbourCellCanNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + Vector2 neighbourCellWithWall = getRandomWallPosition(filterWallsOnBorder(allEastWalls)); + int neighbourX = (int) neighbourCellWithWall.x; + int neighbourY = (int) neighbourCellWithWall.y; + Vector2 playerPosition = new Vector2(neighbourX + 1, neighbourY); + player.setPosition(playerPosition); + player.setDirection(Direction.WEST); + board.movePlayer(player); + assertEquals(playerPosition, player.getPosition()); + } + } + + /** + * See {@link #playerFacingRandomEastWallOnNeighbourCellCanNotMoveTest()} + */ + @Test + public void playerFacingRandomWestWallOnNeighbourCellCanNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + Vector2 neighbourCellWithWall = getRandomWallPosition(filterWallsOnBorder(allWestWalls)); + int neighbourX = (int) neighbourCellWithWall.x; + int neighbourY = (int) neighbourCellWithWall.y; + Vector2 playerPosition = new Vector2(neighbourX - 1, neighbourY); + player.setPosition(playerPosition); + player.setDirection(Direction.EAST); + board.movePlayer(player); + assertEquals(playerPosition, player.getPosition()); + } + } + + /** + * See {@link #playerFacingRandomEastWallOnNeighbourCellCanNotMoveTest()} + */ + @Test + public void playerFacingRandomNorthWallOnNeighbourCellCanNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + Vector2 neighbourCellWithWall = getRandomWallPosition(filterWallsOnBorder(allNorthWalls)); + int neighbourX = (int) neighbourCellWithWall.x; + int neighbourY = (int) neighbourCellWithWall.y; + Vector2 playerPosition = new Vector2(neighbourX, neighbourY+1); + player.setPosition(playerPosition); + player.setDirection(Direction.SOUTH); + board.movePlayer(player); + assertEquals(playerPosition, player.getPosition()); + } + } + + /** + * See {@link #playerFacingRandomEastWallOnNeighbourCellCanNotMoveTest()} + */ + @Test + public void playerFacingRandomSouthWallOnNeighbourCellCanNotMoveTest() { + // Test for some random walls + for (int i = 0; i < 5; i++) { + Vector2 neighbourCellWithWall = getRandomWallPosition(filterWallsOnBorder(allSouthWalls)); + int neighbourX = (int) neighbourCellWithWall.x; + int neighbourY = (int) neighbourCellWithWall.y; + Vector2 playerPosition = new Vector2(neighbourX, neighbourY-1); + player.setPosition(playerPosition); + player.setDirection(Direction.NORTH); + board.movePlayer(player); + assertEquals(playerPosition, player.getPosition()); + } + } + + + +}