项目二 黄金矿工 1

1 绘制窗口

public class GameWin extends JFrame {

//    窗口绘制方法
    void launch(){
        this.setVisible(true);
        this.setSize(500,500);
//        设置窗口位置,居中
        this.setLocationRelativeTo(null);
        this.setTitle("黄金矿工");
//        关闭窗口
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }


    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.launch();
    }

}

2 背景绘制

背景中需要添加人物,矿山,天空
创建背景类来接收,在主类中调用

  1. 创建Bg类
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(bg,0,200,null);
        g.drawImage(bg1,0,0,null);
        g.drawImage(peo,310,50,null);
    }

}

  1. 主类中调用(GameWin.java)

创建Bg类对象,
创建绘制图片的方法,调用paintSelf

Bg bg = new Bg();

//    绘制图片
public void paint(Graphics g){
    bg.paintSelf(g);
}

运行后
在这里插入图片描述

3 红线绘制

创建红线类

public class Line {
//    起点坐标
    int x=380;
    int y=180;
//    终点坐标
    int endx=500;
    int endy=500;
//    线长
    double length = 100;
    double n = 0;
//    添加方向参数
    int dir = 1;

//    Graphics对象代表画笔
    void paintSelf(Graphics g){
        if (n<0.1){
            dir=1;
        }else if (n>0.9){
            dir=-1;
        }
        n=n+0.005*dir;
        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);
    }
}

方向参数初始值为1,当在0-2PI之间运动时,方向为正,当超出2PI时,红线转向dir为负

在主类中,创建Line对象,调用paintSelf方法绘制红线,注意,在绘制方法中,加入死循环,可以让红线一直运动

    Line line = new Line();
//    窗口绘制方法
    void launch(){
        this.setVisible(true);
        this.setSize(768,1000);
//        设置窗口位置,居中
        this.setLocationRelativeTo(null);
        this.setTitle("黄金矿工");
//        关闭窗口
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//*******************************************************************************
        while (true){
            repaint();

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
//*******************************************************************************
    }

4 线的延长和收回

在红线类中的定义线的状态 Line类

红线状态 0:摇摆 1:抓取 2:收回

 int state;

将绘制红线的代码提出,写成一个方法

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中

void paintSelf(Graphics g){

        switch (state){
            //case0 线摇摆
            case 0:
                if (n<0.1){
                    dir=1;
                }else if (n>0.9){
                    dir=-1;
                }
                n=n+0.005*dir;
                lines(g);
                break;
            case 1:  //抓取
                if (length<500){
                    length = length+10;
                    lines(g);
                }else {state=0;}
                break;
            case 2:
                if (length>100){
                    length=length-10;
                    lines(g);
                }else {state=0;}
        }
    }

在主类中,创建Line对象,添加鼠标监听事件,这样点击鼠标,就能控制线的移动

Line line = new Line();

//    窗口绘制方法
    void launch(){
        this.setVisible(true);
        this.setSize(768,1000);
//        设置窗口位置,居中
        this.setLocationRelativeTo(null);
        this.setTitle("黄金矿工");
//        关闭窗口
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//*******************************************************************************
       addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
//                点击鼠标左键(e.getButton()==1),线的状态为抓取
                if (e.getButton()==1){
                    line.state=1;
                }else if (e.getButton()==3){
//                点击鼠标右键(e.getButton()==3),线的状态为收回
                    line.state=2;
                }
            }
        });
//*******************************************************************************

        while (true){
            repaint();

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

    }

6 金块绘制

金块和石头是我们后续要创建的对象,他们有很多共同的属性,创建Object类,让石头类和金块类继承Object类

  1. Object类
public class Object {
    //坐标
    int x;
    int y;
    //宽高
    int width;
    int height;
//    图片
    Image img;
//    绘制方法
    void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }
}
public class Gold extends Object{
    Gold(){
        this.x=300;
        this.y=500;
        this.width=52;
        this.height=52;
        this.img= Toolkit.getDefaultToolkit().getImage("imgs/gold1.gif");
    }
}

