实验内容
1)实现贪吃蛇游戏基本功能,屏幕上随机出现一个“食物”,称为豆子。玩家能利用上下左右键控制“蛇”的移动,“蛇”吃到“豆子”后“蛇”身体加长一节,得分增加,“蛇”碰到边界或蛇头与蛇身相撞,“蛇”死亡,游戏结束。
2)进行交互界面的设计,要有开始键、暂停键和停止退出的选项,能够控制游戏进程。对蛇吃到豆子进行分值计算,可以设置游戏速度,游戏音乐等拓展元素。
实现效果
点击暂停即可暂停游戏,点击开始即可继续游戏,点击背景音乐按钮即可播放背景音乐,点击得分d出得分面板。
实现思路
使用swing和绘图类实现
实现过程
1.首先需要创建一个名为Gameframe,用于放置GamePanel和按键。
为按键设置侦听器,再使用KeyListener设置按键侦听。
public class Gameframe extends Jframe { GamePanel gamePanel; Score score; //public Timer timer0; boolean stop0=true; private boolean bgm_control_jud = true;//防止打开多个bgm; public static Font font1 = new Font("宋体", Font.BOLD, 20);//定义字体1 public Gameframe() throws HeadlessException { Container container = getContentPane(); //设置窗体属性 this.setTitle("贪吃蛇 BY 废旧螺栓机甲"); this.setSize(640, 690); this.setLocation(100, 100); this.setResizable(false); this.setVisible(true); this.setFocusable(true); this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); //设置键盘监听 this.keyEvent(); //开始按钮,重置游戏 JButton game_start = new JButton(); game_start.setText("开始"); game_start.setForeground(Color.red); game_start.setFont(font1); game_start.setBounds(0, 0, 150, 30); game_start.setBackground(new Color(135, 206, 250)); game_start.setFocusable(false); container.add(game_start); //BGM *** 控 JButton bgm_control = new JButton(); bgm_control.setText("背景音乐"); bgm_control.setForeground(Color.yellow); bgm_control.setFont(font1); bgm_control.setBounds(300, 0, 150, 30); bgm_control.setBackground(new Color(100, 149, 237)); bgm_control.setFocusable(false); container.add(bgm_control); bgm_control.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Sound.Btn_press(); if (bgm_control_jud) { bgm_control_jud = false; Sound.BGM(); } } }); //暂停按钮 JButton stop_game = new JButton(); stop_game.setText("暂停/继续"); stop_game.setBounds(150, 0, 150, 30); stop_game.setForeground(Color.orange); stop_game.setFont(font1); stop_game.setBackground(new Color(147, 112, 219)); stop_game.setFocusable(false); container.add(stop_game); //计分板按钮 JButton score_get = new JButton(); score_get.setText("得分");//等待补充分数 score_get.setBounds(450, 0, 180, 30); score_get.setForeground(Color.MAGENTA); score_get.setFont(font1); score_get.setBackground(new Color(238, 232, 170)); container.add(score_get); score_get.setFocusable(false); //JPanel对象 gamePanel = new GamePanel(null); container.add(gamePanel); game_start.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Sound.Btn_press(); if(!stop0){ stop0=true;gamePanel.stop=false; } } }); stop_game.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Sound.Btn_press(); if(stop0){stop0=false;gamePanel.stop=true;} } }); score_get.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { Sound.Btn_press(); Gameframe.this.end(); } }); } //键盘监听 private void keyEvent() { addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyPressed(KeyEvent e) { switch (e.getKeyCode()) { case KeyEvent.VK_UP: if(gamePanel.snake.getDirection()!=Direction.DOWN)gamePanel.snake.setDirection(Direction.UP); break; case KeyEvent.VK_DOWN: if(gamePanel.snake.getDirection()!=Direction.UP)gamePanel.snake.setDirection(Direction.DOWN); break; case KeyEvent.VK_LEFT: if(gamePanel.snake.getDirection()!=Direction.RIGHT)gamePanel.snake.setDirection(Direction.LEFT); break; case KeyEvent.VK_RIGHT: if(gamePanel.snake.getDirection()!=Direction.LEFT)gamePanel.snake.setDirection(Direction.RIGHT); break; } } @Override public void keyReleased(KeyEvent e) { } }); } //结算 public int end(){ score=new Score(Gameframe.this); score.setVisible(true); return score.getScore(); } }
2.蛇由很多节点和蛇头的方向组成,所以创建三个类Node,Direction,Snake来表示蛇。
定义变量isLive来判断蛇头是否和自身重合,判断输入方向(比如蛇头向上不得朝下移动)
public enum Direction { UP,DOWN,LEFT,RIGHT }
public class Node { private int x; private int y; public Node() { } public Node(int x, int y) { this.x = x; this.y = y; } 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 Snake { //body public linkedListbody; private Direction direction= Direction.LEFT; //die or live public boolean isLive=true; public Snake() { initSnake(); } public void initSnake(){ body=new linkedList<>(); body.add(new Node(10,10)); body.add(new Node(11,10)); body.add(new Node(12,10)); body.add(new Node(13,10)); } public void move(){ //蛇头 Node head=body.getFirst(); if(isLive){ switch (direction){ case UP:{ body.addFirst(new Node(head.getX(),head.getY()-1)); break;} case DOWN:{ body.addFirst(new Node(head.getX(),head.getY()+1)); break;} case RIGHT:{ body.addFirst(new Node(head.getX()+1,head.getY())); break;} case LEFT:{ body.addFirst(new Node(head.getX()-1,head.getY())); break;} } body.removeLast();} //live or die head=body.getFirst(); if(head.getX()<0||head.getY()<0||head.getX()>30||head.getY()>30)isLive=false; for(int i=1;i getBody() { return body; } public void setBody(linkedList body) { this.body = body; } public Direction getDirection() { return direction; } public void setDirection(Direction direction) { this.direction = direction; } //吃食物 public void eat(Food food) { Node head=body.getFirst(); switch (direction){ case UP:{ body.addFirst(new Node(head.getX(),head.getY()-1)); break;} case DOWN:{ body.addFirst(new Node(head.getX(),head.getY()+1)); break;} case RIGHT:{ body.addFirst(new Node(head.getX()+1,head.getY())); break;} case LEFT:{ body.addFirst(new Node(head.getX()-1,head.getY())); break;} } } }
3.创建Food类,用于随机生成蛇的食物
public class Food { private int x; private int y; public Food(int x, int y) { this.x = x; this.y = y; } public Food(){ Random r=new Random(); //生成横坐标 this.x=r.nextInt(30); this.y=r.nextInt(30); } public int getX() { return x; } public int getY() { return y; } }
创建游戏窗体GamePanel,设置计时器,在屏幕上不断重绘,显示分数等。
public class GamePanel extends JPanel{ public static int u_score; public boolean game_over=false; public boolean stop=true; public Timer timer; public Snake snake; private boolean repeat=false;//判断食物是否和蛇身体重合,默认不重合 Image img; Food food; public Score score; public GamePanel(LayoutManager layout) { super(layout); score = new Score(); food = new Food(18, 18); snake = new Snake(); this.setBounds(0, 30, 640, 640); //添加背景图像 img = new ImageIcon("src/data/background.png").getImage(); stop=false; timer = new Timer(); TimerTask timerTask = new TimerTask() { @Override public void run() { if (!stop) { snake.move(); if (!snake.isLive && !game_over) { Sound.Game_over(); game_over = true; }//结束音效 if (!repeat) { //吃食物判断和食物是否和蛇身体重合判断 Node food0 = new Node(food.getX(), food.getY()); Node head = snake.getBody().getFirst(); if (head.getX() == food0.getX() && head.getY() == food0.getY()) { snake.eat(food); food = new Food(); Sound.Eat_food(); score.getScore(); u_score = score.getN(); } } else { food = new Food(); } for (int i = 1; i < snake.body.size(); i++) { Node node = snake.body.get(i); if (food.getX() == node.getX() && food.getY() == node.getY()) repeat = true; else repeat = false; } repaint(); } } }; timer.scheduleAtFixedRate(timerTask, 0, 200); } @Override public void paint(Graphics g) { //背景图绘制 Graphics2D g2=(Graphics2D) g; g2.drawImage(img,0,0,this.getWidth(),this.getHeight(),this); //网格线 g.setColor(Color.BLACK); for (int i = 0; i <31; i++) { g.drawLine(0, 20 * i, 600, 20 * i); g.drawLine(20 * i, 0, 20 * i, 600); } //绘制snake linkedListbody=snake.getBody(); g.setColor(Color.orange); for(Node node:body){ g.fillRoundRect(node.getX()*20, node.getY()*20,20,20,50,50); } //绘制food g.setColor(Color.GREEN); g.fillRoundRect(food.getX()*20,food.getY()*20,20,20,50,50); //绘制分数 g2.setColor(Color.pink); Font font0=new Font("宋体",Font.BOLD,20); g2.setFont(font0); g2.drawString(String.valueOf(u_score),580,20); Font font1=new Font("宋体",Font.BOLD,40); g2.setFont(font1); if(game_over){ g2.drawString("游戏结束,请退出",160,300); g2.setFont(font0); g2.drawString("最终得分"+String.valueOf(u_score),160,360); } } }
4.创建音频播放器MusicPlayer类用于播放音效,创建Sound类用于各种音效的控制。
public class MusicPlayer implements Runnable{ File soundFile;//音乐文件 Thread thread; boolean cir;//循环 public MusicPlayer(String filepath,boolean cir){ this.cir=cir; soundFile=new File(filepath);//文件地址 } public void run(){ byte[] auBuffer=new byte[1024*4096];//创建缓冲区 do{ AudioInputStream audioInputStream=null; SourceDataLine auline=null; try{ //从文件中获取音频输入流 audioInputStream= AudioSystem.getAudioInputStream(soundFile); AudioFormat format=audioInputStream.getFormat();//获得音频格式 DataLine.Info info=new DataLine.Info(SourceDataLine.class,format); auline=(SourceDataLine) AudioSystem.getLine(info); auline.open(format); auline.start(); int byteCount=0; while(byteCount!=-1){ byteCount=audioInputStream.read(auBuffer,0,auBuffer.length); if(byteCount>=0){ auline.write(auBuffer,0,byteCount); } } } catch (IOException e){e.printStackTrace();} catch (UnsupportedAudioFileException e){e.printStackTrace();} catch (LineUnavailableException e){e.printStackTrace();} finally { auline.drain(); auline.close(); } }while (cir); } public void play(){ thread=new Thread(this); thread.start();//开始线程 } public void stop(){ thread.stop();//强制关闭 } }
public class Sound { //各种音效 static final String bgm = "音乐图片资源/bgm.wav"; static final String eat_beans = "音乐图片资源/eat_beans.wav"; static final String game_over = "音乐图片资源/game_over.wav"; static final String press_button="音乐图片资源/btn_press.wav"; private static void play(String filepath, boolean cir) {//描述如何播放音乐,包括位置和是否循环 MusicPlayer player = new MusicPlayer(filepath, cir);//创建播放器 player.play();//start to play music } static public void Btn_press(){play(press_button,false);} static public void Game_over(){play(game_over,false);} static public void Eat_food(){play(eat_beans,false);} static public void BGM(){//播放bgm play( bgm, false); } }
5.创建继承于JDialog的类Score用于返回分数信息
public class Score extends JDialog { public int n=0; public Score(Gameframe owner) { super(owner,"分数",false); Container container=getContentPane(); this.setLayout(null); this.setFocusable(false); this.setBounds(300,100,200,200); JLabel score=new JLabel(); score.setText("你的得分是"+GamePanel.u_score); score.setFont(Gameframe.font1); score.setBounds(0,0,200,100); container.add(score); } public Score() { } public int getScore(){ n=n+10; return n; } public int getN() { return n; } }
6.最后创建一个Start类,运行程序
public class Start { public static void main(String[]args){ new Gameframe(); } }
项目结构预览:
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)