Java写一个黄金矿工小游戏

写这个小游戏的初衷

同学一起互助学习

前两天和一个计科的高中同学交流想法,有讲到合理规划时间,然后用分出来的时间去网上找资源学一些项目,这不,就有了这个小游戏了

和同学交流的时候,对方说每周花一个小时来学习,然后写项目,我本来觉得一个小时太少了,一周那么多时间,这一个小时绰绰有余啊

然后真相了,大二生一枚,虽然课看起来不多吧,但是杂七杂八的事情也挺多的,比如本来今天想学一下语言,然后被叫去干活,一会开班会,一会有有党课🌝

但是第一周开始决定要学写项目了,三分钟热度还是要有的,周末肝了一个晚上和一个上午用来改bug,效果还是看得见的

项目资源

先上小破站搜Java项目,看到60多个小时的果断放弃了

滑鼠一滑,两小时黄金矿工,好,就它了

废话不多说,直接上效果吧

视频放不过来,只能截一张图了
在这里插入图片描述

上码

背景类

package com.sxt;

import javax.swing.*;
import java.awt.*;

/**
 * 背景
 */
public class Bg extends JFrame {

    //关卡数
    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);
    //是否进入商店,初始不购买
    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(bg1,0,0,null);
        g.drawImage(bg,0,200,null);
        switch(GameWin.state){
            case 0->{
                drawWord(g,80,Color.green,"准备开始",200,400);
            }
            case 1->{
                g.drawImage(peo,310,50,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);


            }
            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();
                }
            }
            case 3->{
                drawWord(g,80,Color.cyan,"失败",250,350);
                drawWord(g,80,Color.cyan,"积分:"+count,200,450);

            }

            case 4->{
                drawWord(g,80,Color.red,"成功",250,350);
                drawWord(g,80,Color.red,"积分:"+count,200,450);
            }
        }


    }

    //true为倒计时完成,false为正在倒计时
    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);
    }
}

Object类
用来作石块和金块的父类

package com.sxt;

import java.awt.*;

public class Object {
    //坐标
    int x;
    int y;

    //宽高
    int width;
    int height;

    //图片
    Image img;

    //标记是否可移动
    boolean flag=false;//true可移动,false 不可移动

    //质量
    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);
    }
}

Gold类

package com.sxt;

import java.awt.*;

public class Gold extends Object{

    Gold(){
        this.x=(int)(Math.random()*700);
        this.y=(int)(Math.random()*550+300);
        this.width=52;
        this.height=52;
        this.flag=false;
        this.m=30;
        this.count=4;
        this.type=1;
        this.img= Toolkit.getDefaultToolkit().getImage("imgs/gold1.gif");
    }
}

class GoldMin extends Gold{
    GoldMin(){
         this.width=36;
         this.height=36;
         this.m=15;
         this.count=2;
         this.img= Toolkit.getDefaultToolkit().getImage("imgs/gold0.gif");
    }
}

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/gold2.gif");
    }
}

Rock类

package com.sxt;

import java.awt.*;

/**
 * 石块类
 */
public class Rock extends Object{
    Rock(){
        this.x=(int)(Math.random()*700);
        this.y=(int)(Math.random()*550+300);
        this.width=71;
        this.height=71;
        this.flag=false;
        this.m=50;
        this.count=1;
        this.type=2;
        this.img= Toolkit.getDefaultToolkit().getImage("imgs/rock1.png");
    }
}

Line类
游戏时的钩子上的线收缩拉取

package com.sxt;

import java.awt.*;

import static java.awt.Color.red;

public class Line {
    //(x,y)起点坐标
    int x=380;
    int y=180;

    //终点坐标
    int endx=500;
    int endy=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(endx>obj.x&&endx<obj.x+obj.width
                    &&endy>obj.y&&endy<obj.y+obj.height){
                state=3;
                obj.flag=true;//接触到了则可以移动
            }
        }


    }

    //绘制方法
    void lines(Graphics g){//画线
        endx=(int)(x+length*Math.cos(n*Math.PI));
        endy=(int)(y+length*Math.sin(n*Math.PI));
        g.setColor(red);
        g.drawLine(x-1,y,endx-1,endy);
        g.drawLine(x,y,endx,endy);
        g.drawLine(x+1,y,endx+1,endy);
        g.drawImage(hook,endx-36,endy-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+=5;
                   lines(g);
                }else{
                    state=2;//到收回状态
                }
            }

            case 2->{//线收回
                if(length>MIN_length) {
                    length -= 5;
                    lines(g);
                }else{
                    state=0;//回到摇摆的状态
                }
            }

            case 3->{
                int m=1;
                if(length>MIN_length) {
                    length -= 5;
                    lines(g);
                    for(Object obj:this.frame.objectList){
                        if(obj.flag){
                            m=obj.m;
                            obj.x=endx-obj.getWidth()/2;
                            obj.y=endy;
                            if(length<=100){
                                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;
                                 }else 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) {
                    e.printStackTrace();
                }

            }
        }


        }

    //重置线
    void reGame(){
        n=0;
        length=100;
    }



    }