7 闪动问题解决

每次都会创建新的画布,都会刷新一次
创建一个一摸一样的画布,放在最下层,每次重新绘制时,就不会出现闪动现象

public void paint(Graphics g){

//        创建两个画布,一个放在最下面,第一步先把金块背景放进去
        offScreenImage = this.createImage(768,1000);
        Graphics gImage = offScreenImage.getGraphics();
        bg.paintSelf(gImage);
        line.paintSelf(gImage);
        gold.paintSelf(gImage);

//        第二步把画布画到背景中
        g.drawImage(offScreenImage,0,0,null);
    }

8 抓取判定与返回

当绳子碰到金块时,就把金块从屏幕移除,绳子返回

  1. 定义绳子新状态 state3 抓取返回
  2. 定义方法,当绳子碰到金块的所在区域时,判定绳子碰到了金块,此时绳子就是新状态
GameWin frame;
Line(GameWin frame){
    this.frame = frame;
}
//当绳子在金块的四边形区域内时,绳子的状态为3 
void logic(){
    if (endx>this.frame.gold.x && endx<this.frame.gold.x+this.frame.gold.width &&
    endy>this.frame.gold.y && endy<this.frame.gold.y+this.frame.gold.height){
        state=3;
     }
 }

//    Graphics对象代表画笔
    void paintSelf(Graphics g){
//      调用判断,当绳子碰到金块时,绳子的状态时3,此时在switch中写状态3情况
        logic();
        switch (state){
            //case0 线摇摆
            case 0:
                if (n<0.1){
                    dir=1;
                }else if (n>0.9){
                    dir=-1;
                }
                n=n+0.005*dir;
                lines(g);
                break;
//                case1 抓取
            case 1:
                if (length<500){
                    length = length+10;
                    lines(g);
                }else {state=0;}
                break;
            case 2:
                if (length>100){
                    length=length-10;
                    lines(g);
                }else {state=0;}
//*******************************************************************************
            case 3:
                if (length>100){
                    length=length-10;
                    lines(g);
//                    减去偏移量  金块长度的一半
                    this.frame.gold.x=endx-26;
                    this.frame.gold.y=endy;
                }else {
//                    抓取成功,直接将金块移除  -150就是放在屏幕外面
                    this.frame.gold.x= -150;
                    this.frame.gold.y= -150;
                    state = 0;
                }
//*******************************************************************************

                break;

        }

    }

9 添加多个金块

  1. 在主类中(GameWin),创建集合,用来存放金块,后续放石头
//    可以用来放金块,石块
List<Object> objectList = new ArrayList<>();

在方法体中写循环,来遍历上述集合

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

在绘制方法中绘制出来

public void paint(Graphics g){
//创建一个一摸一样的画布,放在最下层,每次重新绘制时,就不会出现闪动现象
//        创建两个画布,一个放在最下面,第一步先把金块背景放进去
        offScreenImage = this.createImage(768,1000);
        Graphics gImage = offScreenImage.getGraphics();
        bg.paintSelf(gImage);
        line.paintSelf(gImage);
//*******************************************************************************     
//        绘制金块,采用增强for循环
        for (Object obj:objectList){
            obj.paintSelf(gImage);
        }
//*******************************************************************************
//        第二步把画布画到背景中
        g.drawImage(offScreenImage,0,0,null);
    }

金块类改变了,原来创建金块的类被用集合代替了,所以在 Line类 中,需要修改代码

原logic()方法:

void logic(){
    if (endx>this.frame.gold.x && endx<this.frame.gold.x+this.frame.gold.width &&
    endy>this.frame.gold.y && endy<this.frame.gold.y+this.frame.gold.height){
        state=3;
     }
}

修改后的:

void logic(){
//        从主窗口中拿objectList集合来遍历
        for (Object obj: frame.objectList){
            if (endx>obj.x && endx<obj.x+obj.width &&
                    endy>obj.y && endy<obj.y+obj.height){
                state=3;
            }
        }
    }

