创建屏幕

开始游戏的窗口,首先引入窗口,然后在窗口画布上进行添加各类动画。

JFrame frame=new JFrame("My SnakeGame");

Jframe 是个类,引入了窗口frame,该窗口的标题是:My SnakeGame

frame.setBounds(100,100,800,500);//设置零点坐标,窗口大小

参数1: 窗口的左上角点的横坐标

参数2:窗口的左上角点的纵坐标

参数3:窗口的宽度

参数4:窗口的高度

单位为像素

frame.setResizable(false); //窗口大小不可随意改变大小

这样设置后不能够随意改变窗口的大小。主要是牵扯到画面的自动扩展延伸。

frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口即关闭程序,无后台

这样设置后关闭窗口后自动关闭程序,否则关闭窗口后,程序依旧在运行。

frame.setVisible(true);    //窗口可被展示

窗口可以被看到

frame.add(new GameJPanel());//引入画板

通过这个语句引入画板,图片,操作都在画板上进行。

画板

定义我们自己的画布类必须继承自JPanel系统画板类,我们需要重写方法

protected void paintComponent(Graphics g){} //在这个方法里编写我们想要画在画板上的东西

这里的Graphics g参数是画笔g,我们可以设置画笔的颜色,字体等。

在我们重写的这个方法里先调用父类的方法 :super.paintComponent(g);

需要在画面上进行某些改变的话都要写在这个重写的方法里。

this.setBackground(Color.WHITE);  //定义背景颜色

WHITE可选该为其他颜色,其他部分为固定语法法

this表示当前画布,可以理解为当前画布设置背景颜色为白色

 g.setColor(Color.WHITE);  //画笔颜色设置
g.setFont(new Font("宋体",Font.BOLD,40));

设置画笔的写出的颜色,字体格式,字体类型,字体大小。

g.drawString("按下空格开始",300,250);

语法:g.drawString("要打印的字体",x,y);

写入打印的字符串,打印起始点的坐标。

Date.header.paintIcon(this,g,2,0);//在画板里打印图片
//参数分别为,窗口this(本窗口),画笔g,(2,0)表示坐标距离

语法:Date.名字.paintIcon(画面,画笔,x,y);

这里的header是我们在下面的数据引入时引入的图片资源名称。

paomtIcon();指打印图片的方法。

g.fillRect(25,75,750,400); //填充窗口画面

25,75表示起始的点坐标。750,400表示从那点开始要打印的画面的宽度,高度

这部主要实现游戏窗口的背景打印。

按键监听

这里我们需要实现两个接口,第一个是键盘监听接口 KeyListener。这个接口依旧在我们自己定义的画板上进行实现,实现了这个接口我们就需要实现三个方法。

  1. public void keyTyped(KeyEvent e) { //按一下
    
    }

    这个方法主要监听键盘上按键仅按一下的情况下。可以理解为按一下记一下。

  2. public void keyReleased(KeyEvent e) { //弹起
    
    }

    这个方法监听的是键盘按下后弹起的过程。

  3. public void keyPressed(KeyEvent e) { //一直按
    }

    监听长按的键盘。

这里的KeyEvent e是接受的参数,e.getKeyCode();表示得到的键盘输入情况

定义个数keyCode接受这个按键。 int keyCode=e.getKeyCode();后面都是用keyCode与按键进行比较

KeyEvent.VK_UP //表示上键

语法:KeyEvent.VK_按键; 表示这个案件 //按键部分需要全大写字母。例如LEFT

if(keyCode==KeyEvent.VK_DDWN)

{           

 //当按键为“下”时做什么,一般为改变一个变量(在这个监听按键的方法里改变),通过这个改变这个变量改变打印的内容(在重写的画板方法里改变打印的内容),从而实现画面里方向的改变。

 }
repaint(); //重新绘制界面的方法

repaint();作用是刷新打印的界面,可以在监听按键的方法里调用,从而实现按键后画面的改变。

一般会定义个初始化变量的方法,用来实现游戏重新加载或第一次加载时的变量初始化。

定时操作

我们需要实现重写的第二个接口是定时活动操作ActionListener,会随着时间变化而变化,设置定时执行该方法的的方法体。我们需要重写方法

public void actionPerformed(ActionEvent e) {//执行定时操作
//随时间变化的操作,如想让蛇头朝一个方向走动只需要其坐标(X或Y)自增。这里面的操作都会随着我们设置的时间间隔不断重复执行。
timer.start(); //计时器开始
}

在方法的左后要加上timer.start(); //计时器开始确保计时器开始执行,即执行完第一次后不断重复执行开始