GameWin类,主角登场

package com.sxt;
//窗口绘制
import javax.swing.*;
import java.awt.*;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import java.util.List;

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 GoldMin();
            }else if(random<0.7){
                gold=new GoldPlus();
            }else {
                gold=new Gold();
            }

            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--;
            }

        }
    }

    Image offScreenImage;

    void launch(){
        this.setVisible(true);
        this.setSize(768,1000);
        this.setLocationRelativeTo(null);
        this.setTitle("黄金矿工");
        setDefaultCloseOperation(EXIT_ON_CLOSE);

        addMouseListener(new MouseAdapter(){
           @Override
            public void mouseClicked(MouseEvent e){
               super.mouseClicked(e);
               switch(state){
                   case 0->{
                        if(e.getButton()==3){
                            state=1;
                            bg.startTime=System.currentTimeMillis();//记录开始时间

                        }
                   }
                   case 1->{
                       if(e.getButton()==1&&line.state==0){//鼠标左键=1,右键=3,滚轮=2
                           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();
                       }
                   }
               }

           }
        });


        while(true){
            repaint();//重新绘制
            nextLevel();
            try {
                Thread.sleep(10);//延时,10ms刷新一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

        }
    }

    //下一关
    public void nextLevel(){
        if(bg.gameTime()&&state==1){
            if(Bg.count>=bg.goal){
                if(Bg.level==5){
                    state=4;//进入成功状态
                }else{
                    state=2;
                    Bg.level++;
//                    bg.startTime=System.currentTimeMillis();
                }

            }else{
                state=3;
            }
            dispose();
            GameWin gameWin1= new GameWin();
            gameWin1.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();
    }


}

从这个小游戏中get到的小tips

  1. 使用双缓存技术刷新页面
  • 需求:
    在项目初期,背景中的图片时层叠加入的,刷新一次就每个图片直接再通过画笔drawImage()一次到画布(姑且这么叫)上
    这样就造成了游戏界面频繁闪现,也就是一卡一卡的

  • 解决办法
    重写paint函数,创建一个新的Image,每一次刷新都将图片按次序添加到新的Image上,添加完毕后再将整个Image添加到实际的游戏界面上,这样每次看见的游戏界面的图片都是完整的,不会存在这个刚刚刷新出来,另一部分图片还是之前的,看起来游戏很稳定
    把paint函数挑出来

 @Override
    public void paint(Graphics g){
        offScreenImage=this.createImage(768,1000);//用于双缓存刷频
        Graphics gImage=offScreenImage.getGraphics();//一个新的画笔

        bg.paintSelf(gImage);

        if(state==1){//1为游戏中
            //绘制物体
            for(Object obj:objectList){
                obj.paintSelf(gImage);//使用后新画笔画图像
            }
            line.paintSelf(gImage);//新画笔画线
        }

    g.drawImage(offScreenImage,0,0,null);//将画好的整个Image画到游戏界面
    }

小游戏不完善之处

游戏界面的大小比我实际设置的大小要大一些,(以高度为例,我设置的高度为1000,但是实际的heigth超过了1000,宽度也是这样)以至于游戏界面在我的电脑上不能完全显示,还有一截在屏幕下面看不见,这个问题在视频中是没有的,上网查了一下也不知道是什么问题,这个问题先抛在这


咳咳 手动分割线

显示图片大小 …更新…

关于这个显示图片的问题
我总结下来是我的电脑和老师电脑不一样,更确切地说,是电脑显示的分辨率和缩放度可能是不一样的

我的电脑是1902*1080的分辨率,缩放150%
然后老师演示的电脑好像不一样,
这点可能有点不同

以下尝试修改缩放度来达到效果
不过相当不建议,能改代码就改代码,能不动电脑就别动电脑

设置1:在这里插入图片描述

1902*1034p
150%
效果1:
1902×1034
设置2:在这里插入图片描述

效果2:
在这里插入图片描述
设置3:在这里插入图片描述

效果3:在这里插入图片描述
我觉得缩放度在110%到125%之间应该是效果比较好
但是怕改了之后麻烦太多,就收回了手
在这里插入图片描述

当然,也可以通过计算图片在自己当前电脑上显示的占比,然后经过一通计算更改图片的像素,当然也可以写个方法让电脑自己算

我总觉得还有什么更好的办法
以上改缩放度真心不建议
但是怎么改代码。。。我。。。不知道了。。。
球球路过的大佬捞一捞(●’◡’●)


这个小游戏还是很简单,很基础的,在这个基础上还可以添加一些操作或者选项,让这个小游戏更好玩
譬如通关时背景更炫酷一些,
药水可以在任何时候购买,通过游戏界面按钮来实现交互(是否开始,是否购买药水这些)
有暂停功能
···

写完小游戏

还是超级开心的,一个小游戏在自己的手中一步一步完善,最后的运行效果也还不错,(虽说是跟着别人一部一部写的)也提高了一点点的代码能力和代码量,还是不错的

而且写代码真的有时候会停不下来,视频两小时,然后给自己的时间本来只有每周花一小时来写,但是写一半就放着让人不舒服,于是乎熬夜也要写完才罢休

今天(不,是昨天)正好是1024,纪念2021程序员节

  • 4
    点赞
  • 50
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,下面是一个简单的黄金矿工小游戏Java代码实现。 首先,我们需要定义一些游戏中会用到的常量和变量: ```java public class GoldMiner { private static final int MAX_DEPTH = 10; // 最大深度 private static final int MAX_GOLD = 5; // 最大金子数 private static final int MIN_GOLD = 1; // 最小金子数 private static final int MAX_DISTANCE = 20; // 最大距离 private static final int MIN_DISTANCE = 5; // 最小距离 private static final int MAX_SCORE = 100; // 最大得分 private int depth; // 当前深度 private int gold; // 当前金子数 private int distance; // 当前距离 private int score; // 当前得分 } ``` 接下来,我们需要实现一些游戏中会用到的方法,比如开始游戏、升降钩子、移动人物等: ```java public class GoldMiner { ... /** * 开始游戏 */ public void startGame() { System.out.println("游戏开始!"); // 初始化游戏状态 depth = 0; gold = 0; distance = MIN_DISTANCE; score = 0; // 循环直到到达最大深度或者得分达到最大值 while (depth < MAX_DEPTH && score < MAX_SCORE) { // 升降钩子 upAndDownHook(); // 移动人物 moveCharacter(); // 挖取金子 digGold(); } // 游戏结束 System.out.println("游戏结束!你的得分是:" + score); } /** * 升降钩子 */ private void upAndDownHook() { System.out.println("升降钩子..."); // 计算下降距离和消耗的能量 int dropDistance = (int) (Math.random() * (distance - MIN_DISTANCE)) + 1; int energy = dropDistance * 2; // 检查能量是否足够 if (energy > depth + gold) { System.out.println("能量不足,升降钩子无法下降!"); } else { // 下降一定距离 depth += dropDistance; System.out.println("升降钩子下降了 " + dropDistance + " 米,当前深度为 " + depth + " 米。"); // 消耗能量 int remainingEnergy = energy - gold; if (remainingEnergy > 0) { System.out.println("消耗了 " + remainingEnergy + " 点能量。"); gold = 0; } else { gold -= energy; System.out.println("消耗了 " + energy + " 点能量,剩余金子数为 " + gold + " 个。"); } } } /** * 移动人物 */ private void moveCharacter() { System.out.println("移动人物..."); // 随机生成移动距离 int moveDistance = (int) (Math.random() * (MAX_DISTANCE - MIN_DISTANCE)) + MIN_DISTANCE; // 更新距离 distance -= moveDistance; System.out.println("人物向前移动了 " + moveDistance + " 米,当前距离为 " + distance + " 米。"); } /** * 挖取金子 */ private void digGold() { System.out.println("挖取金子..."); // 随机生成金子数量 int goldNum = (int) (Math.random() * (MAX_GOLD - MIN_GOLD)) + MIN_GOLD; // 更新金子数和得分 gold += goldNum; score += goldNum * depth; System.out.println("挖取了 " + goldNum + " 个金子,当前金子数为 " + gold + " 个,当前得分为 " + score + " 分。"); } } ``` 最后,我们可以在main方法中实例化一个GoldMiner对象并调用其startGame方法来开始游戏: ```java public class Main { public static void main(String[] args) { GoldMiner game = new GoldMiner(); game.startGame(); } } ``` 这样,一个简单的黄金矿工小游戏好了。当然,你可以继续完善它,比如增加难度、添加音效等等。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值