目录
💴哈喽,大家好丫,你们的小郭子又来啦 ~
🌞今天我们用java来写一个简单的小项目——【贪吃蛇】,嘿嘿,是不是DNA动了呀🌞🌞
🌞话不多说,直接上干货,
(一)效果图
(二)代码实现
(1)将图片加载到程序中
现在本程序中创建一个Images包,包中保存需要使用的照片,如图所示
/**
* Images这个类,专门用来获取游戏中所涉及的图片
*/
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);
}
class TestURL {
//这是一个main方法,是程序的入口:
public static void main(String[] args) {
URL url = Images.class.getResource("/");// /指代的就是相对路径,相对/D:/IDEA_workspace/TestJavaSE/out/production/TestSnakeGame/
System.out.println(url);
}
}
(2)创建窗体
public class StartGame {
public static void main(String[] args) {
//创建一个窗体:
JFrame jf = new JFrame();
//给窗体设置一个标题:
jf.setTitle("贪吃蛇 by jayden");
//设置窗体弹出的坐标,对应窗体的宽高:
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);
}
}
(3)创建面板
public class StartGame {
public static void main(String[] args) {
//创建一个窗体:
JFrame jf = new JFrame();
//给窗体设置一个标题:
jf.setTitle("贪吃蛇 by jayden");
//设置窗体弹出的坐标,对应窗体的宽高:
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);
}
}
(4)绘制静态的小蛇
/**
* @author : jayden
* 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
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(208, 221, 227));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g:指的是使用的画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,-10,10);
//调解画笔颜色:
g.setColor(new Color(219, 226, 219));
//画一个矩形:
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]);
}
}
}
(5) 加入监听事件
/**
* @author : jayden
* 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()方法
}
}
});
}
/*
paintComponent这个方法比较特殊,这个方法就属于图形版的main方法
自动调用
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(208, 221, 227));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g:指的是使用的画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,-10,10);
//调解画笔颜色:
g.setColor(new Color(219, 226, 219));
//画一个矩形:
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);
}
}
}
(6)让蛇动起来
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();//重绘动作,重新调用paintComponent()方法
}
}
});
//对定时器进行初始化动作:
timer = new Timer(150, new ActionListener() {
/*
ActionListener是 事件监听
相当于每100ms监听一下你是否发生了一个动作
具体的动作放入actionPerformed
*/
@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
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(208, 221, 227));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g:指的是使用的画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,-10,10);
//调解画笔颜色:
g.setColor(new Color(219, 226, 219));
//画一个矩形:
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);
}
}
}
(7)绘制食物和吃食物
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;
//初始化食物的坐标:
foodX = 300;
foodY = 200;
//初始化蛇头的方向:
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()方法
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(150, new ActionListener() {
/*
ActionListener是 事件监听
相当于每100ms监听一下你是否发生了一个动作
具体的动作放入actionPerformed
*/
@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]>750){
snakeX[0] = 25;
}
//检测碰撞的动作:
//食物的坐标和蛇头的坐标一样的时候,才是碰撞了
if(snakeX[0] == foodX&&snakeY[0] == foodY){
//蛇长度加1:
length++;
//吃上食物以后 积分加10分:
score += 10;
//食物坐标改变:随机生成坐标 --》细节:坐标必须是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,30]
*/
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]
}
//死亡判定:蛇头和任意一节身子碰撞都是死亡:
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
protected void paintComponent(Graphics g) {
super.paintComponent(g);
//填充背景颜色:
this.setBackground(new Color(208, 221, 227));
//画头部图片:
/*
paintIcon四个参数:this指的是当前面板 g:指的是使用的画笔 x,y对应的坐标
*/
Images.headerImg.paintIcon(this,g,-10,10);
//调解画笔颜色:
g.setColor(new Color(219, 226, 219));
//画一个矩形:
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(255, 248, 248));
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("积分:"+score,670,45);
//画入死亡状态:
if(isDie){
g.setColor(new Color(255, 82, 68));
g.setFont(new Font("微软雅黑",Font.BOLD,20));
g.drawString("小蛇死亡,游戏停止,按下空格重新开始游戏",200,330);
}
}
}
(8)把游戏打包
好啦,今天的分享到这里就结束啦 ~🌞🌞
觉得我分享的文章不错的话,可以关注一下哦,嘻嘻嘻🌞🌞