狂神说的贪吃蛇 游戏
帧,如果时间片足够小,就是动画,一秒30帧 60帧,连起来就是动画,拆开就是静态的图片!
键盘监听
定时器timer
实现思路
-
将素材引入 -
创建一个窗口,导入头部图片 -
绘制一个850 * 900像素的游戏区域 -
导入贪吃蛇的头部(上下左右)和身体图片 -
导入食物素材用随机数方法让它在游戏区域内生成 -
创建空格的监听事件 -
判断失败的状态
首先创建一个java项目,在项目里我们创建开始游戏类(StartGame)和游戏界面类(GamePanel)还有存放外部数据的类(data)
StartGame类的代码
//游戏的主体启动类
public class StartGame {
? ?public static void main(String[] args) {
? ? ? ?//1.绘制一个静态窗口 JFrame
? ? ? ?JFrame frame = new JFrame("贪吃蛇小游戏");
? ? ? ?//设置界面大小
? ? ? ?frame.setBounds(10,10,900,720);
? ? ? ?frame.setResizable(false); // 窗口大小则不可以改变
? ? ? ?frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); // 用户单击窗口的关闭按钮时程序执行的操作退出
?
? ? ? ?//2.面板 JPanel
? ? ? ?frame.add(new GamePanel()); // 新建一个对象添加游戏区域
? ? ? ?frame.setVisible(true);
?
? }
}
GamelPanel类的代码
各种变量的定义
public class GamePanel extends JPanel implements KeyListener, ActionListener {// 初始化
? ?int length; // 蛇的长度
? ?int[] snakeX = new int[700]; // 蛇的坐标X
? ?int[] snakeY = new int[600]; // 蛇的坐标Y
? ?String state; // R:右 L:左 U:上 D:下
? ?boolean isStart = false; // 游戏是否开始
? ?Timer timer = new Timer(300, this); //定时器
? ?int foodX; // 定义食物的坐标
? ?int foodY;
? ?Random random = new Random();
? ?boolean isFail = false; // 死亡判断
? ?int score; // 分数
}
写一个构造器方法实现初始化方法
注意setFocusable方法为将此 Component 的焦点状态设置为指定值。此值覆盖 Component 的默认焦点状态。
public GamePanel() {
? ? ? ?init();
? ? ? ?// 获取键盘的监听事件
? ? ? ?this.setFocusable(true);
? ? ? ?this.addKeyListener(this); // 让当前游戏区域实现键盘监听事件
? ? ? ?timer.start(); // 让时间动起来
? }
初始化
//初始化
? ?public void init() {
? ? ? ?length = 3;
? ? ? ?snakeX[0] = 110;
? ? ? ?snakeY[0] = 100;
? ? ? ?snakeX[1] = 85;
? ? ? ?snakeY[1] = 100;
? ? ? ?snakeX[2] = 60;
? ? ? ?snakeY[2] = 100;
? ? ? ?state = "R";
? ? ? ?foodX = 25 + 25 * random.nextInt(34); // 随机数范围为25 + 850的随机数
? ? ? ?foodY = 75 + 25 * random.nextInt(24); // 随机数范围为75 + 600的随机数
? ? ? ?int score = 0; // 默认积分为0分
? }
继承了JPanel需要重写painComponent方法
有一个类继承了了jpanel,然后在里面重写了paintcompaint,以实现设置jpanel中背景图的目的重写是为了将图片重新描绘在面板中
// 画板:画界面,画蛇
? ?//Grapics : 画笔
? ?@Override
? ?protected void paintComponent(Graphics g) {
? ? ? ?super.paintComponent(g); //清屏
? ? ? ?this.setBackground(Color.WHITE);
?
? ? ? ?// 绘制头部的广告栏
? ? ? ?data.header.paintIcon(this, g, 25, 11);
?
? ? ? ?// 绘制游戏区域
? ? ? ?g.fillRect(25, 75, 850, 600);
?
? ? ? ?// 画一条小蛇
? ? ? ?switch (state) {
? ? ? ? ? ?case "R":
? ? ? ? ? ? ? ?data.right.paintIcon(this, g, snakeX[0], snakeY[0]);
? ? ? ? ? ? ? ?break;
? ? ? ? ? ?case "L":
? ? ? ? ? ? ? ?data.left.paintIcon(this, g, snakeX[0], snakeY[0]);
? ? ? ? ? ? ? ?break;
? ? ? ? ? ?case "U":
? ? ? ? ? ? ? ?data.up.paintIcon(this, g, snakeX[0], snakeY[0]);
? ? ? ? ? ? ? ?break;
? ? ? ? ? ?default:
? ? ? ? ? ? ? ?data.down.paintIcon(this, g, snakeX[0], snakeY[0]);
? ? ? ? ? ? ? ?break;
? ? ? }
? ? ? ?for (int i = 1; i < length; i++) {
? ? ? ? ? ?data.body.paintIcon(this, g, snakeX[i], snakeY[i]);
? ? ? }
? ? ? ?data.food.paintIcon(this, g, foodX, foodY); // 画随机的食物
实现keyListener接口要重写键盘的监听事件
//接收键盘的输入:监听
? ?@Override
? ?public void keyPressed(KeyEvent e) {
? ? ? ?// 键盘按下,未释放
? ? ? ?// 获取按下的键盘是哪个键
? ? ? ?int key = e.getKeyCode();
?
? ? ? ?if (key == KeyEvent.VK_SPACE) { // 如果按下的是空格键
? ? ? ? ? ?// 如果按下的是空格重新开始游戏
? ? ? ? ? ?if (isFail == true) { // 失败,游戏重新再来
? ? ? ? ? ? ? ?isFail = false;
? ? ? ? ? ? ? ?init(); // 重新初始化游戏
? ? ? ? ? } else {
? ? ? ? ? ? ? ?isStart = !isStart;
? ? ? ? ? }
? ? ? ? ? ?repaint(); //刷新界面
? ? ? }
? ? ? ?// 键盘控制方向
? ? ? ?if (key == KeyEvent.VK_LEFT) {
? ? ? ? ? ?state = "L";
? ? ? } else if (key == KeyEvent.VK_RIGHT) {
? ? ? ? ? ?state = "R";
? ? ? } else if (key == KeyEvent.VK_UP) {
? ? ? ? ? ?state = "U";
? ? ? } else if (key == KeyEvent.VK_DOWN) {
? ? ? ? ? ?state = "D";
? ? ? }
? }
? ?@Override
? ?public void keyTyped(KeyEvent e) {
? ? ? ?// 键盘按下,弹起:敲击
? }
?
? ?@Override
? ?public void keyReleased(KeyEvent e) {
? ? ? ?// 释放某个键
? }
要是想让小蛇动起来需要添加一个定时器,即每过1秒刷新10帧。。。因为我面的for循环除了脑袋都往前移:身体移动即第i节(后一节)的位置变为(i-1:前一节)节的位置!以此每刷新一次帧就会上下左右动起来。
// 定时器,监听时间,帧
? ?@Override
? ?public void actionPerformed(ActionEvent e) {
? ? ? ?// 如果游戏处于开始状态
? ? ? ?if (isStart == true && isFail == false) {
? ? ? ? ? ?// 右移
? ? ? ? ? ?for (int i = length - 1; i > 0; i--) {
? ? ? ? ? ? ? ?snakeX[i] = snakeX[i - 1]; // 身体移动
? ? ? ? ? ? ? ?snakeY[i] = snakeY[i - 1];
? ? ? ? ? }
? ? ? ? ? ?// 通过控制方向让头部移动
? ? ? ? ? ?if (state.equals("R")) {
? ? ? ? ? ? ? ?snakeX[0] = snakeX[0] + 25; // 头部移动
? ? ? ? ? ? ? ?// 边界判断
? ? ? ? ? ? ? ?if (snakeX[0] > 850) {
? ? ? ? ? ? ? ? ? ?snakeX[0] = 25;
? ? ? ? ? ? ? }
? ? ? ? ? } else if (state.equals("L")) {
? ? ? ? ? ? ? ?snakeX[0] = snakeX[0] - 25;
? ? ? ? ? ? ? ?if (snakeX[0] < 25) {
? ? ? ? ? ? ? ? ? ?snakeX[0] = 850;
? ? ? ? ? ? ? }
? ? ? ? ? } else if (state.equals("U")) {
? ? ? ? ? ? ? ?snakeY[0] = snakeY[0] - 25;
? ? ? ? ? ? ? ?if (snakeY[0] < 75) {
? ? ? ? ? ? ? ? ? ?snakeY[0] = 650;
? ? ? ? ? ? ? }
? ? ? ? ? } else if (state.equals("D")) {
? ? ? ? ? ? ? ?snakeY[0] = snakeY[0] + 25;
? ? ? ? ? ? ? ?if (snakeY[0] > 650) {
? ? ? ? ? ? ? ? ? ?snakeY[0] = 75;
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? ?// 如果小蛇的头部和食物重合
? ? ? ? ? ?if (snakeX[0] == foodX && snakeY[0] == foodY) {
? ? ? ? ? ? ? ?//长度加一节
? ? ? ? ? ? ? ?length += 1;
? ? ? ? ? ? ? ?score += 10;
? ? ? ? ? ? ? ?// 刷新食物
? ? ? ? ? ? ? ?foodX = 25 + 25 * random.nextInt(34); // 随机数范围为25 + 850的随机数
? ? ? ? ? ? ? ?foodY = 75 + 25 * random.nextInt(24); // 随机数范围为75 + 600的随机数
// ? ? ? ? ? ? ? snakeX[length - 1] = 999999; // 将增长的身体坐标移除到游戏区域外
// ? ? ? ? ? ? ? snakeY[length - 1] = 999999;
? ? ? ? ? ? ? ?snakeX[length-1] = foodX-1;
? ? ? ? ? ? ? ?snakeY[length-1] = foodY-1;
? ? ? ? ? }
?
? ? ? ? ? ?// 如果小蛇碰到了身体
? ? ? ? ? ?for (int i = 1; i < length; i++) {
? ? ? ? ? ? ? ?if (snakeX[0] == snakeX[i] && snakeY[0] == snakeY[i]) {
? ? ? ? ? ? ? ? ? ?isFail = true;
? ? ? ? ? ? ? }
? ? ? ? ? }
? ? ? ? ? ?// 刷新界面
? ? ? ? ? ?repaint();
? ? ? }
? ? ? ?timer.start(); // 让时间动起来
? }
游戏开始失败和积分系统
// 游戏提示,是否开始
? ? ? ?if (isStart == false) {
? ? ? ? ? ?// 画一个文字,String
? ? ? ? ? ?g.setColor(Color.WHITE); //设置画笔颜色
? ? ? ? ? ?g.setFont(new Font("黑体", Font.BOLD, 40)); //画笔的字体风格
? ? ? ? ? ?g.drawString("按空格开始游戏", 300, 300);
? ? ? }
?
? ? ? ?// 失败提醒
? ? ? ?if (isFail == true) {
? ? ? ? ? ?// 画一个文字,String
? ? ? ? ? ?g.setColor(Color.RED);
? ? ? ? ? ?g.setFont(new Font("黑体", Font.BOLD, 40));
? ? ? ? ? ?g.drawString("游戏失败,按下空格重新开始游戏", 200, 300);
? ? ? }
? ? ? ?// 积分系统
? ? ? ?g.setColor(Color.WHITE);
? ? ? ?g.setFont(new Font("黑体", Font.BOLD, 18));
? ? ? ?g.drawString("长度:" + length, 750, 35);
? ? ? ?g.drawString("分数:" + score, 750, 50);
? }
data类的代码
//存入外部数据
public class data {
? ?// 头部的图片 URL
? ?public static URL headerURL = data.class.getResource("/statics/header.png");// URL:定位图片的地址
? ?public static ImageIcon header = new ImageIcon(headerURL); // 预加载图片
?
? ?// 头部
? ?public static URL upURL = data.class.getResource("/statics/up.png");
? ?public static URL downURL = data.class.getResource("/statics/down.png");
? ?public static URL rightURL = data.class.getResource("/statics/right.png");
? ?public static URL leftURL = data.class.getResource("/statics/left.png");
? ?public static ImageIcon up = new ImageIcon(upURL); // 预加载图片
? ?public static ImageIcon down = new ImageIcon(downURL); // 预加载图片
? ?public static ImageIcon right = new ImageIcon(rightURL); // 预加载图片
? ?public static ImageIcon left = new ImageIcon(leftURL); // 预加载图片
?
? ?// 身体
? ?public static URL bodyURL = data.class.getResource("/statics/body.png");
? ?public static ImageIcon body = new ImageIcon(bodyURL); // 预加载图片
?
? ?// 食物
? ?public static URL foodURL = data.class.getResource("/statics/food.png");
? ?public static ImageIcon food = new ImageIcon(foodURL); // 预加载图片
}
谢谢~~~!!!
|