java贪吃蛇

贪吃蛇思路: 


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()); //设置鼠标监听

}

//双缓冲技术,解决屏幕闪烁的问题

@Override
public 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()

@Override
public 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;
}


}

猜你喜欢

转载自blog.csdn.net/qq_39404258/article/details/80460047