赞
踩
写个小游戏练习一下。
蛇头、蛇身、食物位置都是一个在背景图片上的点(坐标),再根据这个点去绘制图片;
共设计了包括测试类在内的6个类:
1、ImageUtil类: 加载所有图片,作为静态属性,通过类名直接调用;
2、DrawImage类:绘制类,绘制游戏中所有的东西;
3、Snake类:蛇类,控制蛇的移动,吃食物,判断游戏是否结束;
4、Food类:随机产生食物,食物被吃产生新的食物;
5、Listener类:监听类,时间监听,键盘监听;
6、Demo类:测试类。
1、绘制图片时闪烁;解决办法:双重缓冲绘制。
2、蛇移动后如何正确绘制蛇头蛇身位置(即重新设置坐标);我的解决办法较简单:根据背景图片大小、蛇头、蛇身大小去初始化蛇头蛇身的坐标,并设置蛇每次移动的距离为蛇身大小。(可以进行优化)
3、如何确保食物可以被吃;解决办法:根据背景图片、蛇头、蛇身大小和蛇移动的距离去设置食物可以出现的坐标;食物必须出现在蛇头可以经过的坐标。(可以进行优化)
4、蛇移动速度快,待优化。
像素:960 x 640
像素:32 x 32
像素:32 x 32
像素:32 x 41
/*
960/32 = 30;
640/32 = 20;
初始化蛇头蛇身
snakeHead = new Point(160,160);
linkedList.add(new Point(128,160));
linkedList.add(new Point(96,160));
蛇移动距离为32
食物产生位置
foodP.x = random.nextInt(30) * 32;//x:大于等于0小于等于29的随机数再乘32
foodP.y = (random.nextInt(19) + 1) * 32;//y:大于等于1小于等于19的随机数再乘32
*/
package mySnake; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.File; import java.io.IOException; //照片资源类 public class ImageUtil { public static BufferedImage background; public static BufferedImage food; public static BufferedImage snake_headR; public static BufferedImage snake_headL; public static BufferedImage snake_headU; public static BufferedImage snake_headD; public static BufferedImage snake_body; public static BufferedImage fail; public static BufferedImage iconImage; static { try { background = ImageIO.read(new File("src\\image\\背景.png"));//读取照片 food = ImageIO.read(new File("src\\image\\food.png")); snake_headR = ImageIO.read(new File("src\\image\\蛇头-右.png")); snake_headL = ImageIO.read(new File("src\\image\\蛇头-左.png")); snake_headU = ImageIO.read(new File("src\\image\\蛇头-上.png")); snake_headD = ImageIO.read(new File("src\\image\\蛇头-下.png")); snake_body = ImageIO.read(new File("src\\image\\蛇身.png")); fail = ImageIO.read(new File("src\\image\\fail.png")); iconImage = ImageIO.read(new File("src\\image\\图标.png")); } catch (IOException e) { e.printStackTrace(); } } }
package mySnake; import javax.swing.*; import java.awt.*; import java.awt.image.BufferedImage; import java.util.LinkedList; //绘制所有图片的界面类 public class DrawImage extends JFrame{ //蛇 private Snake snake = new Snake(); //蛇头坐标 private Point snakeP; //蛇身 private LinkedList linkedList; //食物 private Food food = new Food(); private Point foodP = new Point(); //时间计时 private Timer timer; //蛇头照片 private BufferedImage snake_head = ImageUtil.snake_headR;//初始向右 //监听器类的对象 Listener listener = new Listener(this,snake,food); //组装 public DrawImage(){ super("贪吃蛇"); //时间计时 timer = new Timer(200,listener.getActionListener()); timer.start(); //注册键盘监听器 addKeyListener(listener.getKeyListener()); //设置窗体图标 setIconImage(ImageUtil.iconImage); //设置窗体 setSize(ImageUtil.background.getWidth(),ImageUtil.background.getHeight() ); setLocationRelativeTo(null); setResizable(false); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(true); } //双重缓冲解决图片闪烁 //进行绘制 @Override public void paint(Graphics g) { Image image = this.createImage(ImageUtil.background.getWidth(), ImageUtil.background.getHeight()); Graphics gImage = image.getGraphics(); gImage.setColor(gImage.getColor()); gImage.fillRect(0,0,ImageUtil.background.getWidth(),ImageUtil.background.getHeight() ); super.paint(gImage); //绘制背景 gImage.drawImage(ImageUtil.background,0 ,0 ,null ); //判断游戏是否结束 if(!snake.isOver()) { //游戏继续 snakeP = snake.getSnakeHead();//蛇头坐标 linkedList = snake.getLinkedList();//蛇身 foodP = food.getFoodP();//食物坐标 //绘制食物 gImage.drawImage(ImageUtil.food, foodP.x, foodP.y, null); //绘制蛇头 gImage.drawImage(snake_head, snakeP.x, snakeP.y, null); //绘制蛇身 for (int i = 0; i < linkedList.size(); i++) { Point p = (Point) linkedList.get(i); gImage.drawImage(ImageUtil.snake_body, p.x, p.y, null); } } else{ //游戏结束 //绘制结束图片 gImage.drawImage(ImageUtil.fail, 250, 200,null ); //时间计时结束 timer.stop(); } //最后绘制缓冲后的图片 g.drawImage(image,0 ,0 , null); } //改变绘制蛇头的图片 public void setSnake_head(BufferedImage image){ snake_head = image; } }
package mySnake; import java.awt.*; import java.util.LinkedList; //蛇类 public class Snake { //蛇头位置用点表示 private Point snakeHead; //蛇身用LinkedList进行储存 private LinkedList<Point> linkedList = new LinkedList<>(); //蛇头移动速度 private int speed_x = 32; private int speed_y = 0; //蛇是否死亡 private boolean isOver = false; //蛇移动方向 //蛇头走向 1:右 -1:左 2:上 -2:下 private int direction = 1;//默认向右 //记录蛇最后一节身体坐标,吃到食物时添加 private Point p = new Point(); public Snake(){ //初始化蛇头蛇身 snakeHead = new Point(160,160); linkedList.add(new Point(128,160)); linkedList.add(new Point(96,160)); } //返回游戏是否继续 public boolean isOver() { return isOver; } //返回蛇身 public LinkedList<Point> getLinkedList() { return linkedList; } //返回蛇头坐标 public Point getSnakeHead() { return snakeHead; } //返回蛇头移动方向 public int getDirection(){ return direction; } //改变蛇移动的x方向速度 public void setSpeed_x(int speed_x) { this.speed_x = speed_x; } //改变蛇移动的y方向速度 public void setSpeed_y(int speed_y) { this.speed_y = speed_y; } //改变蛇头移动方向 public void setDirection(int direction) { this.direction = direction; } //蛇移动 public void move(){ //蛇身移动,在linkedList第一个添加蛇身坐标就是蛇头坐标,然后删除最后一个蛇身坐标,返回的坐标为蛇吃到食物时添加的坐标 linkedList.addFirst(new Point(snakeHead.x,snakeHead.y)); p = linkedList.pollLast(); //蛇头移动 snakeHead.move(snakeHead.x + speed_x, snakeHead.y + speed_y); //判断是否出界和碰到自身 setIsOver(); isEatOneself(); } //边界问题 //蛇头是否出界 private void setIsOver(){ int x = snakeHead.x; int y = snakeHead.y; if(x < 0 || y < 32) isOver = true; else if(x > (ImageUtil.background.getWidth() - 32) || y > (ImageUtil.background.getHeight() - 32)) isOver = true; } //判断蛇头是否碰到蛇身 private void isEatOneself(){ //循环判断 for(int i = 0;i < linkedList.size();i ++){ if(snakeHead.equals(linkedList.get(i))){ isOver = true; break; } } } //吃食物 public void eatFood(Food food){ //判断依据:蛇移动方向上蛇头与食物是否在一条线上,若在再根据之间的距离判断是否相碰 if((direction == 1 || direction == -1) && (snakeHead.y == food.getFoodP().y)){ if(Math.abs(snakeHead.x - food.getFoodP().x) <= 32 ){ food.isEat(); linkedList.addLast(p); } } if((direction == 2 || direction == -2) && (snakeHead.x == food.getFoodP().x)){ if(Math.abs(snakeHead.y - food.getFoodP().y) <= 32){ food.isEat(); linkedList.addLast(p); } } } }
package mySnake; import java.awt.*; import java.util.Random; //食物类 public class Food { //产生随机数对象 Random random = new Random(); //食物坐标 private Point foodP = new Point(); //代码块初始化食物 { setFoodP(); } //随机产生食物 private void setFoodP(){ foodP.x = random.nextInt(30) * 32; foodP.y = (random.nextInt(19) + 1) * 32; } //食物被吃 public void isEat(){ //重新生产食物 setFoodP(); } //返回食物坐标 public Point getFoodP() { return foodP; } }
package mySnake; import java.awt.event.*; //外部监听类 public class Listener { private Snake snake; private Food food; private DrawImage drawImage; public Listener(DrawImage drawImage,Snake snake,Food food){ this.drawImage = drawImage; this.snake = snake; this.food = food; } //返回ActionListener public ActionListener getActionListener() { return actionListener; } //返回KeyListener public KeyListener getKeyListener() { return keyListener; } private ActionListener actionListener = new ActionListener() { @Override public void actionPerformed(ActionEvent e) { snake.move(); snake.eatFood(food); drawImage.repaint(); } }; //键盘监听器 private KeyListener keyListener = new KeyAdapter() { @Override public void keyPressed(KeyEvent e) { //获取按键对应的值 int keyCode = e.getKeyCode(); //获取蛇移动方向 int direction = snake.getDirection(); //蛇头走向 1:右 -1:左 2:上 -2:下 //按下左键且蛇不向右走时 if(keyCode == KeyEvent.VK_LEFT && direction != 1){ //改变蛇移动方向 snake.setDirection(-1); //改变速度 snake.setSpeed_x(-32); snake.setSpeed_y(0); //蛇移动 snake.move(); //每次移动后让蛇吃食物 snake.eatFood(food); //改变蛇头图片 drawImage.setSnake_head(ImageUtil.snake_headL); } //右 if(keyCode == KeyEvent.VK_RIGHT && direction != -1){ snake.setDirection(1); snake.setSpeed_x(32); snake.setSpeed_y(0); snake.move(); snake.eatFood(food); drawImage.setSnake_head(ImageUtil.snake_headR); } //上 if(keyCode == KeyEvent.VK_UP && direction != -2){ snake.setDirection(2); snake.setSpeed_x(0); snake.setSpeed_y(-32); snake.move(); snake.eatFood(food); drawImage.setSnake_head(ImageUtil.snake_headU); } //下 if(keyCode == KeyEvent.VK_DOWN && direction != 2){ snake.setDirection(-2); snake.setSpeed_x(0); snake.setSpeed_y(32); snake.move(); snake.eatFood(food); drawImage.setSnake_head(ImageUtil.snake_headD); } } }; }
package mySnake;
//测试类
public class Demo {
public static void main(String[] args) {
new DrawImage();
}
}
游戏界面
游戏结束界面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。