用Java制作贪吃蛇小游戏
1.贪吃蛇小游戏详解
1.1引入
- 游戏效果展示:
- 涉及技能点:
-
游戏图形化界面编程---》GUI图形化界面编程
-
GUI中的组件:
- GUI技术,不流行了!!!
- 已经被淘汰了,为什么还学?
(1)提起兴趣
(2)分层思想
(3)锻炼监听器的思想
(4)举一反三
1.2 将图片加载到程序中来
- 测试相对路径:
- 将图片封装:
public class Images {
/*
现在是面向对象的语言,面向对象的思维-->>将图片进行封装,封装为一个对象,这样在程序中才可以通过操纵这个对象来操纵图片。
*/
//将图片的路径封装为一个对象:
public static URL bodyURL = Images.class.getResource("/images/body.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon bodyImg = new ImageIcon(bodyURL);
//将图片的路径封装为一个对象:
public static URL downURL = Images.class.getResource("/images/down.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon downImg = new ImageIcon(downURL);
//将图片的路径封装为一个对象:
public static URL foodURL = Images.class.getResource("/images/food.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon foodImg = new ImageIcon(foodURL);
//将图片的路径封装为一个对象:
public static URL headerURL = Images.class.getResource("/images/header.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon headerImg = new ImageIcon(headerURL);
//将图片的路径封装为一个对象:
public static URL leftURL = Images.class.getResource("/images/left.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon leftImg = new ImageIcon(leftURL);
//将图片的路径封装为一个对象:
public static URL rightURL = Images.class.getResource("/images/right.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon rightImg = new ImageIcon(rightURL);
//将图片的路径封装为一个对象:
public static URL upURL = Images.class.getResource("/images/up.png");//"/"指相对路径
//将图片封装为程序中一个对象:
public static ImageIcon upImg = new ImageIcon(upURL);
}
1.3创建一个窗体
package com.msb.game;
import javax.swing.*;
import java.awt.*;
public class StartGame {
//这是一个人main方法,是程序的入口
public static void main(String[] args) {
//创建一个窗体:
JFrame jf = new JFrame();
//给窗体设置一个标题:
jf.setTitle("小游戏 大逻辑 by ligaowei");
//设置窗体弹出的坐标,对应窗体的宽高:
//获取屏幕的长宽高:
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(jf.EXIT_ON_CLOSE);
//默认情况下窗体是隐藏效果,必须将窗体进行显现:细节--》这个显现
jf.setVisible(true);
}
}
1.4 创建一个面板
package com.msb.game;
import javax.swing.*;
import java.awt.*;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
}
}
1.5画一个静态小蛇
package com.msb.game;
import javax.swing.*;
import java.awt.*;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//一个数组,专门储存蛇的X的坐标
int[] snakeX = new int [200];
//一个数组,专门储存蛇的y的坐标
int[] snakeY = new int[200];
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
}
public GamePanel(){
init();
}
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
//画小蛇:
//画蛇头:
Images.rightImg.paintIcon(this,g,snakeX[0],snakeY[0]);
/*//画第一节身子;
Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
//画第二节身子;
Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
//优化为循环画蛇的身子:
for (int i = 1; i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
}
}
1.6 将蛇头按照行走方向改变
package com.msb.game;
import javax.swing.*;
import java.awt.*;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//一个数组,专门储存蛇的X的坐标
int[] snakeX = new int [200];
//一个数组,专门储存蛇的y的坐标
int[] snakeY = new int[200];
//定义蛇的行走方向:
String direction;
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
//初始化蛇头的方向:
direction = "R";//U D L R
}
public GamePanel(){
init();
}
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
//画小蛇:
//画蛇头:
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]);
}
/*//画第一节身子;
Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
//画第二节身子;
Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
//优化为循环画蛇的身子:
for (int i = 1; i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
}
}
1.7 加入监听,空格来控制游戏是否开始
package com.msb.game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//一个数组,专门储存蛇的X的坐标
int[] snakeX = new int [200];
//一个数组,专门储存蛇的y的坐标
int[] snakeY = new int[200];
//游戏只有两个状态,开始,暂停:
boolean isStart = false;//默认游戏是暂停效果
//定义蛇的行走方向:
String direction;
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
//初始化蛇头的方向:
direction = "R";//U D L R
}
public GamePanel(){
init();
//将焦点定位在当前操作的面板上:
this.setFocusable(true);
//加入监听:
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {//监听键盘按键的按键操作
super.keyPressed(e);
int KeyCode = e.getKeyCode();
System.out.println(KeyCode);
if (KeyCode == 32){
isStart = !isStart;
repaint(); //重绘
}
}
});
}
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
//画小蛇:
//画蛇头:
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]);
}
/*//画第一节身子;
Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
//画第二节身子;
Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
//优化为循环画蛇的身子:
for (int i = 1; i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//如果游戏暂停的,界面中间就应该有一句提示语:
if(isStart == false){
//画一个文字:
g.setColor(new Color(114,98,255));
//三个参数:字体,加粗,字号
g.setFont(new Font("微软雅黑",Font.BOLD,40));
//画文字:三个参数:文字内容,X轴坐标,Y轴坐标
g.drawString("点击空格开始游戏",250,330);
}
}
}
1.8 使小蛇向右动起来
package com.msb.game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//一个数组,专门储存蛇的X的坐标
int[] snakeX = new int [200];
//一个数组,专门储存蛇的y的坐标
int[] snakeY = new int[200];
//游戏只有两个状态,开始,暂停:
boolean isStart = false;//默认游戏是暂停效果
//加入一个定时器:
Timer timer;
//定义蛇的行走方向:
String direction;
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
//初始化蛇头的方向:
direction = "R";//U D L R
}
public GamePanel(){
init();
//将焦点定位在当前操作的面板上:
this.setFocusable(true);
//加入监听:
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {//监听键盘按键的按键操作
super.keyPressed(e);
int KeyCode = e.getKeyCode();
System.out.println(KeyCode);
if (KeyCode == 32){
isStart = !isStart;
repaint(); //重绘
}
}
});
//对定时器进行初始化动作:
timer = new Timer(100, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if(isStart){//游戏是开始状态的时候,蛇才动:
//后一节身子走到前一节身子的位置上:
for (int i = length-1;i>0;i--){
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
//动头
snakeX[0] += 25;
//防止蛇超出边界:
if(snakeX[0]>750){
snakeX[0] = 25;
}
repaint();//重绘
}
}
});
//定时器必须要启动:
timer.start();
}
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
//画小蛇:
//画蛇头:
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]);
}
/*//画第一节身子;
Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
//画第二节身子;
Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
//优化为循环画蛇的身子:
for (int i = 1; i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//如果游戏暂停的,界面中间就应该有一句提示语:
if(isStart == false){
//画一个文字:
g.setColor(new Color(114,98,255));
//三个参数:字体,加粗,字号
g.setFont(new Font("微软雅黑",Font.BOLD,40));
//画文字:三个参数:文字内容,X轴坐标,Y轴坐标
g.drawString("点击空格开始游戏",250,330);
}
}
}
1.9小蛇上下左右移动并画豆豆,吃豆豆
package com.msb.game;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.util.Random;
/*
GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板
*/
public class GamePanel extends JPanel {
//蛇的长度:
int length;
//一个数组,专门储存蛇的X的坐标
int[] snakeX = new int [200];
//一个数组,专门储存蛇的y的坐标
int[] snakeY = new int[200];
//游戏只有两个状态,开始,暂停:
boolean isStart = false;//默认游戏是暂停效果
//加入一个定时器:
Timer timer;
//定义蛇的行走方向:
String direction;
//定义食物的X,Y轴坐标:
int foodX;
int foodY;
public void init(){
//初始化蛇的长度:
length = 3;
//初始化蛇头坐标:
snakeX[0] = 175;
snakeY[0] = 275;
//初始化第一节身子坐标:
snakeX[1] = 150;
snakeY[1] = 275;
//初始化第二节身子坐标:
snakeX[2] = 125;
snakeY[2] = 275;
//初始化蛇头的方向:
direction = "R";//U D L R
//初始化食物的坐标:
foodX = 300;
foodY = 200;
}
public GamePanel(){
init();
//将焦点定位在当前操作的面板上:
this.setFocusable(true);
//加入监听:
this.addKeyListener(new KeyAdapter() {
@Override
public void keyPressed(KeyEvent e) {//监听键盘按键的按键操作
super.keyPressed(e);
int KeyCode = e.getKeyCode();
System.out.println(KeyCode);
if (KeyCode == KeyEvent.VK_SPACE){//监听空格
isStart = !isStart;
repaint(); //重绘
}
//监听向上箭头:
if (KeyCode == KeyEvent.VK_UP){//监听空格
direction = "U";
}
//监听向下箭头:
if (KeyCode == KeyEvent.VK_DOWN){//监听空格
direction = "D";
}
//监听向左箭头:
if (KeyCode == KeyEvent.VK_LEFT){//监听空格
direction = "L";
}
//监听向右箭头:
if (KeyCode == KeyEvent.VK_RIGHT){//监听空格
direction = "R";
}
}
});
//对定时器进行初始化动作:
timer = new Timer(100, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
if(isStart){//游戏是开始状态的时候,蛇才动:
//后一节身子走到前一节身子的位置上:
for (int i = length-1;i>0;i--){
snakeX[i] = snakeX[i-1];
snakeY[i] = snakeY[i-1];
}
//动头
if ("R".equals(direction)){
snakeX[0] += 25;
}
if ("L".equals(direction)){
snakeX[0] -= 25;
}
if ("U".equals(direction)){
snakeY[0] -= 25;
}
if ("D".equals(direction)){
snakeY[0] += 25;
}
//防止蛇超出边界:
if(snakeX[0]>750){
snakeX[0] = 25;
}
if(snakeX[0]<25){
snakeX[0] = 750;
}
if(snakeY[0]<100){
snakeY[0] = 725;
}
if(snakeY[0]>725){
snakeY[0] = 100;
}
//检测碰撞的动作:
if(snakeX[0] == foodX&&snakeY[0]== foodY){
//蛇的长度加1:
length++;
//食物坐标改变:随机生成坐标--》细节:坐标必须是25的倍数
/*
[25,750]->[1,30]*25
[1,30]
Math.random() ->[0.0,1.0)
Math.random()*30 -> [0.0,30.0)
(int)(Math.random()*30) -> [0,29]
(int)(Math.random()*30)+1 -> [1,29]
*/
foodX =((int)(Math.random()*30)+1)*25 ;//[25,750]
/*
[100,725] -> [4,29]*25
[4,29] -> [0,25]+4
[0,25]
new Random().nextInt(26) -> [0,26) -> [0,25]
*/
foodY = (new Random().nextInt(26)+4)*25;//[100,725]
}
repaint();//重绘
}
}
});
//定时器必须要启动:
timer.start();
}
/*
paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法
自动调用
*/
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(46, 72, 127, 255));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,10,10);
//调解笔的颜色:
g.setColor(new Color(253, 253, 254));
//画一个矩形:
g.fillRect(10,70,770,685);
//画小蛇:
//画蛇头:
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]);
}
/*//画第一节身子;
Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]);
//画第二节身子;
Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/
//优化为循环画蛇的身子:
for (int i = 1; i<length;i++){
Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]);
}
//如果游戏暂停的,界面中间就应该有一句提示语:
if(isStart == false){
//画一个文字:
g.setColor(new Color(114,98,255));
//三个参数:字体,加粗,字号
g.setFont(new Font("微软雅黑",Font.BOLD,40));
//画文字:三个参数:文字内容,X轴坐标,Y轴坐标
g.drawString("点击空格开始游戏",250,330);
}
//画食物:
Images.foodImg.paintIcon(this,g,foodX,foodY);
}
}
1.10画积分
package com.msb.game;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.util.Random;/*GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板 */public class GamePanel extends JPanel { //蛇的长度: int length; //一个数组,专门储存蛇的X的坐标 int[] snakeX = new int [200]; //一个数组,专门储存蛇的y的坐标 int[] snakeY = new int[200]; //游戏只有两个状态,开始,暂停: boolean isStart = false;//默认游戏是暂停效果 //加入一个定时器: Timer timer; //定义蛇的行走方向: String direction; //定义食物的X,Y轴坐标: int foodX; int foodY; //定义一个积分: int score; public void init(){ //初始化蛇的长度: length = 3; //初始化蛇头坐标: snakeX[0] = 175; snakeY[0] = 275; //初始化第一节身子坐标: snakeX[1] = 150; snakeY[1] = 275; //初始化第二节身子坐标: snakeX[2] = 125; snakeY[2] = 275; //初始化蛇头的方向: direction = "R";//U D L R //初始化食物的坐标: foodX = 300; foodY = 200; } public GamePanel(){ init(); //将焦点定位在当前操作的面板上: this.setFocusable(true); //加入监听: this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) {//监听键盘按键的按键操作 super.keyPressed(e); int KeyCode = e.getKeyCode(); System.out.println(KeyCode); if (KeyCode == KeyEvent.VK_SPACE){//监听空格 isStart = !isStart; repaint(); //重绘 } //监听向上箭头: if (KeyCode == KeyEvent.VK_UP){//监听空格 direction = "U"; } //监听向下箭头: if (KeyCode == KeyEvent.VK_DOWN){//监听空格 direction = "D"; } //监听向左箭头: if (KeyCode == KeyEvent.VK_LEFT){//监听空格 direction = "L"; } //监听向右箭头: if (KeyCode == KeyEvent.VK_RIGHT){//监听空格 direction = "R"; } } }); //对定时器进行初始化动作: timer = new Timer(100, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if(isStart){//游戏是开始状态的时候,蛇才动: //后一节身子走到前一节身子的位置上: for (int i = length-1;i>0;i--){ snakeX[i] = snakeX[i-1]; snakeY[i] = snakeY[i-1]; } //动头 if ("R".equals(direction)){ snakeX[0] += 25; } if ("L".equals(direction)){ snakeX[0] -= 25; } if ("U".equals(direction)){ snakeY[0] -= 25; } if ("D".equals(direction)){ snakeY[0] += 25; } //防止蛇超出边界: if(snakeX[0]>750){ snakeX[0] = 25; } if(snakeX[0]<25){ snakeX[0] = 750; } if(snakeY[0]<100){ snakeY[0] = 725; } if(snakeY[0]>725){ snakeY[0] = 100; } //检测碰撞的动作: if(snakeX[0] == foodX&&snakeY[0]== foodY){ //蛇的长度加1: length++; //食物坐标改变:随机生成坐标--》细节:坐标必须是25的倍数 /* [25,750]->[1,30]*25 [1,30] Math.random() ->[0.0,1.0) Math.random()*30 -> [0.0,30.0) (int)(Math.random()*30) -> [0,29] (int)(Math.random()*30)+1 -> [1,29] */ foodX =((int)(Math.random()*30)+1)*25 ;//[25,750] /* [100,725] -> [4,29]*25 [4,29] -> [0,25]+4 [0,25] new Random().nextInt(26) -> [0,26) -> [0,25] */ foodY = (new Random().nextInt(26)+4)*25;//[100,725] //吃上食物后 积分加10分: score += 10; } repaint();//重绘 } } }); //定时器必须要启动: timer.start(); } /* paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法 自动调用 */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); //填充背景颜色: this.setBackground(new Color(46, 72, 127, 255)); //画头部图片: /* paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标 */ Images.headerImg.paintIcon(this,g,10,10); //调解笔的颜色: g.setColor(new Color(253, 253, 254)); //画一个矩形: g.fillRect(10,70,770,685); //画小蛇: //画蛇头: 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]); } /*//画第一节身子; Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]); //画第二节身子; Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/ //优化为循环画蛇的身子: for (int i = 1; i<length;i++){ Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]); } //如果游戏暂停的,界面中间就应该有一句提示语: if(isStart == false){ //画一个文字: g.setColor(new Color(114,98,255)); //三个参数:字体,加粗,字号 g.setFont(new Font("微软雅黑",Font.BOLD,40)); //画文字:三个参数:文字内容,X轴坐标,Y轴坐标 g.drawString("点击空格开始游戏",250,330); } //画食物: Images.foodImg.paintIcon(this,g,foodX,foodY); //画积分: g.setColor(new Color(114,98,248)); g.setFont(new Font("微软雅黑",Font.BOLD,35)); //画文字:三个参数:文字内容,X轴坐标,Y轴坐标 g.drawString("积分"+score,670,50); }}
1.11死亡判定
package com.msb.game;import javax.swing.*;import java.awt.*;import java.awt.event.ActionEvent;import java.awt.event.KeyAdapter;import java.awt.event.KeyEvent;import java.util.Random;/*GamePanel继承了JPanel以后,才具有面板的功能,才能成为一个面板 */public class GamePanel extends JPanel { //蛇的长度: int length; //一个数组,专门储存蛇的X的坐标 int[] snakeX = new int [200]; //一个数组,专门储存蛇的y的坐标 int[] snakeY = new int[200]; //游戏只有两个状态,开始,暂停: boolean isStart = false;//默认游戏是暂停效果 //加入一个定时器: Timer timer; //定义蛇的行走方向: String direction; //定义食物的X,Y轴坐标: int foodX; int foodY; //定义一个积分: int score; //加入一个变量,判断小蛇的死亡状态: boolean isDie = false; //默认情况下小蛇没有死亡 public void init(){ //初始化蛇的长度: length = 3; //初始化蛇头坐标: snakeX[0] = 175; snakeY[0] = 275; //初始化第一节身子坐标: snakeX[1] = 150; snakeY[1] = 275; //初始化第二节身子坐标: snakeX[2] = 125; snakeY[2] = 275; //初始化蛇头的方向: direction = "R";//U D L R //初始化食物的坐标: foodX = 300; foodY = 200; } public GamePanel(){ init(); //将焦点定位在当前操作的面板上: this.setFocusable(true); //加入监听: this.addKeyListener(new KeyAdapter() { @Override public void keyPressed(KeyEvent e) {//监听键盘按键的按键操作 super.keyPressed(e); int KeyCode = e.getKeyCode(); System.out.println(KeyCode); if (KeyCode == KeyEvent.VK_SPACE){//监听空格 if(isDie){ //全部恢复到初始化状态 init(); isDie = false; }else {//小蛇没有死亡的情况下: isStart = !isStart; repaint(); //重绘 } } //监听向上箭头: if (KeyCode == KeyEvent.VK_UP){//监听上箭头 direction = "U"; } //监听向下箭头: if (KeyCode == KeyEvent.VK_DOWN){//监听下箭头 direction = "D"; } //监听向左箭头: if (KeyCode == KeyEvent.VK_LEFT){//监听左箭头 direction = "L"; } //监听向右箭头: if (KeyCode == KeyEvent.VK_RIGHT){//监听右箭头 direction = "R"; } } }); //对定时器进行初始化动作: timer = new Timer(100, new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { if(isStart&&isDie == false){//游戏是开始状态的时候,蛇才动: //后一节身子走到前一节身子的位置上: for (int i = length-1;i>0;i--){ snakeX[i] = snakeX[i-1]; snakeY[i] = snakeY[i-1]; } //动头 if ("R".equals(direction)){ snakeX[0] += 25; } if ("L".equals(direction)){ snakeX[0] -= 25; } if ("U".equals(direction)){ snakeY[0] -= 25; } if ("D".equals(direction)){ snakeY[0] += 25; } //防止蛇超出边界: if(snakeX[0]>750){ snakeX[0] = 25; } if(snakeX[0]<25){ snakeX[0] = 750; } if(snakeY[0]<100){ snakeY[0] = 725; } if(snakeY[0]>725){ snakeY[0] = 100; } //检测碰撞的动作: if(snakeX[0] == foodX&&snakeY[0]== foodY){ //蛇的长度加1: length++; //食物坐标改变:随机生成坐标--》细节:坐标必须是25的倍数 /* [25,750]->[1,30]*25 [1,30] Math.random() ->[0.0,1.0) Math.random()*30 -> [0.0,30.0) (int)(Math.random()*30) -> [0,29] (int)(Math.random()*30)+1 -> [1,29] */ foodX =((int)(Math.random()*30)+1)*25 ;//[25,750] /* [100,725] -> [4,29]*25 [4,29] -> [0,25]+4 [0,25] new Random().nextInt(26) -> [0,26) -> [0,25] */ foodY = (new Random().nextInt(26)+4)*25;//[100,725] //吃上食物后 积分加10分: score += 10; } //死亡判定: for (int i = 1;i<length;i++){ if (snakeX[0]==snakeX[i]&&snakeY[0]==snakeY[i]){ //将死亡 状态改为:true isDie = true; } } repaint();//重绘 } } }); //定时器必须要启动: timer.start(); } /* paintComponent这个方法比较特殊,这个方法就是属于图形版的main方法 自动调用 */ @Override public void paintComponent(Graphics g) { super.paintComponent(g); //填充背景颜色: this.setBackground(new Color(46, 72, 127, 255)); //画头部图片: /* paintIcon四个参数:this指的是当前面板 g;指的是使用画笔 x,y对应的坐标 */ Images.headerImg.paintIcon(this,g,10,10); //调解笔的颜色: g.setColor(new Color(253, 253, 254)); //画一个矩形: g.fillRect(10,70,770,685); //画小蛇: //画蛇头: 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]); } /*//画第一节身子; Images.bodyImg.paintIcon(this,g,snakeX[1],snakeY[1]); //画第二节身子; Images.bodyImg.paintIcon(this,g,snakeX[2],snakeY[2]);*/ //优化为循环画蛇的身子: for (int i = 1; i<length;i++){ Images.bodyImg.paintIcon(this,g,snakeX[i],snakeY[i]); } //如果游戏暂停的,界面中间就应该有一句提示语: if(isStart == false){ //画一个文字: g.setColor(new Color(114,98,255)); //三个参数:字体,加粗,字号 g.setFont(new Font("微软雅黑",Font.BOLD,40)); //画文字:三个参数:文字内容,X轴坐标,Y轴坐标 g.drawString("点击空格开始游戏",250,330); } //画食物: Images.foodImg.paintIcon(this,g,foodX,foodY); //画积分: g.setColor(new Color(114,98,248)); g.setFont(new Font("微软雅黑",Font.BOLD,35)); //画文字:三个参数:文字内容,X轴坐标,Y轴坐标 g.drawString("积分"+score,670,50); //画入死亡状态: if(isDie){ g.setColor(new Color(114,98,255)); //三个参数:字体,加粗,字号 g.setFont(new Font("微软雅黑",Font.BOLD,20)); //画文字:三个参数:文字内容,X轴坐标,Y轴坐标 g.drawString("小蛇死亡,游戏停止,按下空格重新开始游戏",200,330); } }}