栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

【JAVA】-- 黄金矿工小游戏(一)(实现思路+每步代码)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

【JAVA】-- 黄金矿工小游戏(一)(实现思路+每步代码)

游戏规则:抓取石块右键可以爆破、抓取金块右键快速抓取。

完成任务:窗体绘制、钩爪往返旋转、物体批量绘制、双缓存解决闪动问题、点和矩形碰撞检测、多种类物体随机生成、物体堆叠检测、多种类抓取速度判定、积分设置、关卡设置、重新开始、单关卡倒计时、金块的快速拉取、石块爆破、商店购物。

游戏大致界面:

 一、窗口绘制 创建GameWin类
import javax.swing.*;

public class GameWin extends JFrame {
    void launch(){
        this.setVisible(true);
        this.setSize(500,500);
        this.setLocationRelativeTo(null);//屏幕中央出现窗口
        this.setTitle("黄金矿工");
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.launch();
    }
}
二、绘制图片

需要几个图片素材,私信。

新建imgs文件夹存放图片。

创建Bg类

背景由多个图片组成,所以创建一个背景类。

获取图片,用绘图技术将图片画在界面上;

注意根据图片大小计算好xy位置。

import java.awt.*;

public class Bg {
    Image bg = Toolkit.getDefaultToolkit().getImage("imgs/bg.jpg");
    Image bg1 = Toolkit.getDefaultToolkit().getImage("imgs/bg1.jpg");
    Image peo = Toolkit.getDefaultToolkit().getImage("imgs/peo.png");
    void paintSelf(Graphics g){
        g.drawImage(bg1,0,0,null);
        g.drawImage(bg,0,282,null);
        g.drawImage(peo,350,133,null);
    }
}
GameWin类增加
    Bg bg = new Bg();
    public void paint(Graphics g){
        bg.paintSelf(g);
    }

查看图片大小,修改界面大小

        this.setSize(814,1000);
三、红线绘制 创建Line类
import java.awt.*;

public class Line {
    int x = 400;//起点在人物坐标处
    int y = 282;//起点坐标
    int endx = 500;
    int endy = 500;//重点坐标
    void paintSelf(Graphics g){
        g.setColor(Color.red);
        g.drawLine(x,y,endx,endy);
    }
}
GameWin类增加
    Line line = new Line();

paint方法增加

line.paintSelf(g);

四、红线摇摆 实现原理:

如何求出endx和endy,找到endx、endy、x、y之间的关系。

计算机中,x轴向右为正方向,y轴向下为正方向;

角度起点为x轴正方向,顺时针旋转90°到达y轴,也就是旋转Π/2即1.57;

可利用此实现摇摆效果,如1小于Π/2,则在y轴右方,2大于Π/2,则在y轴左方。

如果要想实现在0-Π之间摇摆,可以设n∈(0,1)代替cosα中的α,则操作n可实现角度的变化,n*Π∈(0,Π)。

 Line类增加/修改
double length = 100;//线长
    double n = 0;//线摇摆角度
    void paintSelf(Graphics g){
        n+=0.005;
        endx = (int)(x+length*Math.cos(n*Math.PI));
        endy = (int)(y+length*Math.sin(n*Math.PI));
        g.setColor(Color.red);
        g.drawLine(x,y,endx,endy);
    }
GameWin类增加

需要每隔0.01s绘制一次画面,达到摇摆效果。

 while (true){
            repaint();
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

目前,红线是摇摆一整圈,原因是n一直是+0.005,需要设置摇摆的范围,在0-Π之间摇摆。

 五、红线摇摆范围

设置一个dir表示方向即正负,通过判断,改变符号。

 Line类增加
int dir = 1;//方向

paintSelf方法增加/修改

 if(n<0){
            dir = 1;
        }
        else if (n>1){
            dir = -1;
        }
        n+=0.005*dir;
六、红线抓取 Line类增加

state表示状态,通过鼠标点击修改state数值,下面根据state数值实现红线的不同状态。

    int state;//状态0为摇摆,1为抓取,2为收回

由于后面多次使用方法的四行代码,所以定义一个方法,后面直接调用方法。

  void lines(Graphics g){
        endx = (int)(x+length*Math.cos(n*Math.PI));
        endy = (int)(y+length*Math.sin(n*Math.PI));
        g.setColor(Color.red);
        g.drawLine(x,y,endx,endy);
    }

重新修改paintSelf方法,通过switch判断state数值,使红线做出不同动作。

 void paintSelf(Graphics g){
        switch (state){
            case 0:
                if(n<0){
                    dir = 1;
                }
                else if (n>1){
                    dir = -1;
                }
                n+=0.005*dir;
                lines(g);
                break;
            case 1:
                if(length<500){//限制抓取长度
                    length+=10;
                    lines(g);
                }else{state = 2;}//如果超出长度则收回
                break;
            case 2:
                if(length>100){//限制收回长度
                    length-=10;
                    lines(g);
                }else{state = 0;}
                break;
            default:
        }
    }
GameWin类增加

鼠标点击事件,通过getButton()获取点击的键值修改line类的state。

        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
                if(e.getButton() == 1){//鼠标左键1,滚轮2,右键3
                    line.state = 1;
                }
            }
        });
