一、需求分析
-
游戏类型:首先,需要确定游戏的类型。可以选择扑克牌、益智、解谜、动作、冒险或角色扮演等各种类型。选择与时代相符的受众群体广泛的游戏类型。
-
平台适配性:随着技术的进步,人们在不同设备上玩游戏的方式也在变化。考虑到广泛性和可访问性,最好将游戏开发为跨平台应用程序。这样,用户无论是在电脑、手机、平板电脑或其他设备上都能够畅玩该游戏。
-
游戏目标和规则:每个游戏都必须有明确的目标和规则。根据游戏类型的不同,目标和规则会有所区别。确保目标具有挑战性和可行性,并且规则简单明了,易于理解。
-
游戏界面设计:一个好的游戏必须有令人愉悦的界面设计。界面设计应该有吸引力,注重用户体验,符合现代审美观念。使用合适的颜色、图形和特效来增强游戏的视觉效果。
-
引人入胜的剧情:许多成功的游戏都有令人着迷的剧情。创建一个引人入胜的故事情节可以更好地吸引并留住玩家。在剧情中加入各种情节和转折,以激发玩家的兴趣和情感共鸣。
-
多样化的关卡和挑战:为了保持游戏的新鲜感和趣味性,添加多样化的关卡和挑战非常重要。关卡的设计应该有逐步增加的难度,挑战玩家的智力和技巧,并激发他们的成就感。
-
社交功能:社交互动已经成为现代游戏的重要组成部分。考虑添加社交功能,如排行榜、好友对战、组队合作等。这些功能可以增加玩家之间的互动和竞争,提高游戏的娱乐价值。
-
更新和维护:为了保持游戏的活力和吸引力,定期更新和维护至关重要。随着时代推进和玩家反馈,及时修复漏洞、改善功能、添加新内容和特性,并及时发布更新版本。
-
用户反馈和数据分析:收集用户反馈和进行数据分析可以帮助优化游戏体验。通过监测用户行为和玩法数据,了解用户偏好和痛点,并采取相应措施来改进游戏质量。
-
安全和隐私保护:游戏应该重视用户的安全和隐私保护。在游戏开发中采取必要的安全措施,防止黑客攻击和数据泄露,并遵守相关的隐私政策和法规。
二、开发便利:
Java开发小游戏有许多好处:
-
跨平台性:Java具有出色的跨平台能力,一次编写,到处运行。这意味着使用Java开发的游戏可以在几乎所有主流操作系统上运行,包括Windows、Mac和各种Linux发行版,从而扩大了游戏的受众群体。
-
强大的生态系统:Java拥有丰富而成熟的生态系统,包括强大的集成开发环境(IDE)如Eclipse、IntelliJ IDEA等,以及相应的库、框架和工具,便于开发人员构建高质量的游戏。
-
高性能:尽管一些人认为Java语言性能不足,但随着JVM的不断优化和硬件的提升,现代的Java程序已经具备了相当不错的性能,足以支持大多数小型游戏的需求。
-
丰富的API支持:Java提供了广泛的标准API支持,从图形渲染到用户输入处理等方面都有成熟的解决方案,使得开发人员能够更容易地实现游戏所需的各种功能。
-
安全性:Java拥有严格的安全特性和内置的安全机制,这对于在线游戏或需要保护用户数据的游戏来说至关重要。
-
增量式开发:Java拥有很好的代码组织和模块化支持,有利于团队协作开发。此外,在游戏开发过程中,Java还支持增量式开发(Iterative development),使得开发人员可以逐步完善和修改游戏。
综合这些优点,使用Java开发小游戏可以带来跨平台的灵活性、稳定性和安全性,并在代码编写和团队协作方面提供便利。
三、项目结构
代码结构:
结构体:
结构图:
四、类
主类:GanmeWin
父类:Object
线类:Line(draw)
背景类:Bg
子类:Rock,Gold,GoldMini
五、代码解读
主类GameWin
继承JFram的主程序;
public class GameWin extends JFrame {
//程序状态 0未开始 1运行中 2商店 3失败 4胜利
static int state;
//存储金块,石块的列表集合
List<Object>objectList=new ArrayList<>();
Bg bg=new Bg();
Line line=new Line(this);
{
//是否可以放置,更新位置
boolean isPlace=true;
for (int i = 0; i < 11; i++) {
//随机数位置生成金块组件
double random=Math.random();
Gold gold;//存放当前生成的金块;
//条件判断生成金块大小的概率
if (random< 0.3 ){gold=new GoldMini();}
else if (random< 0.4){gold=new Gold();}
else{gold=new GoldPlus();}
for (Object obj:objectList){
if (gold.getRec().intersects(obj.getRec())){
//不能放置,重新生成
isPlace=false;
}
}
if (isPlace){objectList.add(gold);}
else {isPlace=true;i--;}
}
//随机数位置生成石块组件
for (int i = 0; i < 5; i++) {
Rock rock=new Rock();
for (Object obj:objectList){
if (rock.getRec().intersects(obj.getRec())){
//不能放置,重新生成
isPlace=false;
}
}
//释放状态,抓取后的石块不再生成
if (isPlace){objectList.add(rock);}
else {isPlace=true;i--;}
}
}
//新建一个画布,运用双缓存技术解决JAVA运行框组件闪动问题
Image offScreenImage;
//创建运行框基础数据
void launch(){
this.setVisible(true);
this.setSize(768,864);
this.setLocationRelativeTo(null);
this.setTitle("黄金矿工JAVA版");
setDefaultCloseOperation(EXIT_ON_CLOSE);
//添加鼠标右按键反馈
addMouseListener(new MouseAdapter() {
@Override
public void mouseClicked(MouseEvent e) {
super.mouseClicked(e);
//应用鼠标点击状态对应程序运行状态,参数为state
switch (state) {
case 0 -> {
if (e.getButton() == 3) {
state = 1;
bg.startTime = System.currentTimeMillis();
}
}
case 1 -> {
//左右摇摆,点击左键
if (e.getButton() == 1 && line.state == 0) {
line.state = 1;
}
//抓取返回,点击右键
if (e.getButton() == 3 && line.state == 3 && Bg.waterNum > 0) {
Bg.waterFlag = true;
Bg.waterNum--;
}
}
case 2 -> {
if (e.getButton() == 1) {
bg.shop = true;
}
if (e.getButton() == 3) {
state = 1;
bg.startTime = System.currentTimeMillis();
}
}
case 3, 4 -> {
if (e.getButton() == 1) {
state = 0;
bg.reGame();
line.reGame();
}
}
default -> {
}
}
}});
//建立死循环和延时,使线类重复绘制
//!!!!循环中调用Thread可能导致忙等待,使程序死锁!!!!
while (true) {
repaint();
nextlevel();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
//设置下一关
public void nextlevel(){
if (bg.gameTime()&&state==1){
if (Bg.count>= bg.goal){
if (Bg.level==5){
state=4;
}
else {
state=2;
Bg.level++;
}
}else {
state=3;
}
dispose();
GameWin gameWin=new GameWin();
gameWin.launch();
}
}
//画笔工具调用
@Override
public void paint(Graphics g) {
//双缓存画布大小参数
offScreenImage=this.createImage(768,1000);
Graphics gImage=offScreenImage.getGraphics();
bg.paintSelf(gImage);
if (state==1){
//绘制物体
for (Object obj:objectList)
{
obj.paintSelf(gImage);
}
line.paintSelf(gImage);
}
g.drawImage(offScreenImage,0,0,null);
}
//主函数程序入口,调用软件包和类
public static void main(String[] args) {
GameWin gameWin=new GameWin();
gameWin.launch();
}
}
父类Object(石块和金块的父类)
定义金块或石块的元素:生成位置、宽、高、质量、积分
package com.sxt;
import java.awt.*;
public class Object {
//坐标
int x;
int y;
//宽高
int width;
int height;
//图片
Image img;
//标记,是否能移动
boolean flag;
//质量
int m;
//积分
int count;
//类型1金块,2石块
int type;
void paintSelf(Graphics g){g.drawImage(img,x,y,null);}
public int getWidth() {
return width;
}
//获取矩形
public Rectangle getRec(){
return new Rectangle(x,y,width,height);
}
}
线类Line
- 定义起点终点坐标,线长最小和最大值、方向、钩爪图片、以及基础状态;
- 通过GameWin类的frame控件来进行碰撞检测即检测金块石块是否被抓取;
- 并调用线的绘制方法绘制线的图像;
- 通过switch循环来使得线抓取返回,加分;
- 利用try{} catch{}来使得线程休眠并抛出异常;
package com.sxt;
import java.awt.*;
public class Line {
//线类起点坐标设置
int x = 380;
int y = 180;
//线长终点坐标设置
int enx = 500;
int eny = 500;
//线长设置
double length = 100;
//线长最小值
double MIN_length=100;
//线长最大值
double MAX_length=750;
double n = 0;
//红线伸缩方向
int dir = 1;
//状态 0摇摆 1抓取 2收回 3抓取返回
int state;
//钩爪图片插入
Image hook=Toolkit.getDefaultToolkit().getImage("imgs\\hook.png");
GameWin frame;
Line(GameWin frame){this.frame=frame;}
//碰撞检测,检测金块,石块是否被抓取
void logic()
{
for (Object obj:this.frame.objectList)
{
if (enx>obj.x&&enx<obj.x+obj.width
&&eny>obj.y&&eny<obj.y+obj.height)
{
state=3;
//释放抓取参数
obj.flag=true;
}
}
}
//xian红线绘制方法Graphics g
void lines(Graphics g){
enx = (int) (x + length * Math.cos(n * Math.PI));
eny = (int) (y + length * Math.sin(n * Math.PI));
//线类颜色设置
g.setColor(Color.red);
//画线
g.drawLine(x-1, y, enx-1, eny);
g.drawLine(x, y, enx, eny);
g.drawLine(x+1, y, enx+1, eny);
//图像位置端口
g.drawImage(hook,enx-36,eny-2,null);
}
void paintSelf(Graphics g) {
logic();
//抓取状态判断
switch (state) {
case 0 -> {
if (n < 0.1) {
dir = 1;
} else if (n > 0.9) {
dir = -1;
}
n = n + 0.005 * dir;
lines(g);
}
case 1 -> {
if (length < MAX_length) {
length = length + 5;
lines(g);
} else {
state = 2;
}
}
case 2 -> {
if (length > MIN_length) {
length = length - 5;
lines(g);
} else {
state = 0;
}
}
case 3 -> {//红线抓取返回
int m = 1;
if (length > MIN_length) {
//线类实现抓取后返回速度的设置
length = length - 5;
lines(g);
for (Object obj : this.frame.objectList) {
if (obj.flag) {
m = obj.m;
obj.x = enx - obj.getWidth() / 2;
obj.y = eny;
if (length <= MIN_length) {
obj.x = -150;
obj.y = -150;
obj.flag = false;
Bg.waterFlag = false;
//抓取到元素后加分项设置
Bg.count += obj.count;
state = 0;
}
if (Bg.waterFlag) {
if (obj.type == 1) {
m = 1;
}
if (obj.type == 2) {
obj.x = -150;
obj.y = -150;
obj.flag = false;
Bg.waterFlag = false;
state = 2;
}
}
}
}
}
try {
Thread.sleep(m);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
default -> {
}
}
}
//重置线
void reGame(){
n=0;
length=100;
}
}
背景类Bg
- 定义关卡数,目标得分、总分、药水数量、药水总分、药水状态,开始和结束的时间、药水价格、是否进入商店购买药水,载入背景、任务以及药水的图片的元素
- 利用paintSelf来绘制图片
- 调用reGame方法来重置各个元素即重新开始游戏
- 利用已经封装好的绘制字符串的方法来绘制“开始游戏”四个字
package com.sxt;
import java.awt.*;
public class Bg {
//关卡数
static int level=1;
//目标得分
int goal=level*15;
//总分
static int count=0;
//药水数量
static int waterNum=3;
//药水状态,默认false,true表示正在使用
static boolean waterFlag=false;
//开始时间
long startTime;
//结束时间
long endTime;
//药水价格
int price= (int) (Math.random()*10);
//是否进入商店f不购买
boolean shop=false;
//载入图片
Image bg=Toolkit.getDefaultToolkit().getImage("imgs\\bg.jpg");
Image bg1=Toolkit.getDefaultToolkit().getImage("imgs\\bg1.jpg");
Image peo=Toolkit.getDefaultToolkit().getImage("imgs\\peo.png");
Image water=Toolkit.getDefaultToolkit().getImage("imgs\\water.png");
//绘制方法
void paintSelf(Graphics g){
g.drawImage(bg,0,0,null);
g.drawImage(bg1,0,30,null);
switch (GameWin.state){
case 0:
drawWord(g,80,Color.green,"准备开始",200,400);
break;
case 1:
g.drawImage(peo,310,80,null);
drawWord(g,30,Color.black,"积分:"+count,30,150);
//药水组件
g.drawImage(water,450,40,null);
drawWord(g,30,Color.black,"*"+waterNum,510,70);
//绘制关卡数
drawWord(g,20,Color.black,"第"+level+"关",30,60);
//目标积分
drawWord(g,30,Color.black,"目标:"+goal,30,110);
//时间组件
endTime=System.currentTimeMillis();
long tim=20-(endTime-startTime)/1000;
drawWord(g,30,Color.black,"时间"+(tim>0?tim:0),520,150);
break;
case 2:
g.drawImage(water,300,400,null);
drawWord(g,30,Color.black,"价格:"+price,300,500);
drawWord(g,30,Color.black,"是否购买?",300,550);
if (shop){
count=count-price;
waterNum++;
shop=false;
GameWin.state=1;
startTime=System.currentTimeMillis();
}
break;
case 3:
drawWord(g,80,Color.cyan,"失败",250,350);
drawWord(g,80,Color.cyan,"积分:"+count,200,450);
break;
case 4:
drawWord(g,80,Color.red,"成功",250,350);
drawWord(g,80,Color.red,"积分:"+count,200,450);
break;
default:
}
}
//t倒计时完成f正在倒计时
boolean gameTime()
{
long tim=(endTime-startTime)/1000;
if (tim>20){return true;}
return false;
}
//重置元素
void reGame(){
//关卡数
level=1;
//目标得分
goal=level*15;
//总分
count=0;
//药水数量
waterNum=3;
//药水状态,默认false,true表示正在使用
waterFlag=false;
}
//绘制字符串的方法,已封装
public static void drawWord(Graphics g,int size,Color color,String str,int x,int y){
g.setColor(color);
g.setFont(new Font("仿宋",Font.BOLD,size));
g.drawString(str,x,y);
}
}
金块类Gold(包括Gold,GoldMini,GoldPlus)
1、继承父类Object类;
2、利用构造函数来构造金块的基础数据生成位置坐标、长、宽、高、质量、图样以及积分;
3、在利用继承的方法来生成迷你金块和巨型金块;
package com.sxt;
import java.awt.*;
public class Gold extends Object{
//类型一:金块基础数据,长宽52,生成位置为xy,质量30,中等大小得分4
Gold(){
this.x=(int)(Math.random()*700);
this.y=(int)(Math.random()*400+300);
this.width=52;
this.height=52;
this.m=30;
this.flag=false;
this.count=4;
this.type=1;
this.img= Toolkit.getDefaultToolkit().getImage("imgs\\gold2.png");
}
}
//迷你金块基础数据,长宽36,生成位置为xy,质量15,小型大小得分2
class GoldMini extends Gold{
GoldMini(){
this.width=36;
this.height=36;
this.m=15;
this.count=2;
this.img=Toolkit.getDefaultToolkit().getImage("imgs\\gold1.png");
}
}
//巨型金块基础数据,长宽105,生成位置为xy,质量60,中等大小得分8
class GoldPlus extends Gold{
GoldPlus(){
this.x=(int)(Math.random()*650);
this.width=105;
this.height=105;
this.m=60;
this.count=8;
this.img=Toolkit.getDefaultToolkit().getImage("imgs\\gold3.png");
}
}
石块类Rock:
1、继承父类Object类;
2、利用构造函数来构造石块的基础数据生成位置坐标、长、宽、高、质量、图样以及积分;
package com.sxt;
import java.awt.*;
public class Rock extends Object{
//类型二:石块基础数据,长宽71,生成位置为xy,质量50,得分1
Rock(){
this.x=(int)(Math.random()*700);
this.y=(int)(Math.random()*450+300);
this.width=71;
this.height=71;
this.m=50;
this.flag=false;
this.count=1;
this.type=2;
this.img= Toolkit.getDefaultToolkit().getImage("imgs\\rock.png");
}
}
六:运行截图
七、总结体会
已实现功能:
- 正常启动、运行、关闭程序;
- 计分、关卡设置、抓取模块、线类组件运行正常;
- 组件闪烁问题利用双缓存技术解决;
困难与问题:
循环中调用Thread sleep所可能导致出现忙等待,使得程序死锁:
多人游戏功能未能实现;
体会:
java语言程序设计是高校计算机相关专业的一门重要课程,它是一门逻辑性较强、概念较多、结构相对复杂的课程,但高校开设的课时却相对较少。学生学习该课程时广泛存在缺乏兴趣、没恒心,态度不端正的现象。传统教学过程中忽视动手实践能力的培养,不利于学生实用技能的提高。让学生通过相互协作应用java程序解决问题,教师或计算机程序引导和促进学生对问题进行深层次的理解,有利于学生沟通合作、解决问题和动手实践能力的提高,有利于激发学生对java程序设计的学习兴趣。