diff --git a/src/KeyboardListener.java b/src/KeyboardListener.java index 0271729..d003dc5 100644 --- a/src/KeyboardListener.java +++ b/src/KeyboardListener.java @@ -5,25 +5,51 @@ public class KeyboardListener extends KeyAdapter{ public void keyPressed(KeyEvent e){ switch(e.getKeyCode()){ - case 39: // -> Right - //if it's not the opposite direction - if(ThreadsController.directionSnake!=2) - ThreadsController.directionSnake=1; - break; - case 38: // -> Top - if(ThreadsController.directionSnake!=4) - ThreadsController.directionSnake=3; - break; + + //Player One Controls + case 39: // -> Right + //if it's not the opposite direction + if(ThreadsController.directionSnake!=2) + ThreadsController.directionSnake=1; + break; + case 38: // -> Top + if(ThreadsController.directionSnake!=4) + ThreadsController.directionSnake=3; + break; - case 37: // -> Left - if(ThreadsController.directionSnake!=1) - ThreadsController.directionSnake=2; - break; + case 37: // -> Left + if(ThreadsController.directionSnake!=1) + ThreadsController.directionSnake=2; + break; - case 40: // -> Bottom - if(ThreadsController.directionSnake!=3) - ThreadsController.directionSnake=4; - break; + case 40: // -> Bottom + if(ThreadsController.directionSnake!=3) + ThreadsController.directionSnake=4; + break; + + //Player Two Controls + + case KeyEvent.VK_D: // -> Player 2 Right + if(ThreadsControllerPlayerTwo.directionSnake != 2) + ThreadsControllerPlayerTwo.directionSnake = 1; + break; + + + case KeyEvent.VK_W: // -> Player 2 Top + if(ThreadsControllerPlayerTwo.directionSnake != 4) + ThreadsControllerPlayerTwo.directionSnake = 3; + break; + + case KeyEvent.VK_A: // -> Player 2 Left + if(ThreadsControllerPlayerTwo.directionSnake != 1) + ThreadsControllerPlayerTwo.directionSnake = 2; + break; + + + case KeyEvent.VK_S: // -> Player 2 Bottom + if(ThreadsControllerPlayerTwo.directionSnake != 3) + ThreadsControllerPlayerTwo.directionSnake = 4; + break; default: break; } diff --git a/src/Main.java b/src/Main.java index e2da510..8a6ed60 100644 --- a/src/Main.java +++ b/src/Main.java @@ -4,8 +4,8 @@ public class Main { public static void main(String[] args) { - //Creating the window with all its awesome snaky features - Window f1= new Window(); + //Creating the window with all its awesome snakey features + Window f1 = new Window(); //Setting up the window settings f1.setTitle("Snake"); diff --git a/src/ThreadsController.java b/src/ThreadsController.java index 3df2d3d..82ac83d 100644 --- a/src/ThreadsController.java +++ b/src/ThreadsController.java @@ -71,7 +71,7 @@ private void checkCollision() { //Stops The Game private void stopTheGame(){ - System.out.println("COLISION! \n"); + System.out.println("COLLISION! \n"); while(true){ pauser(); } diff --git a/src/ThreadsControllerPlayerTwo.java b/src/ThreadsControllerPlayerTwo.java new file mode 100644 index 0000000..20df098 --- /dev/null +++ b/src/ThreadsControllerPlayerTwo.java @@ -0,0 +1,169 @@ +import java.util.ArrayList; + + +//Controls all the game logic .. most important class in this project. +public class ThreadsControllerPlayerTwo extends Thread { + ArrayList> Squares= new ArrayList>(); + Tuple headSnakePos; + int sizeSnake=3; + long speed = 50; + public static int directionSnake ; + + ArrayList positions = new ArrayList(); + Tuple foodPosition; + + //Constructor of ControlleurThread + ThreadsControllerPlayerTwo(Tuple positionDepart){ + //Get all the threads + Squares=Window.Grid; + + headSnakePos=new Tuple(positionDepart.x,positionDepart.y); + directionSnake = 1; + + //!!! Pointer !!!! + Tuple headPos = new Tuple(headSnakePos.getX(),headSnakePos.getY()); + positions.add(headPos); + + foodPosition= new Tuple(Window.height-1,Window.width-1); + spawnFood(foodPosition); + + } + + //Important part : + public void run() { + while(true){ + moveInterne(directionSnake); + checkCollision(); + moveExterne(); + deleteTail(); + pauser(); + } + } + + //delay between each move of the snake + private void pauser(){ + try { + sleep(speed); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + //Checking if the snake bites itself or is eating + private void checkCollision() { + Tuple posCritique = positions.get(positions.size()-1); + for(int i = 0;i<=positions.size()-2;i++){ + boolean biteItself = posCritique.getX()==positions.get(i).getX() && posCritique.getY()==positions.get(i).getY(); + if(biteItself){ + stopTheGame(); + } + } + + boolean eatingFood = posCritique.getX()==foodPosition.y && posCritique.getY()==foodPosition.x; + if(eatingFood){ + System.out.println("Yummy!"); + sizeSnake=sizeSnake+1; + foodPosition = getValAleaNotInSnake(); + + spawnFood(foodPosition); + } + } + + //Stops The Game + private void stopTheGame(){ + System.out.println("COLLISION! \n"); + while(true){ + pauser(); + } + } + + //Put food in a position and displays it + private void spawnFood(Tuple foodPositionIn){ + Squares.get(foodPositionIn.x).get(foodPositionIn.y).lightMeUp(1); + } + + //return a position not occupied by the snake + private Tuple getValAleaNotInSnake(){ + Tuple p ; + int ranX= 0 + (int)(Math.random()*19); + int ranY= 0 + (int)(Math.random()*19); + p=new Tuple(ranX,ranY); + for(int i = 0;i<=positions.size()-1;i++){ + if(p.getY()==positions.get(i).getX() && p.getX()==positions.get(i).getY()){ + ranX= 0 + (int)(Math.random()*19); + ranY= 0 + (int)(Math.random()*19); + p=new Tuple(ranX,ranY); + i=0; + } + } + return p; + } + + //Moves the head of the snake and refreshes the positions in the arraylist + //1:right 2:left 3:top 4:bottom 0:nothing + private void moveInterne(int dir){ + switch(dir){ + case 4: + headSnakePos.ChangeData(headSnakePos.x,(headSnakePos.y+1)%20); + positions.add(new Tuple(headSnakePos.x,headSnakePos.y)); + break; + case 3: + if(headSnakePos.y-1<0){ + headSnakePos.ChangeData(headSnakePos.x,19); + } + else{ + headSnakePos.ChangeData(headSnakePos.x,Math.abs(headSnakePos.y-1)%20); + } + positions.add(new Tuple(headSnakePos.x,headSnakePos.y)); + break; + case 2: + if(headSnakePos.x-1<0){ + headSnakePos.ChangeData(19,headSnakePos.y); + } + else{ + headSnakePos.ChangeData(Math.abs(headSnakePos.x-1)%20,headSnakePos.y); + } + positions.add(new Tuple(headSnakePos.x,headSnakePos.y)); + + break; + case 1: + headSnakePos.ChangeData(Math.abs(headSnakePos.x+1)%20,headSnakePos.y); + positions.add(new Tuple(headSnakePos.x,headSnakePos.y)); + break; + } + } + + //Refresh the squares that needs to be + private void moveExterne(){ + for(Tuple t : positions){ + int y = t.getX(); + int x = t.getY(); + Squares.get(x).get(y).lightMeUp(0); + + } + } + + //Refreshes the tail of the snake, by removing the superfluous data in positions arraylist + //and refreshing the display of the things that is removed + private void deleteTail(){ + int cmpt = sizeSnake; + for(int i = positions.size()-1;i>=0;i--){ + if(cmpt==0){ + Tuple t = positions.get(i); + Squares.get(t.y).get(t.x).lightMeUp(2); + } + else{ + cmpt--; + } + } + cmpt = sizeSnake; + for(int i = positions.size()-1;i>=0;i--){ + if(cmpt==0){ + positions.remove(i); + } + else{ + cmpt--; + } + } + } +} diff --git a/src/Window.java b/src/Window.java index 518fa9e..b476858 100644 --- a/src/Window.java +++ b/src/Window.java @@ -3,6 +3,7 @@ import java.util.ArrayList; import javax.swing.JFrame; +import javax.swing.JOptionPane; class Window extends JFrame{ @@ -37,6 +38,33 @@ public Window(){ } } + + + /* + * The below code makes a JOptionPane ask the user if he/she wants to play with + * one player or two player, and sets up the game accordingly. + */ + + String[] options = {"One player" , "Two Players"}; + int playersSelected = JOptionPane.showOptionDialog(null, "Would you like to play single player or multiplayer?", + "A Silly Question", + JOptionPane.YES_NO_CANCEL_OPTION, + JOptionPane.QUESTION_MESSAGE, + null, + options, + options[1]); + + //If user selects "Two Player" + if(playersSelected == 1){ + //Set up Player Two Controller + Tuple position2 = new Tuple(13,13); + ThreadsControllerPlayerTwo c2 = new ThreadsControllerPlayerTwo(position2); + c2.start(); + } + + //If User selects "One Player" or exits out of JOptionPane, game starts with only one player + + // initial position of the snake Tuple position = new Tuple(10,10); // passing this value to the controller @@ -46,12 +74,22 @@ public Window(){ // Links the window to the keyboardlistenner. this.addKeyListener((KeyListener) new KeyboardListener()); - - //To do : handle multiplayers .. The above works, test it and see what happens - //Tuple position2 = new Tuple(13,13); - //ControlleurThreads c2 = new ControlleurThreads(position2); - //c2.start(); + + /*TODO: + * Problems With Multiplayer: + * -When one player eats food, and then the other player eats food, the food completely disappears. + * -The two players can freely go through each other (no collision happens between two players). + * This does not necessarily need to be fixed, but it would be interesting to allow + * players to make other players collide in order to win (like original snake of light cycle games). + * This feature would also give more motivation to get the food (the more food you get, + * the longer you are, the more of a chance you have of trapping opponent). + * + * If this feature is not implemented, an alternative would be to show a "scoreboard" on the + * right of the screen, and set a time limit to see which player can get most food + * (without colliding into itself). + */ + } }