案例-java贪吃蛇(附源码)
创建屏幕
开始游戏的窗口,首先引入窗口,然后在窗口画布上进行添加各类动画。
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。这个接口依旧在我们自己定义的画板上进行实现,实现了这个接口我们就需要实现三个方法。
public void keyTyped(KeyEvent e) { //按一下 }
这个方法主要监听键盘上按键仅按一下的情况下。可以理解为按一下记一下。
public void keyReleased(KeyEvent e) { //弹起 }
这个方法监听的是键盘按下后弹起的过程。
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贪吃蛇(附源码)的更多相关文章
- JPA入门案例详解(附源码)
1.新建JavaEE Persistence项目
- 大文件拆分问题的java实践(附源码)
引子 大文件拆分问题涉及到io处理.并发编程.生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性的处理方案和思路,以供后续工作中借 ...
- 大文件拆分方案的java实践(附源码)
引子 大文件拆分问题涉及到io处理.并发编程.生产者/消费者模式的理解,是一个很好的综合应用场景,为此,花点时间做一些实践,对相关的知识做一次梳理和集成,总结一些共性的处理方案和思路,以供后续工作中借 ...
- Ruby for Sketchup 贪吃蛇演示源码(naive_snake)
sketchup是非常简单易用的三维建模软件,可以利用ruby 做二次开发, api文档 http://www.rbc321.cn/api 今天在su中做了一款小游戏 贪吃蛇,说一下步骤 展示 主要思 ...
- C# unity3d 贪吃蛇 游戏 源码 及其感想
这个游戏的设计过程是这样的: 1,创建
- Java经典小游戏——贪吃蛇简单实现(附源码)
一.使用知识 Jframe GUI 双向链表 线程 二.使用工具 IntelliJ IDEA jdk 1.8 三.开发过程 3.1素材准备 首先在开发之前应该准备一些素材,已备用,我主要找了一个图片以 ...
- Vue过渡和动画效果展示(案例、GIF动图演示、附源码)
前言 本篇随笔主要写了Vue过渡和动画基础.多个元素过渡和多个组件过渡,以及列表过渡的动画效果展示.详细案例分析.GIF动图演示.附源码地址获取. 作为自己对Vue过渡和动画效果知识的总结与笔记. 因 ...
- Vue路由实现之通过URL中的hash(#号)来实现不同页面之间的切换(图表展示、案例分析、附源码详解)
前言 本篇随笔主要写了Vue框架中路由的基本概念.路由对象属性.vue-router插件的基本使用效果展示.案例分析.原理图解.附源码地址获取. 作为自己对Vue路由进行页面跳转效果知识的总结与笔记. ...
- 【转】.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 ...
- 微服务11:熔断、降级的Hystrix实现(附源码)
微服务1:微服务及其演进史 微服务2:微服务全景架构 微服务3:微服务拆分策略 微服务4:服务注册与发现 微服务5:服务注册与发现(实践篇) 微服务6:通信之网关 微服务7:通信之RPC 微服务8:通 ...
随机推荐
- 【已解决】Hadoop_07 Hadoop启动超时失败
- #博弈论#Poj 2505 A multiplication game
题目 给你一个整数\(n\),你从1开始乘,乘2-9之间的任意一个数. 最先得到大于等于\(n\)的数的人胜利.Stan先手Ollie后手. 那么,请问给你一个数\(n\),Stan和Ollie都足够 ...
- 使用OHOS SDK构建lua
参照OHOS IDE和SDK的安装方法配置好开发环境. 从github下载源码. 执行如下命令: git clone --depth=1 https://github.com/lua/lua.git ...
- Numpy数组拼接和分裂
将多个数组合并成一个,或将一个数组分裂成多个. 数组拼接 concatenate([a1, a2, ...], axis=0, out=None) #默认沿axis = 0轴拼接,也可设置沿axis ...
- std::thread 二:互斥量(lock_guard())
*:使用 lock_guard 后,就不可以使用 lock() 和 unlock() *:lock_guard 和智能指针一样,会自动解锁 #include <iostream> #i ...
- Java List集合去重、过滤、分组、获取数据、求最值、合并、排序、跳数据和遍历
前言 请各大网友尊重本人原创知识分享,谨记本人博客:南国以南i. 准备工作:现有一个User类.Student 类和Ticket类,加入相关依赖 @Data public class User { / ...
- HarmonyOS跨进程通信—IPC与RPC通信开发指导
一.IPC与RPC通信概述 基本概念 IPC(Inter-Process Communication)与RPC(Remote Procedure Call)用于实现跨进程通信,不同的是前者使用Bi ...
- 报名直达丨HarmonyOS开发者创新大赛线下城市交流会来了,约吗?
HarmonyOS开发者创新大赛线下城市交流会 正式开启啦! 在这里,将有专业的讲师 与HarmonyOS开发者们面对面演示开发实操.交流开发心得 还等什么?赶快扫码报名吧~↓↓↓ 城市交流会报名链接 ...
- C++ 类方法解析:内外定义、参数、访问控制与静态方法详解
C++ 类方法 类方法,也称为成员函数,是属于类的函数.它们用于操作或查询类数据,并封装在类定义中.类方法可以分为两种类型: 类内定义方法: 直接在类定义内部声明和定义方法. 类外定义方法: 在类定义 ...
- CPU性能实战分析
1.从平均负载谈起 我们每次发现线上系统变慢时,第一件事往往都会使用top或者uptime命令查看cpu的负载以及占用率,比如top命令会有下面的结果: top - 15:51:39 up 84 da ...