贪吃蛇(双缓冲版)

写在前面

首先,从准备到搜集各种资料再到自己动手写出来,确实花了不少时间,其间有过很多的疑惑,bug等,但是最开心的还是游戏运行出来的那一刻。我最开始还是用的定时器来控制的(借鉴自B站的某个视频,这是我在网上找到的比较好理解的)然后在网上又了解到双缓冲(消除闪烁),感觉有必要学一下,就又着手找网上的资料,然后在图书馆找到一本比较有好的书(陈锐等主编的《Java游戏编程原理与实践教程》),里面有关双缓冲的讲解虽不详尽,但是完全够用。看完后就翻出代码进行了一些改写–用了双缓冲。所以,辛苦了前前后后大概一个月搞出来的游戏,还是有必要写点什么的。好了,不多说了,上代码。?
ps:这条路没有尽头,因为爱所以愿意为此肝脑涂地?言重了
希望大家可以学到又或是给出指点。

双缓冲版贪吃蛇

游戏截图

里面的素材都是自己ps搞得,勉勉强强吧?
在这里插入图片描述

DBSnakePanel类
package game.snake.first_try;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;

import javax.swing.ImageIcon;
import javax.swing.JPanel;

public class DBSnakePanel extends JPanel implements KeyListener,Runnable {
	//加载图片
	ImageIcon up = new ImageIcon("up.png");
	ImageIcon down = new ImageIcon("down.png");
	ImageIcon right = new ImageIcon("right.png");
	ImageIcon left = new ImageIcon("left.png");
	ImageIcon body = new ImageIcon("body.png");
	ImageIcon food = new ImageIcon("food.png");
	ImageIcon title = new ImageIcon("title.png");
	
	//数组来存放蛇身体节点的坐标
	int[] snakex = new int[850];
	int[] snakey = new int[850];
	
	int len = 3;  //初始长度
	int score = 0;//初始分数
	String direction = "R"; //初始方向
	
	Random random = new Random();
	//随机生成食物
	int foodx = random.nextInt(36) * 25 + 25; //25-925
	int foody = random.nextInt(24) * 25 + 75; //75-675
	
	boolean foodFitFlag = true;
	boolean isStarted = false;
	boolean isFaild = false;
	
	public Image iBuffer;
	public Graphics gBUffer;
	
	public DBSnakePanel() {
		this.setFocusable(true); 
		initSnake();
		this.addKeyListener(this);
		Thread t = new Thread(this);
		t.start();
	}
	
	//初始化
	public void initSnake() {
		isFaild = false;
		isStarted = false;
		len = 3;
		score = 0;
		direction = "R";
		snakex[0] = 100; 
		snakey[0] = 100; 
		snakex[1] = 75; 
		snakey[1] = 100; 
		snakex[2] = 50; 
		snakey[2] = 100;	
	}
	
	//判断食物生成位置是否在蛇身
	public boolean isFoodFit() {
		for (int i = 0; i < len; i++) {
			if(foodx == snakex[i] && foody == snakey[i]) {
				return false; //食物生成在蛇身
			}
		}
		return true;
	}
	
