贪吃蛇思路:
1.画院子,院子中包含对蛇和食物的引用,去操作蛇和食物的出现以及移动
2.蛇是由块组成,蛇的块是一个链表,设置蛇的头和尾分别是什么3.蛇块是一个双向链表,除了头部都有一个下一个后继,除了尾部都有一个前驱
4.蛇的移动就是按照线程的休眠时间,每隔指定的时间在蛇头的前一个位置插入一个(注意该块必须和当前蛇头的方向一致),同时删除蛇尾
5.键盘控制蛇头的方向,给院子加键盘监听时间,调用蛇的方法改变 head的方向
6.画出一个食物
7.使用Rectangle检测蛇头和食物2个区域是否相交,如果相交改变食物的坐标,向蛇头位置添加一块
8.检测是否撞墙,既蛇头所在的行列 row<0 || col<0 || row>Yard.ROWS || col>Yard.COLS 既是撞墙
9.检测是否撞身子,遍历蛇的每一块,如果和蛇头的行列重复 既为撞身子
10.使用标记flag表示是否撞墙或者撞身子
11.计数,使用g.drawString()向页面中写入文字
12.撞墙后写入游戏结束
五个类 一个枚举类(存方向)一个院子类(放图像)一个蛇类 一个碰撞类(判定碰撞)一个食物类
使用的数据尽量不要用数字,设置常量使用。
院子类
public class Yard extends Frame{
static final int rows=30;
static final int cols=50;
static final int VK=20;
static final int size=40;
static final int xborder=20;
static final int yborder=40;
static int sroce=0;
public static Snake snake=new Snake();
public static Food food=new Food();
Crash crash;
Image image=null;
public Yard(){
super("贪吃蛇");
this.setBounds(400, 100, cols*VK+size, rows*VK+size);
this.setVisible(true);
this.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(-1);
}
});
new MyThread().start();
addKeyListener(snake.new Mouse()); //设置鼠标监听
}
//双缓冲技术,解决屏幕闪烁的问题
@Overridepublic void update(Graphics g) {
image = this.createImage(cols*VK+size,rows*VK+size);
Graphics grap = image.getGraphics();
paint(grap);
g.drawImage(image, 0, 0, null);
}
//repaint()->update()->paint()
@Overridepublic void paint(Graphics g){
g.setColor(Color.BLACK);
for(int i=1;i<=rows+1;i++){
g.drawLine(xborder, i*VK, (cols+1)*VK, i*VK);
}
for(int i=1;i<=cols+1;i++){
g.drawLine(i*VK, yborder, i*VK,(rows+1)*VK);
}
snake.move();
snake.draw(g);
crash.eatfood(snake, food);
food.draw(g);
g.drawString("sroce:"+sroce,100, 180);
}
class MyThread extends Thread{
@Override
public void run() {
while (true) {
crash=new Crash(snake.head.getX(), snake.head.getY());
crash.crashyard();
crash.crashbody();
if (crash.isFlag()) {
repaint();
}
else {
gameover();
break;
}
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
void gameover(){
Font font=new Font("宋体",Font.BOLD,100);
Label label=new Label("GAME OVER");
this.setLayout(null);
label.setBounds((cols*VK)/2-300, (rows*VK)/2-100,650,100);
this.setFont(font);
this.add(label);
this.setVisible(true);
}
public static void main(String[] args) {
Yard yard=new Yard();
}
}
//枚举类型 用于设置方向
public enum Dir {
U,R,D,L}
//蛇类(使用链表的形式存储蛇的每一块)
public class Snake {
Node head;//蛇头
private Node tail;//蛇尾
private Node node;//蛇
private int xStart=25;
private int yStart=16;
public Snake() {
//X最大格为50,最小为1,y最大格为30,最小格为2
node=new Node(xStart, yStart, Dir.R);
head=node;
tail=node;
}
void draw(Graphics g){
for(Node n=head;n!=null;n=n.next){
n.draw(g);
}
}
void move(){
addtohead();
deletetotail();
}
void addtohead(){
Node node=null;
switch (head.dir) {
case U:
node=new Node(head.x, head.y-1, Dir.U);
break;
case R:
node=new Node(head.x+1, head.y, Dir.R);
break;
case D:
node=new Node(head.x, head.y+1, Dir.D);
break;
case L:
node=new Node(head.x-1, head.y, Dir.L);
break;
}
node.next=head;
head.prex=node;
head=node;
}
void deletetotail(){
tail=tail.prex;
tail.next=null;
}
//继承监听适配器的好处,不需要把该监听器的所有方法都重写
class Mouse extends KeyAdapter{
@Override
public void keyPressed(KeyEvent e) {
switch (e.getKeyCode()) {
case KeyEvent.VK_LEFT:
if (head.getDir()!=Dir.R) {
head.setDir(Dir.L);
}
break;
case KeyEvent.VK_UP:
if (head.getDir()!=Dir.D) {
head.setDir(Dir.U);
}
break;
case KeyEvent.VK_RIGHT:
if (head.getDir()!=Dir.L) {
head.setDir(Dir.R);
}
break;
case KeyEvent.VK_DOWN:
if (head.getDir()!=Dir.U) {
head.setDir(Dir.D);
}
break;
default :
try {
Thread.sleep(15000);
} catch (InterruptedException e1) {
// TODO 自动生成的 catch 块
e1.printStackTrace();
}
break;
}
}
}
class Node{ //蛇块
Node prex;
Node next;
private int x;
private int y;
private int VK=20;
private Dir dir;
public Node(int x,int y,Dir dir) {
this.x=x;
this.y=y;
this.dir=dir;
}
public Dir getDir() {
return dir;
}
public void setDir(Dir dir) {
this.dir = dir;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
void draw(Graphics g){
g.setColor(Color.black);
g.fillRect(x*VK, y*VK, VK, VK);
}
}
}
//食物类
public class Food {
private int x;
private int y;
private int VK=20;
public Food() {
x=new Random().nextInt(50)+1;
y=new Random().nextInt(29)+2;
}
void draw(Graphics g){
g.setColor(Color.RED);
g.fillOval(x*VK,y*VK, VK, VK);
}
void change(){
x=new Random().nextInt(50)+1;
y=new Random().nextInt(29)+2;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
//碰撞类
public class Crash {
private static int VK=20;
private int x;
private int y;
private boolean flag=true;
static boolean b=false;
public Crash(int x,int y) {
this.x=x;
this.y=y;
}
public Crash(){
}
void crashyard(){
if (x*VK<Yard.xborder||x*VK>(Yard.cols)*VK) {
flag=false;
}
if (y*VK<Yard.yborder||y*VK>(Yard.rows)*VK) {
flag=false;
}
}
void crashbody(){
for(Node node=Yard.snake.head.next;node!=null;node=node.next){
if (Yard.snake.head.getX()==node.getX()&&Yard.snake.head.getY()==node.getY()) {
flag=false;
break;
}
}
}
//Rectangle是检测碰撞 具体用法请自行查API
public Rectangle rectangle1(){
return new Rectangle(Yard.snake.head.getX(),Yard.snake.head.getY(),1,1);
}
public Rectangle rectangle2(){
return new Rectangle(Yard.food.getX(),Yard.food.getY(),1,1);
}
public void eatfood(Snake snake,Food food){
Rectangle snakere=rectangle1();
Rectangle foodre=rectangle2();
b=snakere.intersects(foodre);
if (b) {
b=false;
food.change();
snake.addtohead();
Yard.sroce++;
}
}
public boolean isFlag() {
return flag;
}
public void setFlag(boolean flag) {
this.flag = flag;
}
}