数据引入

在这之前需要先建个static包用来存放我们的资源数据,直接将所需要的照片包拷进该文件夹即可。

定义Data类,通过Date类引入我们需要使用的图片,音乐等外部资源。

语法: 修饰符 URL 地址名称=类名.class.getResource("地址"); //地址名称是自己按规则随意取的,地址是文件所在的文件夹和文件名称和类型。

public static URL headerURL=Date.class.getResource("地址");
//引入资源的地址

eg:public static URL upURL=Date.class.getResource("/static/up.png");

需要注意的是这里只是引入资源的地址,并没有说明这是什么资源类型。

声明引入资源的类型。如图片的声明。

语法:修饰符 ImageIcon 名称=new ImageIcon(地址名称);

public static ImageIcon header=new ImageIcon(headerURL);
//引入资源为图片

屏幕框架引入

package com.cyqf.snake.www;

import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent; public class StartGame {
public static void main(String[] args) {
JFrame frame=new JFrame("My SnakeGame");
frame.setBounds(100,100,800,500);//设置零点坐标,窗口大小
frame.setResizable(false); //窗口大小不可随意改变
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//关闭窗口即关闭程序,无后台
frame.setVisible(true); //窗口可被展示 frame.add(new GameJPanel());//引入画板 //在我们的窗口里可以引入画板画的东西 }
}

数据引入

package com.cyqf.snake.www;

import javax.swing.*;
import java.net.URL; public class Date { //引入数据,引入后才能被直接调用 public static URL headerURL=Date.class.getResource("/static/header.png");
//引入资源的地址
public static ImageIcon header=new ImageIcon(headerURL);
//引入资源为图片
public static URL upURL=Date.class.getResource("/static/up.png");
public static URL downURL=Date.class.getResource("/static/down.png");
public static URL leftURL=Date.class.getResource("/static/left.png");
public static URL rightURL=Date.class.getResource("/static/right.png");
public static URL foodURL=Date.class.getResource("/static/food.png");
public static URL bodyURL=Date.class.getResource("/static/body.png"); public static ImageIcon up=new ImageIcon(upURL);
public static ImageIcon down=new ImageIcon(downURL);
public static ImageIcon left=new ImageIcon(leftURL);
public static ImageIcon right=new ImageIcon(rightURL);
public static ImageIcon food=new ImageIcon(foodURL);
public static ImageIcon body=new ImageIcon(bodyURL); }

画板

package com.cyqf.snake.www;

import com.sun.xml.internal.ws.policy.EffectiveAlternativeSelector;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.util.Random; public class GameJPanel extends JPanel implements KeyListener , ActionListener {
//2.Jpanel画板类,写入我们需要的东西如图片,背景颜色等,
//这里我们自己定义一个画板,继承来自系统的画板
int length=600;//定义蛇的长度
String fx;//蛇头方向
int[] snakex=new int[600]; //定义横坐标
int[] snakey=new int[500]; //定义纵坐标
boolean isstart; //开始结束变量
boolean isfail; //成功失败变量
//设置定时器
Timer timer=new Timer(100,this);//每个多少毫秒,监听哪个窗口
Random random=new Random(); //引入随机方法
int foodx; //食物x坐标
int foody; //食物y坐标
int score; //分数 GameJPanel(){ //构造器
init(); //初始化方法
this.setFocusable(true); //获取键盘的焦点,将键盘的焦点聚集在游戏上
this.addKeyListener(this); //实现类
timer.start(); //计时器引入
} void init(){//初始化方法
length=3; //初始长度
fx="R"; //默认朝向
snakex[0]=100; //头的初始位置
snakey[0]=100;
snakex[1]=75;snakey[1]=100; //第一节身体
snakex[2]=50;snakey[2]=100; //第二节身体
isstart=false; //判断游戏是否开始
isfail=false;
foodx=75+25*random.nextInt(28); //给食物坐标随机
foody=75+25*random.nextInt(13);
score=0; } @Override
protected void paintComponent(Graphics g) { //重写方法,画板
super.paintComponent(g); //这里的Graphics g就是画笔
this.setBackground(Color.WHITE); //定义背景颜色 Date.header.paintIcon(this,g,2,0);//在画板里打印图片
//参数分别为,窗口this(本窗口),画笔g,坐标距离
g.fillRect(25,75,750,350); //填充窗口画面 if (fx.equals("R")){ //通过监听键盘改变fx的值,改变fx的值后打印不同画面,实现蛇头的转向
Date.right.paintIcon(this,g,snakex[0],snakey[0]);
}
else if (fx.equals("L"))
{
Date.left.paintIcon(this,g,snakex[0],snakey[0]);
}
else if (fx.equals("U"))
{
Date.up.paintIcon(this,g,snakex[0],snakey[0]);
}
else if (fx.equals("D"))
{
Date.down.paintIcon(this,g,snakex[0],snakey[0]);
} for (int i = 1; i <length; i++) {
Date.body.paintIcon(this,g,snakex[i],snakey[i]); //初始值为3,两节身体,
// 随着长度增加,可以不断打印
}
if (isfail==false){
if (isstart==false){ //提示信息
g.setColor(Color.WHITE); //画笔颜色设置
g.setFont(new Font("宋体",Font.BOLD,40)); //字体格式,粗体,大小
g.drawString("按下空格开始",300,250);
} }else {
g.setColor(Color.red); //设置画笔的颜色
g.setFont(new Font("宋体",Font.BOLD,40)); //
g.drawString("游戏失败按空格重新开始",250,250);
init();
} Date.food.paintIcon(this,g,foodx,foody);
g.setColor(Color.blue);
g.setFont(new Font("微软雅黑",Font.BOLD,18));
g.drawString("分数:"+score,675,25);
g.drawString("长度:"+length,675,39); } @Override //按键控制监听
public void keyPressed(KeyEvent e) { //一直按
int keyCode=e.getKeyCode();
if (keyCode==KeyEvent.VK_SPACE) //接受到了空格,给状态取反,从而实现开始暂停
{
isstart=!isstart;
}
if (keyCode==KeyEvent.VK_UP) //由键盘输入的值改变fx
{
if(!fx.equals("D")) //不能回头的判断语句
fx="U";
}else if (keyCode==KeyEvent.VK_DOWN)
{
if(!fx.equals("U")) //不能回头的判断语句
fx="D";
}else if (keyCode==KeyEvent.VK_RIGHT)
{
if(!fx.equals("L")) //不能回头的判断语句
fx="R";
}else if (keyCode==KeyEvent.VK_LEFT)
{
if(!fx.equals("R")) //不能回头的判断语句
fx="L";
}
repaint(); //重新绘制界面的方法
} @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 (fx.equals("R")){ //在这里进行打印判断,由fx的值判断蛇头的打印
snakex[0]=snakex[0]+25;
if (snakex[0]>750)
{
snakex[0]=25; //超过边界后从另一边出来
}
} else if (fx.equals("L")){
snakex[0]=snakex[0]-25;
if (snakex[0]<25)
snakex[0]=750; //超过边界后从另一边出来
}else if (fx.equals("U")){
snakey[0]=snakey[0]-25;
if (snakey[0]<75)
snakey[0]=400; //超过边界后从另一边出来
}else if (fx.equals("D")){
snakey[0]=snakey[0]+25;
if (snakey[0]>400){
snakey[0]=75; //超过边界后从另一边出来
}
} if (foodx==snakex[0]&&foody==snakey[0]) //吃到食物的哦按段
{
length++; //身体增加
score+=10; //分数增加
foodx=50+25*random.nextInt(28); //食物坐标刷新坐标随机
foody=75+25*random.nextInt(13);
}
for (int i = 1; i <length; i++) { // 死亡判断
if (snakex[0]==snakex[i]&&snakey[0]==snakey[i]) //当身体的坐标和有重叠时死亡
{
isfail=true; //游戏失败
}
} repaint();//刷新界面
}
timer.start(); //计时器开始
} @Override
public void keyTyped(KeyEvent e) { //按一下 }
@Override
public void keyReleased(KeyEvent e) { //弹起 } }

所需要的资源:

​ right.png

​ left.png

​ up.png

​ down.png

​ food.png

header.png

​ body.png

案例-java贪吃蛇(附源码)的更多相关文章

  1. JPA入门案例详解(附源码)

    1.新建JavaEE Persistence项目

  2. 大文件拆分问题的java实践(附源码)

    引子 大文件拆分问题涉及到io处理.并发编程.生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性的处理方案和思路,以供后续工作中借 ...

  3. 大文件拆分方案的java实践(附源码)

    引子 大文件拆分问题涉及到io处理.并发编程.生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性的处理方案和思路,以供后续工作中借 ...

  4. Ruby for Sketchup 贪吃蛇演示源码(naive_snake)

    sketchup是非常简单易用的三维建模软件,可以利用ruby 做二次开发, api文档 http://www.rbc321.cn/api 今天在su中做了一款小游戏 贪吃蛇,说一下步骤 展示 主要思 ...

  5. C# unity3d 贪吃蛇 游戏 源码 及其感想

    这个游戏的设计过程是这样的: 1,创建

  6. Java经典小游戏——贪吃蛇简单实现(附源码)

    一.使用知识 Jframe GUI 双向链表 线程 二.使用工具 IntelliJ IDEA jdk 1.8 三.开发过程 3.1素材准备 首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以 ...

  7. Vue过渡和动画效果展示(案例、GIF动图演示、附源码)

    前言 本篇随笔主要写了Vue过渡和动画基础.多个元素过渡和多个组件过渡,以及列表过渡的动画效果展示.详细案例分析.GIF动图演示.附源码地址获取. 作为自己对Vue过渡和动画效果知识的总结与笔记. 因 ...

  8. Vue路由实现之通过URL中的hash(#号)来实现不同页面之间的切换(图表展示、案例分析、附源码详解)

    前言 本篇随笔主要写了Vue框架中路由的基本概念.路由对象属性.vue-router插件的基本使用效果展示.案例分析.原理图解.附源码地址获取. 作为自己对Vue路由进行页面跳转效果知识的总结与笔记. ...

  9. 【转】.NET(C#):浅谈程序集清单资源和RESX资源 关于单元测试的思考--Asp.Net Core单元测试最佳实践 封装自己的dapper lambda扩展-设计篇 编写自己的dapper lambda扩展-使用篇 正确理解CAP定理 Quartz.NET的使用(附源码) 整理自己的.net工具库 GC的前世与今生 Visual Studio Package 插件开发之自动生

    [转].NET(C#):浅谈程序集清单资源和RESX资源   目录 程序集清单资源 RESX资源文件 使用ResourceReader和ResourceSet解析二进制资源文件 使用ResourceM ...

  10. 微服务11:熔断、降级的Hystrix实现(附源码)

    微服务1:微服务及其演进史 微服务2:微服务全景架构 微服务3:微服务拆分策略 微服务4:服务注册与发现 微服务5:服务注册与发现(实践篇) 微服务6:通信之网关 微服务7:通信之RPC 微服务8:通 ...

随机推荐

  1. 【已解决】Hadoop_07 Hadoop启动超时失败

  2. #博弈论#Poj 2505 A multiplication game

    题目 给你一个整数\(n\),你从1开始乘,乘2-9之间的任意一个数. 最先得到大于等于\(n\)的数的人胜利.Stan先手Ollie后手. 那么,请问给你一个数\(n\),Stan和Ollie都足够 ...

  3. 使用OHOS SDK构建lua

    参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/lua/lua.git ...

  4. Numpy数组拼接和分裂

    将多个数组合并成一个,或将一个数组分裂成多个. 数组拼接 concatenate([a1, a2, ...], axis=0, out=None) #默认沿axis = 0轴拼接,也可设置沿axis ...

  5. std::thread 二:互斥量(lock_guard())

    *:使用 lock_guard 后,就不可以使用 lock() 和 unlock() *:lock_guard 和智能指针一样,会自动解锁   #include <iostream> #i ...

  6. Java List集合去重、过滤、分组、获取数据、求最值、合并、排序、跳数据和遍历

    前言 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i. 准备工作:现有一个User类.Student 类和Ticket类,加入相关依赖 @Data public class User { / ...

  7. HarmonyOS跨进程通信—IPC与RPC通信开发指导

      一.IPC与RPC通信概述 基本概念 IPC(Inter-Process Communication)与RPC(Remote Procedure Call)用于实现跨进程通信,不同的是前者使用Bi ...

  8. 报名直达丨HarmonyOS开发者创新大赛线下城市交流会来了,约吗?

    HarmonyOS开发者创新大赛线下城市交流会 正式开启啦! 在这里,将有专业的讲师 与HarmonyOS开发者们面对面演示开发实操.交流开发心得 还等什么?赶快扫码报名吧~↓↓↓ 城市交流会报名链接 ...

  9. C++ 类方法解析:内外定义、参数、访问控制与静态方法详解

    C++ 类方法 类方法,也称为成员函数,是属于类的函数.它们用于操作或查询类数据,并封装在类定义中.类方法可以分为两种类型: 类内定义方法: 直接在类定义内部声明和定义方法. 类外定义方法: 在类定义 ...

  10. CPU性能实战分析

    1.从平均负载谈起 我们每次发现线上系统变慢时,第一件事往往都会使用top或者uptime命令查看cpu的负载以及占用率,比如top命令会有下面的结果: top - 15:51:39 up 84 da ...