	@Override
	public void run() {
		while(true) {
			try {
				Thread.sleep(150);
			} catch (Exception e) {}
			
			if(isStarted && !isFaild) {
				//蛇身移动----每个结点等于其前面结点的坐标
				for(int i=len; i>.0; i--) {
					snakex[i] = snakex[i-1];
					snakey[i] = snakey[i-1];
				}
			//蛇头移动
			if(direction.equals("R")) {
				snakex[0] = snakex[0] + 25;
				if(snakex[0] > 900) snakex[0] = 25;
			}else if(direction.equals("L")) {
				snakex[0] = snakex[0] - 25;	
				if(snakex[0] < 25) snakex[0] = 900;
			}else if(direction.equals("U")) {
				snakey[0] = snakey[0] - 25;
				if(snakey[0] < 75) snakey[0] = 675;
			}else if(direction.equals("D")) {
				snakey[0] = snakey[0] + 25;	
				if(snakey[0] > 675) snakey[0] = 75;
			}
			if(snakex[0] == foodx && snakey[0] == foody) {
				len++;
				score++;
				foodx = random.nextInt(36) * 25 + 25;
				foody = random.nextInt(22) * 25 + 75;
			}
			//失败判定
			for(int i = 1; i < len; i++) {
				if(snakex[0] == snakex[i] && snakey[0] == snakey[i]) {
					isFaild = true;
				}
			}
		}
		repaint();
		}
	}
	/** 画板*/
	public void paint(Graphics g) {
		if(iBuffer == null) {
			iBuffer = createImage(this.getSize().width, this.getSize().height);
			gBUffer = iBuffer.getGraphics();
		}
		//画背景
		gBUffer.setColor(Color.BLACK);
		gBUffer.fillRect(25, 75, 900, 625);
		//画标头
		title.paintIcon(this, gBUffer, 25, 10);
		//画蛇头
		if(direction.equals("R")) {
			right.paintIcon(this, gBUffer, snakex[0], snakey[0]);	
		}else if(direction.equals("L")) {
			left.paintIcon(this, gBUffer, snakex[0], snakey[0]);	
		}else if(direction.equals("U")) {
			up.paintIcon(this, gBUffer, snakex[0], snakey[0]);	
		}else if(direction.equals("D")) {
			down.paintIcon(this, gBUffer, snakex[0], snakey[0]);	
		}
		//画蛇身
		for(int i=1; i<len; i++) {
			body.paintIcon(this, gBUffer, snakex[i], snakey[i]);
		}
		//开始游戏提示字幕
		if(!isStarted) {
			gBUffer.setColor(Color.WHITE);
			gBUffer.setFont(new Font("arial",Font.BOLD,30));
			gBUffer.drawString("Press Space to Start or Pause", 230, 350);
		}
		//游戏结束提示
		if(isFaild) {
			gBUffer.setColor(Color.WHITE);
			gBUffer.setFont(new Font("arial",Font.BOLD,30));
			gBUffer.drawString("Game Over,Press Space to Start", 230, 350);
		}
		//画食物
		foodFitFlag = true;
		while(foodFitFlag) {
			if (isFoodFit()) {
				//食物位置合适
				food.paintIcon(this, gBUffer, foodx, foody);
				foodFitFlag = false;
			}else {
				//不合适重新生成
				foodx = random.nextInt(36) * 25 + 25;
				foody = random.nextInt(24) * 25 + 75;
			}
		}
		
		//分数显示
		gBUffer.setColor(Color.WHITE);
		gBUffer.setFont(new Font("arial",Font.PLAIN,15));
		gBUffer.drawString("Score: " + score, 800, 35);
		gBUffer.drawString("Length: " + len, 800, 55);
		
		//将图像一次性的绘制到屏幕上
		g.drawImage(iBuffer, 0, 0, this);
	}
	//还需要重写update才能真正消除闪烁
	@Override
	public void update(Graphics g) {
		paint(g);
	}

	/** 键盘事件*/
	@Override
	public void keyPressed(KeyEvent arg0) {
		//开始暂停控制
		int keyCode = arg0.getKeyCode();
		if(keyCode == KeyEvent.VK_SPACE) {
			if(isFaild) {
				initSnake();
			}else{
				isStarted = !isStarted;
			}
		//设移动控制
		}else if(keyCode == KeyEvent.VK_UP && !direction.equals("D")) {
			direction = "U";
		}else if(keyCode == KeyEvent.VK_DOWN && !direction.equals("U")) {
			direction = "D";
		}else if(keyCode == KeyEvent.VK_LEFT && !direction.equals("R")) {
			direction = "L";
		}else if(keyCode == KeyEvent.VK_RIGHT && !direction.equals("L")) {
			direction = "R";
		}
		
	}
	@Override
	public void keyReleased(KeyEvent arg0) {
		// TODO 自动生成的方法存根
		
	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO 自动生成的方法存根
		
	}
}

主类 Snake
package game.snake.first_try;

import javax.swing.JFrame;

public class Snake {

	public static void main(String[] args) {
		JFrame frame = new JFrame();
		
		frame.setBounds(550, 200, 950, 750);	//边界
		frame.setTitle("贪吃蛇1.0");		//标题
		frame.setResizable(false);		//能否改变大小
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	//退出方式
		
		frame.add(new DBSnakePanel());
		
		frame.setVisible(true);
	}

}

?篇幅有点长了,算了,把定时器版的另发一次吧。

发布了9 篇原创文章 · 获赞 19 · 访问量 1613

猜你喜欢

转载自blog.csdn.net/weixin_42190209/article/details/101566350