数据结构大作业-贪吃蛇
这次数据结构课程我的大作业选择的是贪吃蛇,最初我想了很久到底用什么语言来写贪吃蛇,最后想到java实现图形界面是最方便的,因为JDK里已经有AWT和SWING两个类可以实现图形界面,C语言我会用一个叫easyX的图形库,但是我感觉这个图形库用起来挺麻烦的,c++的话,我还不会用QT,MFC,之类的。这个课程供我们选择的就只有这三门语言,最后我选择了java。
由于我是这学期刚学的java,而且一个星期只有一节java课,一共只学了只有七八周的样子,所以java学的不怎么精,对有些类的理解其实我的理解是错误的,所以,请各位路过的大佬轻喷。
我的想法是先在主函数所在的类建立一个容器JFrame,再建立一个snakePanel类继承JPanel类,通过重写父类的paint()函数来实现整个界面,再通过不停地repaint()来实现图形的变动。
在snakePanel中首先我要自己把各种坐标量好,然后我定义了snakeX和snakeY两个整型数组变量,用来控制蛇的位置,然后我疯狂的在网上找图片,最坑的是蛇头,你们想想,蛇头有四个方向,也就是要找四张图片,还有背景图片,还有蛇身等等,我找图片就在学校图书管找了一个下午。
我又定义了一个lenth变量,每次repaint时通过for循环画lenth-1次蛇身,每次lenth+1就实现了蛇身的增长,还有就是食物,我通过了math类派生出的Rand类随机出食物的X坐标和Y坐标然后paint,当食物的XY坐标和蛇头的XY坐标重合时就吃到了食物,食物此时就重新随机。游戏的失败判定和食物的判定类似,我每次通过一个for循环遍历蛇身,如果蛇身和蛇头重合则游戏失败(我并未设定蛇碰到墙就死的设定)。
最后就是如何动起来的事,我定义了一个IsLive的布尔变量,当蛇存活时未true,蛇死时为false,我全部关于动作的内容全部写在了一个while(isLive)的循环中,中间调用了Sleep函数来实现控制速度。
以上就是我的全部思路。
具体代码如下:
主类snake:
package snake; import java.awt.*; import javax.swing.*; public class Snake extends Thread{ public static void main(String[] args) { //主面板 JFrame frame = new JFrame("贪食蛇游戏"); frame.setBounds(10, 10, 900, 720); frame.setResizable(false); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Snakepanel panel = new Snakepanel(); frame.add(panel); //计分板 JFrame score = new JFrame("计分板"); score.setBounds(980, 10, 256, 180); score.setResizable(false); ScorePanel sp = new ScorePanel(); sp.label2.setText(String.valueOf(panel.lenth-3)); score.add(sp); sp.tr.start(); score.setVisible(true); frame.setVisible(true); OverFrame of = new OverFrame(); } }
snakePanel类:
package snake; import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; import java.util.Random; import javax.swing.ImageIcon; import javax.swing.JPanel; public class Snakepanel extends JPanel implements KeyListener,Runnable{ ImageIcon up = new ImageIcon("up.png"); ImageIcon down = new ImageIcon("down.png"); ImageIcon left = new ImageIcon("left.png"); ImageIcon right = new ImageIcon("right.png"); ImageIcon title = new ImageIcon("title.jpg"); ImageIcon food = new ImageIcon("food.png"); ImageIcon body = new ImageIcon("body.png"); ImageIcon background = new ImageIcon("background.jpg"); int[] snakeX = new int[1000];//蛇的X坐标 int[] snakeY = new int[1000];//蛇的Y坐标 int diriction;//方向,1为上,2为下,3为右,4为左 int lenth;//蛇的长度 int fx,fy;//食物的X轴和Y轴 Random rd = new Random(); boolean isStart; static boolean isLive; int level;//等级 int speed;//速度 Thread tr = new Thread(this); public Snakepanel(){ this.setFocusable(true); this.snakeX[0]=100; this.snakeY[0]=100; this.snakeX[1]=75; this.snakeY[1]=100; this.snakeX[2]=50; this.snakeY[2]=100; this.diriction = 3; this.lenth = 3; this.isLive=true; this.isStart=false; this.addKeyListener(this); this.speed=500; fx = rd.nextInt(34)*25+25; fy = rd.nextInt(24)*25+75; } public void paint(Graphics g) { super.paint(g); //画背景 this.setBackground(Color.WHITE); background.paintIcon(this, g, 0, 0); title.paintIcon(this, g, 25, 11); g.setColor(new Color(0,0,139,100)); g.fillRect(25, 75, 850, 600); //画蛇头 if(this.diriction==1){ up.paintIcon(this, g, snakeX[0], snakeY[0]); }else if(this.diriction==2){ down.paintIcon(this, g, snakeX[0], snakeY[0]); }else if(this.diriction==3){ right.paintIcon(this, g, snakeX[0], snakeY[0]); }else if(this.diriction==4){ left.paintIcon(this, g, snakeX[0], snakeY[0]); } //画蛇身 for(int i=1;i<lenth;i++){ body.paintIcon(this, g, snakeX[i], snakeY[i]); } if(isStart==false){ g.setColor(new Color(255,0,0)); g.setFont(new Font("宋体",Font.ITALIC,40)); g.drawString("请选择难度", 200, 200); g.drawString("按F1为简单", 200, 260); g.drawString("按F2为普通", 200, 320); g.drawString("按F3为困难", 200, 380); g.drawString("按F4为地狱", 200, 440); }else{ } //画食物 food.paintIcon(this, g, fx, fy); } //添加的键盘事件 public void keyPressed(KeyEvent e) { int keycode = e.getKeyCode(); if(keycode==KeyEvent.VK_F1){ this.level=1; this.isStart=true; this.repaint(); this.speed/=this.level; tr.start(); }else if(keycode==KeyEvent.VK_F2){ this.level=3; this.isStart=true; this.repaint(); this.speed/=this.level; tr.start(); }else if(keycode==KeyEvent.VK_F3){ this.level=5; this.isStart=true; this.repaint(); this.speed/=this.level; tr.start(); }else if(keycode==KeyEvent.VK_F4){ this.level=10; this.isStart=true; this.repaint(); this.speed/=this.level; tr.start(); }else if(keycode==KeyEvent.VK_UP){ if(this.diriction!=2){ this.diriction=1; this.repaint(); } }else if(keycode==KeyEvent.VK_DOWN){ if(this.diriction!=1) { this.diriction=2; this.repaint(); } }else if(keycode==KeyEvent.VK_RIGHT){ if(this.diriction!=4){ this.diriction=3; this.repaint(); } }else if(keycode==KeyEvent.VK_LEFT){ if(this.diriction!=3) { this.diriction=4; this.repaint(); } } } public void keyTyped(KeyEvent e) { } public void keyReleased(KeyEvent e) { } public void run() { while(isLive) { try { Thread.sleep(speed); } catch (Exception e) { } for(int i=lenth;i>0;i--){ snakeX[i]=snakeX[i-1]; snakeY[i]=snakeY[i-1]; } if(this.diriction==1){ snakeY[0]=snakeY[0]-25; if(snakeY[0]<75)snakeY[0]=650; }else if(this.diriction==2){ snakeY[0]=snakeY[0]+25; if(snakeY[0]>650)snakeY[0]=75; }else if(this.diriction==3){ snakeX[0]=snakeX[0]+25; if(snakeX[0]>850)snakeX[0]=25; }else if(this.diriction==4){ snakeX[0]=snakeX[0]-25; if(snakeX[0]<25)snakeX[0]=850; } if(snakeX[0]==fx&&snakeY[0]==fy){ ScorePanel.Score++; this.lenth++; fx = rd.nextInt(34)*25+25; fy = rd.nextInt(24)*25+75; } for(int i=1;i<this.lenth;i++) { if(snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]) { isLive=false; } } this.repaint(); } } }
ScorePanel类//用于计分
package snake; import javax.swing.*; import java.awt.*; public class ScorePanel extends JPanel implements Runnable{ JLabel label1 = new JLabel("您的分数为"); JLabel label2 = new JLabel(); static int Score; Thread tr = new Thread(this); Font fo = new Font("Times New Roman",Font.ITALIC,40); public ScorePanel() { this.setLayout(null); label1.setBounds(90, 20, 90, 50); label2.setBounds(90, 60, 150, 75); label2.setFont(fo); this.add(label1); this.add(label2); } public void run() { while(true) { try { label2.setText(String.valueOf(Score)); } catch (Exception e) { } } } }
overpanel类 //在游戏结束时弹出
package snake; import java.awt.*; import javax.swing.*; public class OverFrame extends JFrame implements Runnable{ Thread tr = new Thread(this); JLabel jl = new JLabel(); public OverFrame(){ this.setBounds(300, 300, 256, 180); this.setResizable(false); Font fo = new Font("宋体",Font.ITALIC,40); jl.setFont(fo); jl.setBounds(90, 40, 90, 50); jl.setText("Game Over"); this.add(jl); tr.start(); this.setDefaultCloseOperation(EXIT_ON_CLOSE); } public void run() { while(true) { if(Snakepanel.isLive==false) { this.setVisible(true); } } } }
最后游戏的效果如下
我的代码感觉很繁杂,可读性很差,最后希望路过的大佬们有所指点