case3中也按照同样的方法来改

case 3:
    if (length>100){
        length=length-10;
        lines(g);
//      减去偏移量  金块长度的一半

    for (Object obj: frame.objectList){
        obj.x=endx-26;
        obj.y=endy;
        if (length<=100){
//      抓取成功,直接将金块移除  -150就是放在屏幕外面
             obj.x= -150;
             obj.y= -150;
             state = 0;
         }
    }
 }
  1. 修改 Gold类
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.img= Toolkit.getDefaultToolkit().getImage("imgs/gold1.gif");
//        flag 的初始值为false,代表没被抓到,不移动
        this.flag = false;
    }
}

10 解决金块消失的bug

经过上面的操作我们会发现,每次抓一个金块,其余的都会被带走是因为case3中这段代码,抓到之后,所有的金块都会被移走

for (Object obj: frame.objectList){
        obj.x=endx-26;
        obj.y=endy;
        if (length<=100){
//      抓取成功,直接将金块移除  -150就是放在屏幕外面
             obj.x= -150;
             obj.y= -150;
             state = 0;
         }
    }

因为后续我们不仅抓金块,还会涉及到抓石块,所以在 Object类 中加入布尔类型的判断,判断位置的改变(其余代码省略)

public class Object {

// 标记,是否能移动
    boolean flag;
}

Gold类 中(其余代码省略)

public class Gold extends Object{
    Gold(){
//        flag 的初始值为false,代表没被抓到,不移动
        this.flag = false;
    }
}

于是在 Line类 中,对flag 进行判断

//    Graphics对象代表画笔
void paintSelf(Graphics g){
//      调用判断,当绳子碰到金块时,绳子的状态时3,此时在switch中写状态3情况
   logic();
   switch (state){
      case 3:
          if (length>100){
             ength=length-10;
             lines(g);
// 减去偏移量  金块长度的一半
          for (Object obj: frame.objectList){
             if (obj.flag==true){
                 obj.x=endx-26;
                 obj.y=endy;
                 if (length<=100){
//抓取成功,直接将金块移除  -150就是放在屏幕外面
                    obj.x= -150;
                    obj.y= -150;
                    obj.flag=false;
                    state = 0;
      }        
}

11 创建石块类

Gold类

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.img= Toolkit.getDefaultToolkit().getImage("imgs/rock1.png");
//        flag 的初始值为false,代表没被抓到,不移动
        this.flag = false;
    }
}

在GameWin类中,遍历创建金块石块对象,遍历

//创建金块,石块
{
    for (int i=0;i<3;i++){
        objectList.add(new Gold());
    }
    for (int i=0;i<3;i++){
        objectList.add(new Rock());
    }
}

第一部分小结

  • 创建主类
    GameWin类为主类,主要进行窗口绘制,绘制图片,添加金块、石块、背景类
public class GameWin extends JFrame {

//    可以用来放金块,石块
    List<Object> objectList = new ArrayList<>();
//背景对象
    Bg bg = new Bg();
//    线对象
    Line line = new Line(this);
//定义画布
    Image offScreenImage;
//创建金块,石块,遍历
    {
        for (int i=0;i<3;i++){
            objectList.add(new Gold());
        }
        for (int i=0;i<3;i++){
            objectList.add(new Rock());
        }

    }


//    窗口绘制方法
    void launch(){
        this.setVisible(true);
        this.setSize(768,1000);
//        设置窗口位置,居中
        this.setLocationRelativeTo(null);
        this.setTitle("黄金矿工");
//        关闭窗口
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
//     鼠标监听事件
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                super.mouseClicked(e);
//                点击鼠标左键(e.getButton()==1),线的状态为抓取
                if (e.getButton()==1){
                    line.state=1;
                }else if (e.getButton()==3){
//                点击鼠标右键(e.getButton()==3),线的状态为收回
                    line.state=2;
                }
            }
        });
        while (true){
            repaint();

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

    }

//    绘制图片
//    Graphics 代表画笔
    public void paint(Graphics g){
//创建一个一摸一样的画布,放在最下层,每次重新绘制时,就不会出现闪动现象
//        创建两个画布,一个放在最下面,第一步先把金块背景放进去
        offScreenImage = this.createImage(768,1000);
        Graphics gImage = offScreenImage.getGraphics();
        bg.paintSelf(gImage);
        line.paintSelf(gImage);
        
//        绘制金块,采用增强for循环来遍历金块和石块
        for (Object obj:objectList){
            obj.paintSelf(gImage);
        }

//        第二步把画布画到背景中
        g.drawImage(offScreenImage,0,0,null);
    }


    public static void main(String[] args) {
        GameWin gameWin = new GameWin();
        gameWin.launch();
    }

}
  • 创建背景类
    背景类主要添加三个图片:人物、天空、矿
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(bg,0,200,null);
        g.drawImage(bg1,0,0,null);
        g.drawImage(peo,310,50,null);
    }

}
  • 创建Object类
    Object类是金块类石头类的父类,写他们的公共部分
