java做的贪吃蛇游戏
设计思想
在图形界面上连续摆放相同的图片来表示蛇身和食物,更换图片的位置来代表蛇的移动。
准备
先弄几张图片来做蛇身和食物。为了在放置时可以更方便的使用像素点坐标来表示蛇的位置,所以在准备的时候就把每张图片的像素都定为25×25.这样图片就可以对齐。
封装图片
把图片封装为对象,以更好的调用。
(这里我只放了两个图片的代码,可以自己弄好多图片。)
package Snake;
import javax.swing.*;
import java.net.URL;
/**
*把图片封装成一个类
* 这个类用来获取图片
* @author mahongwei
*/
public class Images {
/**
* 将图片的路径封装为对象:****URL
* 将把路径的图片封装为对象:****Img
*/
public static URL bodyURL = Images.class.getResource("/image/body.png");
public static ImageIcon bodyImg = new ImageIcon(bodyURL);
public static URL foodURL = Images.class.getResource("/image/food.png");
public static ImageIcon foodImg = new ImageIcon(foodURL);
}
绘制游戏面板
- 绘制一个800×800像素的JForm。定放置在屏幕中央。
JFrame jf = new JFrame("Snake Game");
//获取屏幕宽度、高度:
int width = Toolkit.getDefaultToolkit().getScreenSize().width;
int height = Toolkit.getDefaultToolkit().getScreenSize().height;
jf.setBounds((width-800)/2,(height-800)/2,800,800);
//固定窗体大小:
jf.setResizable(false);
//关闭窗口的同时,关闭程序:
jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
jf.setVisible(true);
- 定义一个GamePanel。
1、放置一个游戏header(为了美观)。
放置时,只要确定该图片的像素坐标,以确保它在合适的位置。
protected void paintComponent(Graphics g) {
super.paintComponent(g);
this.setBackground(new Color(189, 182, 182));
Images.headerImg.paintIcon(this,g,10,10);
}
2、创建一个矩形区域作为游戏区域,改变颜色,让效果更直观。
g.setColor(new Color(154, 183, 191, 255));
g.fillRect(10,95,764,653);
3、在矩形区域的四周放置“墙”(图片)。放置要求:需要确定墙之内的
//设置四周的墙
for (int i=3; i<29; i++) {
Images.wallImg.paintIcon(this, g, 5, 21 + 25 * i);
}
for (int i=3; i<29; i++) {
Images.wallImg.paintIcon(this, g, 755, 21 + 25 * i);
}
for (int i=1; i<30; i++) {
Images.wallImg.paintIcon(this, g, 5 + 25 * i, 96);
}
for (int i=1; i<30; i++) {
Images.wallImg.paintIcon(this, g, 5 + 25 * i, 721);
}
4、生成静态的小蛇。
用两个数组来存放蛇的位置。(后期可以优化为用链表)
/**
*定义两个数组,存储蛇的X轴Y轴
*snakeX[0],snakeX[0]代表蛇头
*/
int[] snakeX = new int[300];
int[] snakeY = new int[300];
定义变量来表示蛇头的方向,一方面是为了放置不同蛇头图片,更重要的是为蛇的移动做准备。
/**
* direction定义蛇头的方向
*/
String direction;
此时给定蛇的坐标就已经可以绘制静态的蛇了。
5、让蛇移动。
过程就是把倒数第二个身体的坐标给倒数第一个,把倒数第三个身体的坐标给倒数第二个,以此类推。蛇头就依据当前蛇头的方向来选择向哪个方向移动25个像素点。
for (int i = len - 1; i > 0; i--) {
snakeX[i] = snakeX[i - 1];
snakeY[i] = snakeY[i - 1];
}
if ("R".equals(direction)) {
snakeX[0] = snakeX[0] + 25;
}
if ("L".equals(direction)) {
snakeX[0] = snakeX[0] - 25;
}
if ("U".equals(direction)) {
snakeY[0] = snakeY[0] - 25;
}
if ("D".equals(direction)) {
snakeY[0] = snakeY[0] + 25;
}
//绘制蛇身:这里我用了四张图片,来分别代表蛇的四个不同的方向。
if ("R".equals(direction)) {
Images.rightImg.paintIcon(this, g, snakeX[0], snakeY[0]);
}
if ("L".equals(direction)) {
Images.leftImg.paintIcon(this, g, snakeX[0], snakeY[0]);
}
if ("U".equals(direction)) {
Images.upImg.paintIcon(this, g, snakeX[0], snakeY[0]);
}
if ("D".equals(direction)) {
Images.downImg.paintIcon(this, g, snakeX[0], snakeY[0]);
}
for (int i = 1; i<len; i++) {
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
6、下面完成蛇向不同方向的移动。
定义监听事件,来监听键盘按键,并且来改变蛇头方向。(这里做了一个限制,不让蛇直接掉头)
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {
super.keyPressed(e);
int keyCode = e.getKeyCode();
//方向键改变蛇头
if (keyCode == KeyEvent.VK_LEFT) {
if (!"R".equals(direction)) {
direction = "L";
}
}
if (keyCode == KeyEvent.VK_RIGHT) {
if (!"L".equals(direction)) {
direction = "R";
}
}
if (keyCode == KeyEvent.VK_UP) {
if (!"D".equals(direction)) {
direction = "U";
}
}
if (keyCode == KeyEvent.VK_DOWN) {
if (!"U".equals(direction)) {
direction = "D";
}
}
}
});
7、下面就是该生成食物了。
生成食物时要判定不要生成到墙外或者蛇身上。
/**
* foodX--食物的X坐标
* foodY--食物的Y坐标
*/
int foodX,foodY;
/**
* chonghe 检测食物和蛇身重合
*/
Random random = new Random();
boolean chonghe = false;
/**
* 初始化食物坐标,如果重合就再生成一次。
*/
public void initFoodXY() {
do {
foodX = 30+25 * random.nextInt(29);
foodY = 121+25 * random.nextInt(24);
for (int i = 0; i <len; i++) {
if ( foodX == snakeX[i] && foodY == snakeY[i]) {
chonghe = true;
}
else {
chonghe = false;
}
}
} while (chonghe);
}
//放置食物
Images.foodImg.paintIcon(this,g,foodX,foodY);
8、检测蛇是否吃到。
就是检测蛇头的坐标是不是和食物重合(相等)。
若相等就蛇长+1,重新生成食物坐标。
if (snakeX[0] == foodX && snakeY[0] == foodY) {
initFoodXY();
len++;
}
因为蛇的移动是倒数第二给倒数第一赋值,,长度+1就会为一个新的变量赋予蛇尾的坐标值。
9、蛇死的判定,撞墙或是撞到自己。
撞到之后暂停游戏,重置位置。该功能的实现需要添加事件监听。
timer = new Timer(150-len, new ActionListener() {
//事件监听,每delay处理一下
@Override
public void actionPerformed(ActionEvent e) {
}
}
下面的代码是要放在事件监听里面的
//超出界限
if (snakeX[0] == 755
||snakeX[0] == 5
||snakeY[0] ==96
||snakeY[0] ==721) {
isStart = false;
init();
}
//碰到身体
for (int i = 1; i <len; i++) {
if ( snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
isStart = false;
init();
}
}
创建类GamePanel
GamePanel gp = new GamePanel();
jf.add(gp);
结尾
这里仅是主要的思想和代码实现。
待优化
- 用链表代替数组来存放蛇身的坐标。可以加快移动时的处理速度。
- 蛇身在移动时不重新绘制所有的图片,而是只改变真正移动的图片。
运行界面。