Hallo
Ich habe ein kleines Snake Spiel geschrieben. Das Problem ist, dass meine Hauptklasse zu viel der Arbeit übernimmt. Hier ist die Klasse die für die Speicherung der Koordinaten der Schlange zuständig ist.
Soweit so gut. Die Klasse hat nur einen einzigen Nutzen, welcher klar erkennbar ist.
Nun die Hauptklasse welche das Spiel startet, die Schlange bewegt, auf den Bildschirm malt und die Logik überprüft.
Gibt es vielleicht so etwas wie einen Leitfaden an den man sich hält? Sowas wie, Grafik und Spielelogik getrennt voneinander schreiben? Mir kommt es so vor, als ob ich mich hier in eine Sackgasse geschrieben habe was das Spiel angeht. Jede Änderung am Spiel muss ich ja in dieser einen Klasse durchführen. Und bei Änderung von einer Sache muss ich dann wieder 5 andere Sachen mitverändern.
Ich habe ein kleines Snake Spiel geschrieben. Das Problem ist, dass meine Hauptklasse zu viel der Arbeit übernimmt. Hier ist die Klasse die für die Speicherung der Koordinaten der Schlange zuständig ist.
Java:
package snakegame;
public class BodyPos {
private final int x, y;
public int getX()
{
return x;
}
public int getY()
{
return y;
}
public BodyPos(int x, int y)
{
this.x = x;
this.y = y;
}
}
Nun die Hauptklasse welche das Spiel startet, die Schlange bewegt, auf den Bildschirm malt und die Logik überprüft.
Java:
package snakegame;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
//import java.awt.event.ActionEvent;
//import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.LinkedList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
//import javax.swing.Timer;
public class SnakeGame implements KeyListener{
private JFrame gameFrame;
private enum Direction
{
Initial, Left, Right, Up, Down;
}
//starting direction is undefined (but can't be Left because of the initial position of the snake),
//snake moves in specified direction when player presses one of the arrow keys
private Direction dir = Direction.Initial;
private final int SCREEN_SIZE_X = 900;
private final int SCREEN_SIZE_Y = 750;
private final int SNAKE_SIZE_X = 25;
private final int SNAKE_SIZE_Y = 25;
private int fruitX = new Random().nextInt(SCREEN_SIZE_X - SNAKE_SIZE_X);
private int fruitY = new Random().nextInt(SCREEN_SIZE_Y - SNAKE_SIZE_Y);
//starting coordinates of the snake head, set to middle of screen
private int startPosX = SCREEN_SIZE_X / 2 - SNAKE_SIZE_X / 2;
private int startPosY = SCREEN_SIZE_Y / 2 - SNAKE_SIZE_Y / 2;
//List that holds the x,y coordinates of the snake
LinkedList<BodyPos> snakeBody;
//set to true when the snake touches the fruit
private boolean fruitFlag = false;
public void startGame()
{
snakeBody = new LinkedList<>();
//adds the head of the snake and 2 parts to the body
//adds a gap between the bodyparts
snakeBody.add(new BodyPos(startPosX, startPosY));
snakeBody.add(new BodyPos((startPosX - SNAKE_SIZE_X - 1), startPosY));
snakeBody.add(new BodyPos((startPosX - (2 * SNAKE_SIZE_X) - 2), startPosY));
gameFrame = new JFrame("Snake");
gameFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
DrawPanel dp = new DrawPanel(SCREEN_SIZE_X, SCREEN_SIZE_Y);
gameFrame.getContentPane().add(dp);
gameFrame.getContentPane().addKeyListener(this);
gameFrame.pack();
gameFrame.getContentPane().setFocusable(true);
gameFrame.setVisible(true);
while(!gameOver())
{
move();
gameLogic();
dp.repaint();
try
{
Thread.sleep(70);
}catch(Exception e) { }
}
}
public void move()
{
BodyPos head = snakeBody.getFirst();
if(dir == Direction.Up)
{
snakeBody.addFirst(new BodyPos(head.getX(), (head.getY() - 26)));
}
if(dir == Direction.Down)
{
snakeBody.addFirst(new BodyPos(head.getX(), (head.getY() + 26)));
}
if(dir == Direction.Left)
{
snakeBody.addFirst(new BodyPos((head.getX() - 26), (head.getY())));
}
if(dir == Direction.Right)
{
snakeBody.addFirst(new BodyPos((head.getX() + 26), (head.getY())));
}
if(!(dir == Direction.Initial))
{
//if the head touched a fruit, don't remove the last bodypart
if(fruitFlag)
{
fruitFlag = false;
}
else
{
snakeBody.removeLast();
}
}
}
public boolean gameOver()
{
BodyPos head = snakeBody.getFirst();
//game is over when head leaves screen (with wiggle room of 5 pixels)
if((head.getX() + SNAKE_SIZE_X > (SCREEN_SIZE_X + 5)
|| head.getY() + SNAKE_SIZE_Y > (SCREEN_SIZE_Y + 5))
|| head.getX() < -5 || head.getY() < -5)
{
return true;
}
//game is over when head touches one of the body parts
for(int i = 1; i < snakeBody.size(); i++)
{
if(head.getX() == snakeBody.get(i).getX() && head.getY() == snakeBody.get(i).getY())
{
return true;
}
}
return false;
}
public void gameLogic()
{
Rectangle head = new Rectangle(snakeBody.getFirst().getX(), snakeBody.getFirst().getY(), SNAKE_SIZE_X, SNAKE_SIZE_Y);
Rectangle fruit = new Rectangle(fruitX, fruitY, SNAKE_SIZE_X, SNAKE_SIZE_Y);
//randomize the location of the fruit once the head of the snake touches it
if(head.intersects(fruit))
{
fruitX = new Random().nextInt(SCREEN_SIZE_X - SNAKE_SIZE_X);
fruitY = new Random().nextInt(SCREEN_SIZE_Y - SNAKE_SIZE_Y);
fruitFlag = true;
}
}
public class DrawPanel extends JPanel
{
private static final long serialVersionUID = -8192817857593753584L;
public DrawPanel(int width, int height)
{
this.setPreferredSize(new Dimension(width, height));
}
public void paintComponent(Graphics g)
{
Graphics2D g2d = (Graphics2D) g;
//clear the screen
g2d.setColor(Color.WHITE);
g2d.fillRect(0, 0, this.getWidth(), this.getHeight());
//print the snake
g2d.setColor(Color.BLACK);
for(BodyPos snake : snakeBody)
{
Rectangle bodyPart = new Rectangle(snake.getX(), snake.getY(), SNAKE_SIZE_X, SNAKE_SIZE_Y);
g2d.fill(bodyPart);
}
//print the fruit
g2d.setColor(Color.GREEN);
Rectangle fruit = new Rectangle(fruitX, fruitY, SNAKE_SIZE_X, SNAKE_SIZE_Y);
g2d.fill(fruit);
g2d.dispose();
}
}
@Override
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
//initial position of the head is on the right side of the body,
//moving left from starting position would reverse the direction which is not allowed
if(key == KeyEvent.VK_LEFT && !(dir == Direction.Right) && !(dir == Direction.Initial))
{
dir = Direction.Left;
}
else if(key == KeyEvent.VK_RIGHT && !(dir == Direction.Left))
{
dir = Direction.Right;
}
else if(key == KeyEvent.VK_UP && !(dir == Direction.Down))
{
dir = Direction.Up;
}
else if(key == KeyEvent.VK_DOWN && !(dir == Direction.Up))
{
dir = Direction.Down;
}
}
@Override
public void keyTyped(KeyEvent arg0) { }
@Override
public void keyPressed(KeyEvent arg0) { }
}
Gibt es vielleicht so etwas wie einen Leitfaden an den man sich hält? Sowas wie, Grafik und Spielelogik getrennt voneinander schreiben? Mir kommt es so vor, als ob ich mich hier in eine Sackgasse geschrieben habe was das Spiel angeht. Jede Änderung am Spiel muss ich ja in dieser einen Klasse durchführen. Und bei Änderung von einer Sache muss ich dann wieder 5 andere Sachen mitverändern.