七、创建金块 创建Object类

金块和岩石都有坐标和宽高以及绘制,所以需要定义一个类用来继承。

import java.awt.*;

public class Object {
    int x;
    int y;
    int width;
    int height;
    Image img;
    void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}
创建金块类Gold
import java.awt.*;

public class Gold extends Object{
    Gold(){
        this.x = 300;
        this.y = 500;
        this.width = 78;
        this.height = 88;
        this.img = Toolkit.getDefaultToolkit().getImage("imgs/gold0.png");
    }
}
GameWin类增加
Gold gold = new Gold();

paint方法绘制

gold.paintSelf(g);
八、双缓存技术解决闪动

目前,窗口图片存在闪动问题,原因是像金块这样的图片在岩土这样的背景图片上层,先绘制背景图片再绘制金块图片,再绘制背景图片,再绘制金块......所以产生了图片闪动问题。

可以先将背景图片和金块在绘制之前组织好再一起放置在窗口之上。

GameWin类增加
Image offScreenImage;

paint方法增加

offScreenImage = this.createImage(814,1000);//创建画布
Graphics gImage = offScreenImage.getGraphics();//创建画笔

bg.paintSelf(gImage);
line.paintSelf(gImage);
gold.paintSelf(gImage);

g.drawImage(offScreenImage,0,0,null);//将图片一起绘制
九、抓取判定 Line类增加
   GameWin frame;
    Line(GameWin frame){
        this.frame = frame;
    }
    void logic(){//碰撞检测,检测红线是否在金块范围内
        if(endx > this.frame.gold.x && endx this.frame.gold.y&&endy 

paintSelf方法增加

logic();
GameWin修改

需要传入主类,才能调用主类的方法

Line line = new Line(this);
十、抓取返回 Line类增加/修改

如果红线在金块范围内则改变state状态为3,表示抓取返回。

   void logic(){//碰撞检测,检测红线是否在金块范围内
        if(endx > this.frame.gold.x && endx this.frame.gold.y&&endy 

switch增加判断state为3的情况;

金块的x坐标于红线的x坐标的关系为endx-金块长度/2;

如果抓取金块到达位置则将金块移出屏幕外。

 case 3:
                if(length>100){
                    length-=10;
                    lines(g);
                    this.frame.gold.x = endx - 39;
                    this.frame.gold.y = endy;
                }else{
                    this.frame.gold.x = -150;//移除到屏幕外
                    this.frame.gold.y = -150;
                    state = 0;
                }
                break;
十一、多个金块

使用集合生成多个金块

GameWin类增加

定义集合存储金块

    List objectList = new ArrayList();//存储多个金块
 

循环往集合添加金块

    {
        for (int i = 0; i < 3; i++) {
            objectList.add(new Gold());
        }
    }

paint方法需要循环绘制多个金块

        for(Object obj:objectList){
            obj.paintSelf(gImage);
        }
Line类修改

修改前面使用一个金块的方法

 for(Object obj:this.frame.objectList){
            if(endx > obj.x && endx obj.y&&endy 
 for(Object obj:this.frame.objectList){
                        obj.x = endx - 39;
                        obj.y = endy;
                        if(length<=100){
                            obj.x = -150;//移除到屏幕外
                            obj.y = -150;
                            state = 0;
                        }
                    }
Gold类修改

修改金块生成位置随机

        this.x = (int)(Math.random()*750);//防止生成在窗体
        this.y = (int)(Math.random()*550+300);//防止生成在天上
十二、抓取金块BUG

BUG原因:抓取金块后,修改了所有金块的位置。

BUG解决:设置变量flag标记金块是否能移动

Object类增加
    boolean flag;//标记是否移动
Glod类增加
this.flag = false;
Line类增加

logic方法if增加

obj.flag = true;

switch case 3增加

                    for(Object obj:this.frame.objectList){
                        if(obj.flag){//判断是否能够移动
                            obj.x = endx - 39;
                            obj.y = endy;
                            if(length<=100){
                                obj.x = -150;//移除到屏幕外
                                obj.y = -150;
                                obj.flag = false;
                                state = 0;
                            }
                        }

                    }

 

至此已完成一半内容,下篇文章继续。

转载请注明:文章转载自 www.mshxw.com
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号