public class Object {

// 标记,是否能移动
    boolean flag;
    //坐标
    int x;
    int y;
    //宽高
    int width;
    int height;
//    图片
    Image img;
//    绘制方法
    void paintSelf(Graphics g){
        g.drawImage(img,x,y,null);
    }

//    Line方法中,需要获取金块石块的宽度的一般,来计算偏移量,这里定义getWidth就能在Line类的paintSelf方法中得到了
    public int getWidth() {
        return width;
    }
}
  • 金块类
    写入金块的大小,图片状态
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.img= Toolkit.getDefaultToolkit().getImage("imgs/gold1.gif");
//        flag 的初始值为false,代表没被抓到,不移动
        this.flag = false;
    }

}
  • 石块类
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.img= Toolkit.getDefaultToolkit().getImage("imgs/rock1.png");
//        flag 的初始值为false,代表没被抓到,不移动
        this.flag = false;
    }
    
}
  • 创建线类
    logic() 方法表示当线碰到金块/石块的范围后,线的状态发生改变,
    lines() 方法表示绘制红线
public class Line {
//    起点坐标
    int x=380;
    int y=180;
//    终点坐标
    int endx=500;
    int endy=500;
//    线长
    double length = 100;
    double n = 0;
//    添加方向参数
    int dir = 1;

//    红线状态  0:摇摆  1:抓取  2:收回  3:抓取返回
    int state;

    GameWin frame;
    Line(GameWin frame){
        this.frame = frame;
    }

    void logic(){
//        从主窗口中拿objectList集合来遍历
        for (Object obj: 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(Color.RED);
        g.drawLine(x,y,endx,endy);
    }

//    Graphics对象代表画笔
    void paintSelf(Graphics g){
//      调用判断,当绳子碰到金块时,绳子的状态时3,此时在switch中写状态3情况
        logic();
        switch (state){
            //case0 线摇摆
            case 0:
                if (n<0.1){
                    dir=1;
                }else if (n>0.9){
                    dir=-1;
                }
                n=n+0.005*dir;
                lines(g);
                break;
//                case1 抓取
            case 1:
                if (length<500){
                    length = length+10;
                    lines(g);
                }else {state=0;}
                break;
            case 2:
                if (length>100){
                    length=length-10;
                    lines(g);
                }else {state=0;}
            case 3:
                if (length>100){
                    length=length-10;
                    lines(g);
//                    减去偏移量  金块长度的一半
                    for (Object obj: frame.objectList){
                        if (obj.flag==true){
                            obj.x=endx-obj.getWidth()/2;
                            obj.y=endy;
                            if (length<=100){
                                //抓取成功,直接将金块移除  -150就是放在屏幕外面
                                obj.x= -150;
                                obj.y= -150;
                                obj.flag=false;
                                state = 0;
                            }
                        }
                    }
                }
                break;
        }
    }
}
  • 3
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值