一、概要设计
游戏规则:
由于基本都玩过,再次不在啰嗦。
游戏要素:
1、地图(map)
2、蛇(snake)
3、食物(food)
4、规则(rule)
输入设定:
1、通过键盘上的上、下、左、右进行游戏控制。
2、通过键盘的P控制游戏的暂停(pause)/开始(start)、N(new)控制新的一局的开始。
输出内容:(*为特定条件下激活)
1 、 游戏速度
2 、 游戏进行时间
3 、 贪吃蛇长度
4*、显示游戏结束信息
基本游戏默认参数:
1、地图大小(20X20)
2、地图单元格width = 20, height =20;
3、游戏速度为 (1051 - level*50)ms 初始等级为1,最高等级为20.
4、初始贪吃蛇长度为3
规则:
1、贪吃蛇碰触墙壁或者自身时,游戏结束。
2、贪吃蛇不能朝反方向进行移动。 ( 即:若当前贪吃蛇头部朝向的方向为南,则向北移动是无效的操作。)
3、贪吃蛇达到一定长度时,游戏结束。
4、食物位置随机生成。
未完成部分:
见Snack类中moveTo()方法的TODO标签处。
作业:
1、实现贪吃虫的自动移动。
2、增加游戏计时功能。(游戏时间)
3、增加暂停功能。
4、处理不同因移动造成的情况,进行相应处理
二、详细设计
画布类(Canvas):
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Vector;
import javax.swing.JPanel;
public class Canvas extends JPanel{
/**
*
*/
private static final long serialVersionUID = 1L;
/*画布参数*/
public static final int PADDING = 10; //画布内边距
public static final int CELL_SIZE = 20; //单元格大小
public static final int CELL_COLUMN = 20; //单元格列数
public static final int CELL_ROW = 20; //单元格行数
public static final Color BACKGROUND = Color.WHITE; //画布背景颜色
public int canvasWidth = 2*PADDING + CELL_SIZE*CELL_COLUMN;
public int canvasHeight = 2*PADDING + CELL_SIZE*CELL_ROW;
/*画布中的对象*/
public Snake snake; //贪吃蛇
private GameMap map; //地图(容器)
// ------------------------------------
// 构造方法
// ------------------------------------
public Canvas() {
setPreferredSize(null); //设置面板大小
startGame();
}
/*从Point坐标值转换为swing中的坐标值*/
public int transformX(int pointX){ return 0;}
public int transformY(int pointY){ return 0;}
/*开始游戏*/
public void startGame(){
map = new GameMap();
snake = new Snake(map);
/*初始化开始一条位置,并且长度为3的贪吃蛇*/
snake.enqueue(map.getPoint(10, 12));
snake.enqueue(map.getPoint(10, 11));
snake.enqueue(map.getPoint(10, 10));
map.randomFood(snake);
}
/*绘制界面*/
@Override
public void paint(Graphics g) {
super.paint(g);
/*绘制网格,测试用*/
// for(int i=0;i<=CELL_COLUMN;i++)
// g.drawLine(PADDING, PADDING+CELL_SIZE*i, PADDING +CELL_SIZE*CELL_COLUMN, PADDING+CELL_SIZE*i);
// for(int i=0;i<=CELL_ROW;i++)
// g.drawLine(PADDING + CELL_SIZE*i, PADDING, PADDING + CELL_SIZE*i, PADDING + CELL_SIZE*CELL_ROW);
/*画贪吃蛇*/
Vector<Point> body = snake.getBody();
for(int i=0;i<body.size();i++){
/*头部画黄色*/
Point p = body.get(i);
if(i == body.size()-1){
Color oldColor = g.getColor();
g.setColor(Color.yellow);
g.fillRect((int)p.getX(),(int) p.getY(), CELL_SIZE, CELL_SIZE);
g.setColor(oldColor);
}else
g.fillRect((int)p.getX(),(int) p.getY(), CELL_SIZE, CELL_SIZE);
}
/*画食物*/
Point food = map.getFood();
if(food != null){
//画食物
Color oldColor = g.getColor();
g.setColor(Color.red);
g.fillRect((int)food.getX(), (int)food.getY(), CELL_SIZE, CELL_SIZE);
g.setColor(oldColor);
}
}
/*重载设置面板大小*/
@Override
public void setPreferredSize(Dimension d) {
super.setPreferredSize(new Dimension(canvasWidth,canvasHeight));
}
}
地图类(GameMap):
import java.awt.Point;
import java.util.Random;
public class GameMap {
/*地图坐标*/
public Point[][] map;
/*食物坐标*/
private Point food;
/*构造方法*/
public GameMap() {
map = new Point[Canvas.CELL_ROW][Canvas.CELL_COLUMN];
for (int i=0;i<Canvas.CELL_ROW ;i++) {
for (int j=0;j<Canvas.CELL_COLUMN;j++) {
map[i][j] = new Point(Canvas.PADDING+Canvas.CELL_SIZE*i,Canvas.PADDING+Canvas.CELL_SIZE*j);
}
}
}
/*得到指定位置的X,Y坐标*/
public Point getPoint(int row,int column){
return map[row][column];
}
/*得到指定point所在map中的索引*/
public int[] pointAt(Point p){
int row = (int) ( (p.getX()-Canvas.PADDING) / Canvas.CELL_SIZE);
int column = (int)( (p.getY()-Canvas.PADDING) / Canvas.CELL_SIZE);
return new int[]{row,column};
}
/*随机生成食物坐标*/
public Point randomFood(Snake snake){
Random random = new Random();
int xPos = random.nextInt(Canvas.CELL_ROW);
int yPos = random.nextInt(Canvas.CELL_COLUMN);
while(true){
if( !snake.getBody().contains(getPoint(xPos, yPos)) ){
food = getPoint(xPos, yPos);
return food;
}else {
xPos = random.nextInt(Canvas.CELL_ROW);
yPos = random.nextInt(Canvas.CELL_COLUMN);
}
}
}
/*设置食物位置*/
public void setFood(Point food){
this.food = food;
}
/*得到食物位置*/
public Point getFood(){
return food;
}
}
贪吃蛇类(Snack):
import java.util.Vector;
import java.awt.Point;
public class Snake {
/*贪吃蛇在地图中的点集合,[0]元素为蛇头,[size-1]元素为蛇尾*/
private Vector<Point> body;
/*贪吃蛇所在地图*/
private GameMap map;
/*构造方法*/
public Snake(GameMap map){
this.map = map;
body = new Vector<Point>();
}
/*贪吃蛇移动或进食*/
public void enqueue(Point p) {
body.add(p);
}
/*判断贪吃蛇是否为空*/
public boolean isEmpty(){
return size() == 0;
}
/*返回贪吃蛇的长度*/
public int size() {
return body.size();
}
/*返回贪吃蛇头部的位置*/
public Point getHead() {
if(size()==0)
throw new RuntimeException("贪吃蛇无头部");
return body.get(size()-1);
}
/*返回贪吃蛇尾部的位置*/
public Point getTail() {
if(size()==0)
throw new RuntimeException("贪吃蛇无尾部");
return body.get(0);
}
/*返回头部后的第一个位置*/
public Point getHeadAfter(){
if(size()==1)
throw new RuntimeException("贪吃蛇只有头部");
return body.get(size()-2);
}
/*移除尾部*/
public void removeTail(){
body.remove(0);
}
/*返回整个贪吃蛇*/
public Vector<Point> getBody(){
return body;
}
// -----------------------------------
// 贪吃蛇行为
// -----------------------------------
/*是否为身体一部分*/
public boolean isBody(Point p){
if(body.contains(p))
return true;
return false;
}
/*贪吃蛇移动到地图指定点*/
public void moveTo(int row,int column) {
/*得到头部后第一个位置*/
Point afterHead = getHeadAfter();
/*判断要移动的位置是否有效*/
if(!moveValid(row, column)){
//TODO
//
// 添加你的处理方法,并将游戏结束
//
System.out.println("碰到墙壁了!");
return;
}
/*判断是否为无效反方向移动*/
if(map.getPoint(row, column).equals(afterHead)){
//TODO
//
// 添加你的处理方法,但游戏继续
//
System.out.println("无效的反方向操作!");
return;
}
/*判断是否碰到身体*/
if(isBody(map.getPoint(row, column))){
//TODO
//
// 添加你的处理方法,并将游戏结束
//
System.out.println("碰到身体了!");
return;
}
/*判断是否移动到食物上*/
if(map.getPoint(row, column).equals(map.getFood())){
/*将食物添加到贪吃蛇身体中*/
enqueue(map.getPoint(row, column));
/*重新生成食物*/
map.randomFood(this);
}else{
/*进行普通的移动*/
enqueue(map.getPoint(row, column));
removeTail();
}
}
/*贪吃蛇向左移动*/
public void moveLeft(){
/*得到头部位置*/
Point head = getHead();
int[] cood = map.pointAt(head);
moveTo(cood[0]-1, cood[1]);
}
/*贪吃蛇向右移动*/
public void moveRight(){
/*得到头部位置*/
Point head = getHead();
int[] cood = map.pointAt(head);
moveTo(cood[0]+1, cood[1]);
}
/*贪吃蛇向上移动*/
public void moveUp(){
/*得到头部位置*/
Point head = getHead();
int[] cood = map.pointAt(head);
moveTo(cood[0], cood[1]-1);
}
/*贪吃蛇向下移动*/
public void moveDown(){
/*得到头部位置*/
Point head = getHead();
int[] cood = map.pointAt(head);
moveTo(cood[0], cood[1]+1);
}
/*贪吃蛇移动是否有效*/
public boolean moveValid(int r,int c){
if( r < 0 || r >= Canvas.CELL_ROW || c < 0 || c >= Canvas.CELL_COLUMN)
return false;
return true;
}
}
游戏主界面类(GameFrame):
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import javax.swing.JFrame;
public class GameFrame extends JFrame implements KeyListener{
/**
*
*/
private static final long serialVersionUID = 1L;
private Canvas canvas;
/*构造方法*/
public GameFrame(){
init();
}
/*初始化*/
private void init(){
this.setTitle("贪吃蛇 by:luiyikeke");
canvas = new Canvas();
add(canvas); /*添加画布到主面板*/
pack(); /*自适应大小*/
setResizable(false); /*禁止调整窗口大小*/
setLocationRelativeTo(null); /*窗口屏幕居中显示*/
this.addKeyListener(this);
}
public static void main(String[] args) {
new GameFrame().setVisible(true);
}
@Override
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if (38 == keyCode) {
canvas.snake.moveUp();
} else if (37 == keyCode) {
canvas.snake.moveLeft();
} else if (39 == keyCode) {
canvas.snake.moveRight();
} else if (40 == keyCode) {
canvas.snake.moveDown();
}
canvas.repaint();
}
@Override
public void keyReleased(KeyEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent e) {
// TODO Auto-generated method stub
}
}