ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

如何使用java的WindowBuilder编写贪吃蛇小程序

2020-06-09 11:37:52  阅读:305  来源: 互联网

标签:ImageIcon java int import snakex snakey 贪吃蛇 new WindowBuilder


思路来源

1、摘要
特别感谢上面链接的作者,让我快速理清思路。
我将该作者的代码做了不少改动,转化为我自己的思考。
我的工作如下:
1)设置游戏的等级,让贪吃蛇的运行速度随着等级的变化而改变。
2) 设置了路障,和装饰的草地,以及与贪吃蛇触碰的条件。
3) 设置了三种不同的食物,并考虑了食物和路障的摆放。
4)修复了该作者的bug,包括页面的框架,贪吃蛇移动/死亡的条件等。
5)做了不少UI的调整,包括JPanel背景色、食物、蛇的身体、提示字的位置等。

2、 代码
这份代码只是起到抛转引玉的作用,方便我们了解一个简单的小游戏是如何开发的(感兴趣的朋友可以在web上尝试贪吃蛇游戏)
首先需要根据你们的eclipse版本下载相应版本的WindowBuilder,然后新建一个JPanel部署程序;
值得注意的是,我在工程中新建(或者直接复制粘贴)了一个/pic文件夹,用来存放icon,请大家在学习的时候务必注意图片路径:
MySnakePanel只是测试类,SnakePanel才是我们新建的类

package Jpanel;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random;
import javax.swing.Timer;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;

/*
 * Part1:
 * 设计游戏图纸:画一张900*700的白色窗口
 * 在窗口上添加画布,并在画布上添加标题和游戏区域
 * 第一个问题:蛇的图片如何和画布适应,如何让图片移动
 * Part2:
    初始化放置静态的蛇:一个头、一个身体、一个尾巴
  加上开始提示:按空格键开始游戏
  让蛇动起来:监听Timer事件,平移数据(蛇的身体)
  实现游戏暂停
  实现转向功能(需要蛇头部图片的四个方向)
   Part3:
    添加食物
   吃掉食物
   添加死亡条件
   实现“重新开始”功能
   添加分数、长度和等级(有兴趣的朋友可以增加游戏时间的选项)
 */
public class SnakePanel extends JPanel implements KeyListener, ActionListener {
//初始化图片
	ImageIcon up = new ImageIcon("pic/_up.png");
	ImageIcon down = new ImageIcon("pic/_down.png");
	ImageIcon left = new ImageIcon("pic/_left.png");
	ImageIcon right = new ImageIcon("pic/_right.png");
	ImageIcon food = new ImageIcon("pic/strawberry.png");
	ImageIcon food1 = new ImageIcon("pic/apple.png");
	ImageIcon food2 = new ImageIcon("pic/orange.png");
	ImageIcon body = new ImageIcon("pic/_body.png");
	ImageIcon stone = new ImageIcon("pic/stone.png");
	ImageIcon grass = new ImageIcon("pic/grass.png");
	ImageIcon tail = new ImageIcon("pic/_tail.png");
	ImageIcon title = new ImageIcon("pic/title.jpg");

	int[] snakex = new int[751];
	int[] snakey = new int[651];

	int[] stonex = new int[31];
	int[] stoney = new int[31];
	
	int[] grassx = new int[11];
	int[] grassy = new int[11];

	Random rand = new Random();
	int foodx = rand.nextInt(34) * 25 + 25;
	int foody = rand.nextInt(24) * 25 + 75;
	
	int len = 3;// 一开始只有三节,一个头,一个身体、一个尾巴
	int score = 0;//初始化分数
	int level = 1;
	static int time = 500;//初始化延迟的时间
	int n = 0;// 控制石头
	String direction = "R";//初始化方向

	boolean isStarted = false;// 判断游戏是否开始
	boolean isFailed = false;// 判断游戏是否结束

	Timer timer = new Timer(time, this);// 控制游戏的快慢

	public SnakePanel() {
		this.setFocusable(true);// 获取焦点
		/* 所谓焦点就是被选中的意思,或者说是“当前正在操作的组件”的意思。
		 * 如果一个组件被选中,或者正在被操作者,就是得到了焦点,而相反的,一个组件没有被选中或者失去操作,就是被转移了焦点,焦点已经到   别的组件上去了。
		 * 最明显的两个例子: 一个按钮(button)一旦被选中,就会有一个虚线框在按钮中,并且环绕着按钮的文字,一旦失去焦点,不被操作了,这个虚线框就消失了。
		 * 一个文本框(textfield)一旦被选中,就会有一个“|”在文本框里面闪动,提示可以输入信息,一旦失去或者转移焦点了,这个“|”就没有了,不闪动,
		 * 表示这个文本框你没有在操作。*/
		this.addKeyListener(this);// 监听键盘事件
		//下面都是初始化操作
		setup();
		StoneInitial();
		GrassInitial();
	}   
	public void GrassInitial() {
		Random rand = new Random();
		for(int i=0;i<11;i++) {
			grassx[i] = rand.nextInt(34) * 25 + 25;
			grassy[i] = rand.nextInt(24) * 25 + 75;
		}
	}
	public void GrassPaint(Graphics g) {
		for (int i = 0; i < 11; i++) {
			grass.paintIcon(this, g, grassx[i], grassy[i]);
		}
	}
	public void StoneInitial() {
		Random rand = new Random();
		for (int i = 0; i < 31; i++) {
			stonex[i] = rand.nextInt(34) * 25 + 25;
			stoney[i] = rand.nextInt(24) * 25 + 75;
			while ((stonex[i] == 100 && stoney[i] == 100) || (stonex[i] == 75 && stoney[i] == 100)
					|| (stonex[i] == 50 && stoney[i] == 100)) {//防止与初始化的蛇的身体碰撞,并以此为基准放置石头
				stonex[i] = rand.nextInt(34) * 25 + 25;
				stoney[i] = rand.nextInt(24) * 25 + 75;
				i = 0;
			}
		}
	}
	public void StonePaint(Graphics g) {
		for (int i = 0; i < 31; i++) {
			stone.paintIcon(this, g, stonex[i], stoney[i]); 
		}
	}

