java贪吃蛇

来源:互联网 发布:电子相册软件排行 编辑:程序博客网 时间:2024/06/06 03:49

最近突然想做一个自动寻路的贪吃蛇,然而这个基础是先做一个贪吃蛇,然后再做修改,下面是花一天按照教程(尚学堂马士兵的教程)撸的一个贪吃蛇的代码,我尽量注释得清楚,以便日后再看方便。

Yard.java 

import java.awt.Color;import java.awt.Font;import java.awt.Frame;import java.awt.Graphics;import java.awt.Image;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.awt.event.WindowAdapter;import java.awt.event.WindowEvent;public class Yard extends Frame {public int getScore() {return score;}public void setScore(int score) {this.score = score;}PaintThread paintThread = new PaintThread();private boolean gameOver = false;//院子有几个小格子 25*25public static final int rows = 30; public static final int cols = 30;//每个小格子的大小5*5public static final int BLOCK_SIZE = 15;//得分private int score = 0;//创建一条蛇,传进thisSnake s = new Snake(this);Egg e = new Egg();//加入双缓冲,这个不清楚是什么东西,缓冲解决闪烁的问题Image offScreenImage = null;//展示一下小格子,使用launch(运行)public void launch() {//设定院子出现的位置this.setLocation(200,200);//设置院子的尺寸this.setSize(rows * BLOCK_SIZE, cols*BLOCK_SIZE);//关闭窗口this.addWindowListener(new WindowAdapter() {//重写 右键source --> overide -->windowclosing@Overridepublic void windowClosing(WindowEvent e) {/*// TODO Auto-generated method stubsuper.windowClosing(e);*///重写上面注释掉的部分,下面是简单处理System.exit(0);}});//显示可见this.setVisible(true);//有了这一行蛇才会动,之前一直少这一行this.addKeyListener(new KeyMonitor());//让下面定义的线程跑起来// 原版  new Thread(new PaintThread()).start();new Thread(paintThread).start();}/** * @param args */public static void main(String[] args) {// TODO Auto-generated method stub//运行一下new Yard().launch();}public void stop() {gameOver = true;}//画出小格子public void paint(Graphics g){Color c = g.getColor();//背景色g.setColor(Color.GRAY);g.fillRect(0, 0, rows * BLOCK_SIZE, cols*BLOCK_SIZE);g.setColor(Color.DARK_GRAY);//画出横线,原理是两个定点确定一条直线for(int i = 1; i < rows ; i++){g.drawLine(0, BLOCK_SIZE*i, cols*BLOCK_SIZE, BLOCK_SIZE * i);}//同理,画出竖线for(int i = 1; i < cols ; i++){g.drawLine(BLOCK_SIZE*i,0 ,BLOCK_SIZE * i,  rows*BLOCK_SIZE);}//画出分数线g.setColor(Color.YELLOW);g.drawString("分数:" + score, 10, 60);//第一版的展示分数,之前的那一版因为在线程结束后刷新界面,无法显示/*if(flag == false){//构造方法可以在api手册里面找,字体可以在notepad++里面找一个好看的g.setFont(new Font("华文彩云",Font.BOLD,50));g.drawString("HaHa,you Died", 10, 80);}*/if(gameOver){g.setFont(new Font("华文彩云",Font.BOLD,50));g.drawString("HaHa,you Died", 30, 180);g.setFont(new Font("楷体",Font.BOLD,20));g.drawString("code by mz", 300, 220);paintThread.gameOver();}g.setColor(c);//判断是否吃到蛇,画出蛇,画出蛋s.eat(e);s.draw(g);e.draw(g);}//这个方法是利用双缓冲解决闪烁现象的,虽然原理我还不太懂@Overridepublic void update(Graphics g) {if(offScreenImage == null){offScreenImage = this.createImage(rows * BLOCK_SIZE, cols*BLOCK_SIZE);}Graphics gOff = offScreenImage.getGraphics();paint(gOff);g.drawImage(offScreenImage,0,0 ,null);}//定义一个线程让蛇移动起来private class PaintThread implements Runnable{private boolean runing  = true;@Overridepublic void run() {// TODO Auto-generated method stub//下面的格式比较固定while(runing){repaint();try{//停顿50毫秒Thread.sleep(100);}catch (InterruptedException e) {// TODO: handle exceptione.printStackTrace();}}}public void gameOver() {runing = false;}}//键盘监听,来操作蛇的移动private class KeyMonitor extends KeyAdapter{@Overridepublic void keyPressed(KeyEvent e) {// TODO Auto-generated method stub//让蛇去处理//int key = e.getKeyCode();//if(key == KeyEvent.VK_F2){////paitThread.reStart;//}s.keyPressed(e);}}}
Snake.java  


import java.awt.Color;import java.awt.Graphics;import java.awt.Rectangle;import java.awt.event.KeyEvent;public class Snake {private Node head = null;private Node tail = null;private int size = 0;//先定义一个节点用来创建蛇,作为蛇的初始坐标Node n = new Node(20, 30, Dir.L);private Yard y;//构造函数,一个节点构造的蛇/*public Snake(Node node){head = tail = node;size = 1;}*///重新写构造函数,使其有坐标public Snake(Yard y){head = tail = n;size = 1;this.y = y; } //把节点加在尾巴上public void addToTail(){//Node node = null;//判定方向,并由此确定尾巴加在什么上switch(tail.dir){case L:node = new Node(tail.row,tail.col+1,tail.dir);break;case U:node = new Node(tail.row + 1,tail.col,tail.dir);break;case R:node = new Node(tail.row,tail.col - 1,tail.dir);break;case D:node = new Node(tail.row - 1,tail.col,tail.dir);break;}tail.next = node;node.prior = tail;tail = node;size ++;}//吃一个加在头上public void addToHead(){    Node node = null;//判定方向,并由此确定尾巴加在什么上switch(head.dir){case L:node = new Node(head.row,head.col-1,head.dir);break;case U:node = new Node(head.row - 1,head.col,head.dir);break;case R:node = new Node(head.row,head.col + 1,head.dir);break;case D:node = new Node(head.row + 1,head.col,head.dir);break;}node.next = head;head.prior = node;head = node;size ++;}//画出蛇,draw方法,区别与下面那个draw方法,这个是可以外部访问的public void draw(Graphics g){if(size <= 0){return;}//move放在打印之前更加灵敏move();//循环打印节点for(Node n = head; n != null; n = n.next){n.draw(g);}}//根据蛇头的方向来进行移动,基本思想是把尾巴add到头,同时删除尾巴,比如最新版的贪吃蛇头尾不一样,也可以加到head.next private void move() {// TODO Auto-generated method stubaddToHead();deleteFromTail();//移动完成之后判断是否符合死亡的条件checkDead();}  private void checkDead() {// TODO Auto-generated method stub //判断是否撞墙 //之所以是head.col < 2 是因为上面的标题框盖住了两行if(head.row < 2 || head.col < 0 || head.row > Yard.rows || head.col > Yard.cols){ y.stop();}//判断是否和自己的身体相撞for(Node n = head.next; n != null; n = n.next){if(head.row == n.row && head.col == n.col){y.stop();}}}//private void deleteFromTail() {// TODO Auto-generated method stubif(size == 0)return;tail = tail.prior;tail.next = null;}private class Node{//节点的宽高int w = Yard.BLOCK_SIZE;int h = Yard.BLOCK_SIZE;//节点的坐标(第几行第几列 )int row ,col;Dir dir = Dir.L;//下一个节点是谁Node next = null;Node prior = null; //构造函数 Node(int row, int col,Dir dir) {this.row = row;this.col = col;this.dir = dir;}//画出节点 void draw(Graphics g) {Color c = g.getColor();g.setColor(Color.BLACK);g.fillRect(Yard.BLOCK_SIZE * col, Yard.BLOCK_SIZE * row, w, h);g.setColor(c);}}public void eat(Egg e){//判断是否碰撞if(this.getRect().intersects(e.getRect())){//碰上的话egg就随机出现在另一个地方e.reAppear();//蛇长一个节点this.addToHead();y.setScore(y.getScore()+5);}}//辅助性方法,蛇头所在方块,由此可以想到egg里也有一个这样的方块private Rectangle getRect(){return new Rectangle(Yard.BLOCK_SIZE * head.col, Yard.BLOCK_SIZE * head.row, head.w, head.h);} //键盘控制蛇头的方向public void keyPressed(KeyEvent e) {int key = e.getKeyCode();switch(key) {case KeyEvent.VK_LEFT :if(head.dir != Dir.R)head.dir = Dir.L;break;case KeyEvent.VK_UP :if(head.dir != Dir.D)head.dir = Dir.U;break;case KeyEvent.VK_RIGHT :if(head.dir != Dir.L)head.dir = Dir.R;break;case KeyEvent.VK_DOWN :if(head.dir != Dir.U)head.dir = Dir.D;break;}}}

Egg.java
import java.awt.Color;import java.awt.Graphics;import java.awt.Rectangle;import java.util.Random;public class Egg {int row , col;int w = Yard.BLOCK_SIZE;int h = Yard.BLOCK_SIZE;//生成一个随机数private static Random r = new Random();private Color color = Color.GREEN;public Egg(int row, int col) {super(); this.row = row;this.col = col;}//随机生成一个蛋public Egg(){//注意这种写法,很重要this(r.nextInt(Yard.rows-2)+2,r.nextInt(Yard.cols));}//egg被吃掉后重新出现public void reAppear(){//之所以要减去2再加上2是为了避免出现在我们看不到的边界地带this.row = r.nextInt(Yard.rows-2)+2;this.col = r.nextInt(Yard.cols);}//画出蛋所在的public Rectangle getRect(){return new Rectangle(Yard.BLOCK_SIZE * col, Yard.BLOCK_SIZE * row, w, h);}public void draw(Graphics g) {Color c = g.getColor();g.setColor(color);g.fillOval(Yard.BLOCK_SIZE * col, Yard.BLOCK_SIZE * row, w, h);g.setColor(c);if(color == Color.GREEN){color = Color.RED;}else{color = Color.GREEN;}}public int getRow() {return row;}public void setRow(int row) {this.row = row;}public int getCol() {return col;}public void setCol(int col) {this.col = col;}}

Dir.java

public enum Dir {L,U,R,D}
今天就先敲到这里,有时间再把这个代码改进一下,从今天的敲代码的过程,我发现我对有ava GUI还不熟悉,线程还用的不熟练等问题,日后加强。

 
原创粉丝点击