SnakeGame

来源:互联网 发布:淘宝一个差评扣多少分 编辑:程序博客网 时间:2024/04/28 16:53

写一个简单的贪吃蛇游戏,运行效果如下:

游戏开始:


游戏结束:


代码经多次完善,食物已经不会出现在Snake的身体上,边界也实现为可穿透,完整代码如下:

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.LinkedList;
import java.util.Random;


import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JPanel;


public class SnakeGame {
public static void main(String[] args) {
SnakeGame snakeGame=new SnakeGame();
}
public SnakeGame() {
// TODO 自动生成的构造函数存根
Snake snake=new Snake();
Food food=new Food();
Ground ground=new Ground();

GamePanel gamePanel=new GamePanel();
controller controller=new controller(snake, food, ground, gamePanel);

snake.addSnakeListener(controller);
gamePanel.addKeyListener(controller);

JFrame frame=new JFrame("SnakeGame_Vision1.0");
frame.setSize(420,420);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLocationRelativeTo(null);

frame.add(gamePanel);
gamePanel.setFocusable(true);

controller.startGame();
frame.setVisible(true);
}
}


class GamePanel extends JPanel {
private Snake snake;
private Food food;
private Ground ground;
public void displayPanel(Snake snake,Food food,Ground ground){
this.snake=snake;
this.food=food;
this.ground=ground;
repaint();
}
@Override
protected void paintComponent(Graphics g) {
// TODO 自动生成的方法存根
super.paintComponent(g);
if(snake!=null&&food!=null&&ground!=null){
snake.drawMe(g);
food.drawMe(g);
ground.drawMe(g);
}
}
}


interface SnakeListener {
public void snakeMoveJudge(Snake snake);
}
class controller extends KeyAdapter implements SnakeListener{
private Snake snake;
private Food food;
private Ground ground;

private GamePanel gamePanel;


public controller(Snake snake, Food food, Ground ground, GamePanel gamePanel) {
super();
this.snake = snake;
this.food = food;
this.ground = ground;
this.gamePanel = gamePanel;
}
@Override
public void keyPressed(KeyEvent e) {
// TODO 自动生成的方法存根
super.keyPressed(e);
int KeyCode=e.getKeyCode();
switch (KeyCode) {
case KeyEvent.VK_UP:
snake.changeDirection(Snake.UP);
break;
case KeyEvent.VK_DOWN:
snake.changeDirection(Snake.DOWN);
break;
case KeyEvent.VK_LEFT:
snake.changeDirection(Snake.LEFT);
break;
case KeyEvent.VK_RIGHT:
snake.changeDirection(Snake.RIGHT);
break;
}
}
@Override
public void snakeMoveJudge(Snake snake) {
// TODO 自动生成的方法存根
if(snake.ifEatSelf()){
JOptionPane.showMessageDialog(null,"Game Over!   Your score is "+snake.getScore()+"!","message",JOptionPane.INFORMATION_MESSAGE);
System.exit(-1);
}
if(food.ifEatBySnake(snake)){
snake.eatFood();
food.addFood(getPoint());
}
while(food.ifInSnake(snake)){
food.addFood(getPoint());
}
gamePanel.displayPanel(snake, food, ground);
}
public void startGame(){
snake.start();
food.addFood(getPoint());
}
public Point getPoint(){
int x=new Random().nextInt(Global.WIDTH);
while(x<3||x>22){
x=new Random().nextInt(Global.WIDTH);
}
int y=new Random().nextInt(Global.HEIGHT);
while(y<3||y>22){
y=new Random().nextInt(Global.HEIGHT);
}
return(new Point(x,y));
}
}


class Global {
public static final int CELL_SIZE=15;
public static final int HEIGHT=24;
public static final int WIDTH=24;
}
class Snake {
private LinkedList<Point> body=new LinkedList<Point>();
private SnakeListener snakeListener;
private int oldDirection,newDirection;
public static final int UP=8;
public static final int DOWN=2;
public static final int LEFT=4;
public static final int RIGHT=6;
public Point tail;
private int score;
public Snake(){
init();
}
public void init(){
int x=Global.WIDTH/2;
int y=Global.HEIGHT/2;
for(int i=0;i<3;i++){
body.add(new Point(x-i,y));
}
this.oldDirection=this.newDirection=RIGHT;
this.score=0;
}
public int getScore(){
return this.score;
}
public LinkedList<Point> getBody(){
return this.body;
}
public void move(){
tail=body.removeLast();
int x=body.getFirst().x;
int y=body.getFirst().y;
if(this.oldDirection+this.newDirection!=10){
this.oldDirection=this.newDirection;
}
switch (oldDirection) {
case UP:
y--;
if(y==2) y=22;
break;
case DOWN:
y++;
if(y==23) y=3;
break;
case LEFT:
x--;
if(x==2) x=22;
break;
case RIGHT:
x++;
if(x==23) x=3;
break;
}
body.addFirst(new Point(x,y));
}
public void changeDirection(int direction){
this.newDirection=direction;
}
public void eatFood(){
body.addLast(tail);
score++;
}
public boolean ifEatSelf(){
int count=0;
for(Point p:body){
if(this.GetHead().equals(p))
count++;
}
if(count==2) return true;
else return false;
}
public void drawMe(Graphics g){
g.setColor(Color.red);
for(Point p:body){
g.fill3DRect(p.x*Global.CELL_SIZE, p.y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
g.setFont(new Font("华文新魏", Font.BOLD,20));
g.drawString("Score:"+String.format("%s", this.score), 20, 20);
}
public void addSnakeListener(SnakeListener snakeListener){
if(snakeListener!=null)
this.snakeListener=snakeListener;
}
public void start(){
new SnakeDriver().start();
}
public Point GetHead(){
return body.getFirst();
}
private class SnakeDriver extends Thread{
@Override
public void run(){
// TODO 自动生成的方法存根
while(true){
move();
snakeListener.snakeMoveJudge(Snake.this);
try {
Thread.sleep(100);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
}
}
}
}


class Ground {
public void drawMe(Graphics g){
g.setColor(Color.LIGHT_GRAY);
for(int x=2,y=2;y<24;y++){
g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
for(int x=23,y=2;y<24;y++){
g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
for(int y=2,x=2;x<24;x++){
g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
for(int y=23,x=2;x<24;x++){
g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
}
}


class Food extends Point{
public void drawMe(Graphics g){
g.setColor(Color.yellow);
g.fill3DRect(x*Global.CELL_SIZE, y*Global.CELL_SIZE, Global.CELL_SIZE, Global.CELL_SIZE, true);
}
public boolean ifEatBySnake(Snake snake){
if(snake.GetHead().equals(this)) return true;
else return false;
}
public void addFood(Point p){
this.x=p.x;
this.y=p.y;
}
public boolean ifInSnake(Snake snake){
boolean flag=false;
for(Point p:snake.getBody()){
if(this.equals(p)){
flag=true;
}
}
return flag;
}
}





整套游戏基本上用的是MVC的设计方案,包括实体类(Snake,Food,Ground)、控制器类(Controller)、面板类(GamePanel)、以及辅助类(Global)和SnakeListener接口。

Snake运用LinkedList的数据结构和Point的数据类型。

Food类继承Point类。

Ground限制游戏面板大小、实现穿透。

GamePanel继承JPanel,重写Paint。

0 0
原创粉丝点击