JAVA综合实验:java小游戏开发:黄金矿工(JFram)

一、需求分析

  1. 游戏类型:首先,需要确定游戏的类型。可以选择扑克牌、益智、解谜、动作、冒险或角色扮演等各种类型。选择与时代相符的受众群体广泛的游戏类型。

  2. 平台适配性:随着技术的进步,人们在不同设备上玩游戏的方式也在变化。考虑到广泛性和可访问性,最好将游戏开发为跨平台应用程序。这样,用户无论是在电脑、手机、平板电脑或其他设备上都能够畅玩该游戏。

  3. 游戏目标和规则:每个游戏都必须有明确的目标和规则。根据游戏类型的不同,目标和规则会有所区别。确保目标具有挑战性和可行性,并且规则简单明了,易于理解。

  4. 游戏界面设计:一个好的游戏必须有令人愉悦的界面设计。界面设计应该有吸引力,注重用户体验,符合现代审美观念。使用合适的颜色、图形和特效来增强游戏的视觉效果。

  5. 引人入胜的剧情:许多成功的游戏都有令人着迷的剧情。创建一个引人入胜的故事情节可以更好地吸引并留住玩家。在剧情中加入各种情节和转折,以激发玩家的兴趣和情感共鸣。

  6. 多样化的关卡和挑战:为了保持游戏的新鲜感和趣味性,添加多样化的关卡和挑战非常重要。关卡的设计应该有逐步增加的难度,挑战玩家的智力和技巧,并激发他们的成就感。

  7. 社交功能:社交互动已经成为现代游戏的重要组成部分。考虑添加社交功能,如排行榜、好友对战、组队合作等。这些功能可以增加玩家之间的互动和竞争,提高游戏的娱乐价值。

  8. 更新和维护:为了保持游戏的活力和吸引力,定期更新和维护至关重要。随着时代推进和玩家反馈,及时修复漏洞、改善功能、添加新内容和特性,并及时发布更新版本。

  9. 用户反馈和数据分析:收集用户反馈和进行数据分析可以帮助优化游戏体验。通过监测用户行为和玩法数据,了解用户偏好和痛点,并采取相应措施来改进游戏质量。

  10. 安全和隐私保护:游戏应该重视用户的安全和隐私保护。在游戏开发中采取必要的安全措施,防止黑客攻击和数据泄露,并遵守相关的隐私政策和法规。

二、开发便利:

Java开发小游戏有许多好处:

  1. 跨平台性:Java具有出色的跨平台能力,一次编写,到处运行。这意味着使用Java开发的游戏可以在几乎所有主流操作系统上运行,包括Windows、Mac和各种Linux发行版,从而扩大了游戏的受众群体。

  2. 强大的生态系统:Java拥有丰富而成熟的生态系统,包括强大的集成开发环境(IDE)如Eclipse、IntelliJ IDEA等,以及相应的库、框架和工具,便于开发人员构建高质量的游戏。

  3. 高性能:尽管一些人认为Java语言性能不足,但随着JVM的不断优化和硬件的提升,现代的Java程序已经具备了相当不错的性能,足以支持大多数小型游戏的需求。

  4. 丰富的API支持:Java提供了广泛的标准API支持,从图形渲染到用户输入处理等方面都有成熟的解决方案,使得开发人员能够更容易地实现游戏所需的各种功能。

  5. 安全性:Java拥有严格的安全特性和内置的安全机制,这对于在线游戏或需要保护用户数据的游戏来说至关重要。

  6. 增量式开发: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

  1. 定义起点终点坐标,线长最小和最大值、方向、钩爪图片、以及基础状态;
  2. 通过GameWin类的frame控件来进行碰撞检测即检测金块石块是否被抓取;
  3. 并调用线的绘制方法绘制线的图像;
  4. 通过switch循环来使得线抓取返回,加分;
  5. 利用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

  1. 定义关卡数,目标得分、总分、药水数量、药水总分、药水状态,开始和结束的时间、药水价格、是否进入商店购买药水,载入背景、任务以及药水的图片的元素
  2. 利用paintSelf来绘制图片
  3. 调用reGame方法来重置各个元素即重新开始游戏
  4. 利用已经封装好的绘制字符串的方法来绘制“开始游戏”四个字
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");
    }
}

六:运行截图

七、总结体会

已实现功能:

  1. 正常启动、运行、关闭程序;
  2. 计分、关卡设置、抓取模块、线类组件运行正常;
  3. 组件闪烁问题利用双缓存技术解决;

困难与问题:

        循环中调用Thread sleep所可能导致出现忙等待,使得程序死锁:

        多人游戏功能未能实现;

体会:

        java语言程序设计是高校计算机相关专业的一门重要课程,它是一门逻辑性较强、概念较多、结构相对复杂的课程,但高校开设的课时却相对较少。学生学习该课程时广泛存在缺乏兴趣、没恒心,态度不端正的现象。传统教学过程中忽视动手实践能力的培养,不利于学生实用技能的提高。让学生通过相互协作应用java程序解决问题,教师或计算机程序引导和促进学生对问题进行深层次的理解,有利于学生沟通合作、解决问题和动手实践能力的提高,有利于激发学生对java程序设计的学习兴趣。

  • 44
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值