	public void Level() {//设置游戏的等级
		if (score > 5 && score <= 10 && level == 1) {
			timer.stop();//timer其实也调用了线程,我们首先要暂定之前的线程再开启新的
			time -= 40;
			level++;
			timer = new Timer(time, this);
		} else if (score > 10 && score <= 20 && level == 2) {
			timer.stop();
			time -= 40;
			level++;
			timer = new Timer(time, this);
		} else if (score > 20 && score <= 30 && level == 3) {
			timer.stop();
			time -= 50;
			level++;
			timer = new Timer(time, this);
		} else if (score > 30 && score <= 40 && level == 4) {
			timer.stop();
			time -= 50;
			level++;
			timer = new Timer(time, this);
		}
		else if (score > 40 && score <= 50 && level == 5) {
			timer.stop();
			time -= 60;
			level++;
			timer = new Timer(time, this);
		}
		else if (score > 50 && score <= 60 && level == 6) {
			timer.stop();
			time -= 60;
			level++;
			timer = new Timer(time, this);
		}
	}

	public void food() {// 要改进
		Random rand = new Random();
		for (int i = 0; i < len; i++) {
			if ((snakex[i] == foodx && snakey[i] == foody)) {
				foodx = rand.nextInt(34) * 25 + 25;// 返回一个大于等于0小于34的随机整数
				foody = rand.nextInt(24) * 25 + 75;
				i = 0;
				continue;//从头开始
			}
			for (int j = 0; j < 31; j++) {
				if ((stonex[j] == foodx && stoney[j] == foody)||Dilemma()) {
					foodx = rand.nextInt(34) * 25 + 25;
					foody = rand.nextInt(24) * 25 + 75;
					j = 0;
					i = 0;
					break;
				}
			}
		}
	}
    
	public boolean Dilemma() {//食物的放置可能出现困境
		for(int i=0;i<29;i++) {//以下是全排列
			for(int j=i+1;j<30;j++) {
				for(int k=j+1;k<31;k++) {
					if ((stonex[i]+25 == foodx && stonex[j]-25 == foodx && stoney[k]-25==foody)||
							(stonex[i]+25 == foodx && stonex[j]-25 == foodx && stoney[k]+25==foody)) {
						return true;
					}
				}
			}
		}
		return false;
	}
	
	public void setup() {// 游戏初始化
		isStarted = false;
		isFailed = false;
		len = 3;
		score = 0;
		level=1;
		n=0;
		time=500;
		direction = "R";
		snakex[0] = 100;
		snakex[1] = 75;
		snakex[2] = 50;
		snakey[0] = 100;
		snakey[1] = 100;
		snakey[2] = 100;
		GrassInitial();//草和石头放置的初始化
		StoneInitial();
		timer.start();
	}

	@Override
	public void keyPressed(KeyEvent e) {//控制键盘的上下左右
		int KeyCode = e.getKeyCode();
		if (isStarted) {
			if (KeyCode == KeyEvent.VK_SPACE) {
				if (isFailed) {
					setup();
				} else {
					isStarted = !isStarted;// 暂停和开始
				}
			} else if (KeyCode == KeyEvent.VK_UP && direction != "D") {
				direction = "U";
			} else if (KeyCode == KeyEvent.VK_DOWN && direction != "U") {
				direction = "D";
			} else if (KeyCode == KeyEvent.VK_RIGHT && direction != "L") {
				direction = "R";
			} else if (KeyCode == KeyEvent.VK_LEFT && direction != "R") {
				direction = "L";
			}
		} else {
			if (KeyCode == KeyEvent.VK_SPACE) {
				if (isFailed) {
					setup();
				} else {
					isStarted = !isStarted;// 暂停和开始
				}
			}
		}
	}
	public void paint(Graphics g) {// Graphics 画笔
		g.setColor(Color.orange); // 设置画布背景颜色
		title.paintIcon(this, g, 25, 11);// 放置主题图片,从(25,11)处为title的左上角,放置图片
		g.fillRect(25, 75, 850, 600); // 用画笔设置游戏方框

		//画草
		GrassPaint(g);
		// 画石头
		StonePaint(g);

		// 画蛇头(注意判断蛇头的方向)
		if (direction.equals("R"))
			right.paintIcon(this, g, snakex[0], snakey[0]);
		else if (direction.equals("L"))
			left.paintIcon(this, g, snakex[0], snakey[0]);
		else if (direction.equals("U"))
			up.paintIcon(this, g, snakex[0], snakey[0]);
		else if (direction.equals("D"))
			down.paintIcon(this, g, snakex[0], snakey[0]);

		// 画蛇的身体
		for (int i = 1; i < len-1; i++)
			body.paintIcon(this, g, snakex[i], snakey[i]);
		
		//画蛇尾
		tail.paintIcon(this, g, snakex[len-1],snakey[len-1]);

		// 判断如果游戏没开始,需要显示的字段
		if (!isStarted) {
			g.setColor(Color.WHITE);
			g.setFont(new Font("arial", Font.BOLD, 28));
			g.drawString("Press Space to start / pause", 250, 320);
		}
		// 判断如果游戏失败,需要显示的字段
		if (isFailed) {
			timer.stop();
			g.setColor(Color.WHITE);
			g.setFont(new Font("arial", Font.BOLD, 28));
			g.drawString("Game Over ! Press space to restart", 250, 320);
		}
		// 显示食物
		food();
		if(foodx % 3 == 0)
		    food.paintIcon(this, g, foodx, foody);
		else if((foodx+1) % 3==0)
			food1.paintIcon(this, g, foodx, foody);
		else
			food2.paintIcon(this, g, foodx, foody);
		
		// 设置分数和蛇的长度,以及等级,我最高设置了等级七
		g.setColor(Color.WHITE);
		g.setFont(new Font("arial", Font.PLAIN, 15));
		g.drawString("Score : " + score, 650, 37);
		g.drawString("SnakeLength :" + len, 650, 57);
		g.drawString("Level :" + level, 725, 37);
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		// 1.再定义一个闹钟
		Level();
		timer.start();
		// 2.移动
		if (isStarted && !isFailed) {
			// 移动身体
			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] > 850)
					snakex[0] = 25;
			} else if (direction.equals("L")) {
				snakex[0] = snakex[0] - 25;
				if (snakex[0] < 25)
					snakex[0] = 850;
			} else if (direction.equals("U")) {
				snakey[0] = snakey[0] - 25;
				if (snakey[0] < 75)
					snakey[0] = 650;
			} else if (direction.equals("D")) {
				snakey[0] = snakey[0] + 25;
				if (snakey[0] > 650) // 底下应该是650
					snakey[0] = 75;
			}
			if (snakex[0] == foodx && snakey[0] == foody) {
				len++;
				score++;
				foodx = rand.nextInt(34) * 25 + 25;
				foody = rand.nextInt(24) * 25 + 75;
			}
			for (int i = 1; i < len; i++) {
				if (snakex[0] == snakex[i] && snakey[0] == snakey[i]) {
					isFailed = true;
				}
			}
			for (int i = 0; i < len; i++) {
				for (int j = 1; j < 31; j++) {
					if (stonex[j] == snakex[i] && stoney[j] == snakey[i]) {
						isFailed = true;
					}
				}
			}
		}
		// 3. repaint()
		repaint();
	}

	@Override
	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
	}

	@Override
	public void keyReleased(KeyEvent e) {
		// TODO Auto-generated method stub
	}

	public static void main(String[] args) {
		JFrame frame = new JFrame(); // 创建一个游戏界面的框架
		frame.setBounds(0, 0, 900, 720); // 设置框架的大小
		
		java.awt.Toolkit toolkit = java.awt.Toolkit.getDefaultToolkit();//下面的代码是让框架在屏幕正中间
		Dimension screenSize = toolkit.getScreenSize();
		double screenWidth = screenSize.getWidth();
		double screenHeight = screenSize.getHeight();
		frame.setLocation((int) (screenWidth - frame.getWidth()) / 2, (int) (screenHeight - frame.getHeight()) / 2);

		frame.setResizable(false); // 设置框架大小为不能改变
		// 点击关闭按钮 关闭游戏界面
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		SnakePanel panel = new SnakePanel(); // 添加画布
		frame.add(panel); // 刚添加时画布是空的看不到

		frame.setVisible(true); // 允许显示游戏界面
	}
}

特别注意:调用repaint()这个回调函数的时候,paint(Graphics g)就被调用了。方法在线程里控制,一般都要不断刷屏来显示画面,我们不用理会。

3、运行图片:
demo2.0版本的贪吃蛇
demo1.0版本的贪吃蛇

4、icon素材:
链接:[百度网盘图片下载地址] https://pan.baidu.com/s/1UlfcIzKBysqUv4cG89VHfg 提取码:bl42

5、寄语:
希望大家共同进步,如有不足,希望可以指正!转载请注明出处,谢谢!!!

标签:ImageIcon,java,int,import,snakex,snakey,贪吃蛇,new,WindowBuilder
来源: https://blog.csdn.net/qq_44853197/article/details/106626402

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有