小球游戏——开始我们的第一个游戏-----java.多线程的深入理解

每当我们玩着各式各样游戏时,例如LOL,原神,空洞骑士,你会不会突然脑海里蹦出一个想法,如果自己也可以做一个这样的游戏的就好了。虽然这对我们非常遥远,但是也许在踏上这条游戏制作的路时,可能我们能成为这样的一份子。

所以,让我们开始制作我们的第一个游戏吧,我叫做碰撞小球。

多线程游戏 2022-07-26 16-35-38

建立Ballgame类:

1.建立可视化部分,老生常谈了

this.setTitle("多线程游戏");
        this.setSize(1000,1000);
        this.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        FlowLayout flow=new FlowLayout();
        this.setLayout(flow);
        JButton btn=new JButton("停止");
        JButton btn1=new JButton("继续");
        Dimension dim=new Dimension(100,50);
        btn.setPreferredSize(dim);
        btn.addActionListener(ll);
        this.add(btn);
        btn1.setPreferredSize(dim);
        btn1.addActionListener(ll);
        this.add(btn1);
        this.setVisible(true);//建立好所需的界面,给按钮绑好监听器

2.内部加入鼠标监听器:

addMouseListener(new MouseAdapter() { //内部监听器加法,节省空间

            @Override
            public void mousePressed(MouseEvent e) {
                super.mousePressed(e);
                Random rnd=new Random();
                double speedx=rnd.nextInt(8)-1.6;
                double speedy=rnd.nextInt(6)-2.1;
                Color cl=new Color(rnd.nextInt(Integer.MAX_VALUE));
                int size=rnd.nextInt(40)+10;
                Ball ball=new Ball(e.getX(),e.getY(),speedx,speedy,size,cl);
                bl[index++]=ball;
            }//每点击鼠标一次,即给储存小球信息的数组,Ball[],赋予最开始的信息。

        });

3.开辟一个线程,让其负责小球的移动,使得界面其他操作不会被卡死(重中之重,要认真学习)

 Graphics g=getGraphics();
        Threadball run=new Threadball(this,g);//值得注意的是,我们这次传的是一个对象,方便线程取值
        Thread t=new Thread(run);
        t.start();//开辟一个新线程,同时将所需信息传过去

 4.为了使游戏有层级感,用paint画黑矩形:

public void paint(Graphics g){
        g.setColor(Color.black);
        g.fillRect(0,100,1000,50);
    }//绘制黑矩形,使区域划分开,让按钮可以不被遮盖。

也许你会对传对象感到奇怪,这正是多线程中重要的一点在之后会进行讲解。

建立按钮监听器Ac类:用来控制线程进行

 public void actionPerformed(ActionEvent e){
            btnname=e.getActionCommand();
            if(btnname.equals("停止")){
                flag=false;
            }
            if(btnname.equals("继续")){
                flag=true;
               }
    }//写好按钮反应,控制线程进行。

建立Ball类:

利用构析方法,得到所需信息。

绘制小球:

public void drawball(Graphics g){
        g.setColor(cl);
        g.fillOval((int)(x),(int)(y),size,size);
    } //绘制小球

小球移动方法:

 public void move(){

       if(x<0+0.5*size){
           x=0+0.5*size;
           speedx=-speedx;
       }
       if(x>1000-0.5*size){
           x=1000-0.5*size;
           speedx=-speedx;
       }
        if(y<150+0.5*size){
            y=150+0.5*size;
            speedy=-speedy;
        }
        if(y>1000-0.5*size){
            y=1000-0.5*size;
            speedy=-speedy;
        }//小球碰到边界后,及时位置回复,同时改变速度方向

        x+=speedx;
        y+=speedy;//通过使小球的x,y值发生变化,当下次绘制时达到移动的效果。
    }//小球移动

建立ThreadBall类,实现Runable的接口:

利用构析方法,得到所需信息,值得注意的是得到了Ballgame的对象。

线程所具操作:

public void run() {//线程所具操作
        while (true) {

            g.setColor(Color.black);
            g.fillRect(0,100,1000,50);//多次绘制黑矩形,防止被小球遮盖

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }//用延时来控制小球速度,否则计算机计算过快,会使得小球移速过快而效果不好

            for (int i = 0; i < gui.index; i++) {/*之所以一开始要将对象传来,是因为在线程中,无法完成值传递
                故想要获取信息,只能动态得到,用对象来完成*/
                /*如果只是将index传入的话,哪怕进行点击后,index++,而线程中的index始终为0*/

                for (int j = i + 1; j < gui.index; j++) {
                    double distance = Math.abs(bl[i].x - bl[j].x) * Math.abs(bl[i].x - bl[j].x) +
                            Math.abs(bl[i].y - bl[j].y) * Math.abs(bl[i].y - bl[j].y);
                    double rad = ((bl[i].size + bl[j].size) * (bl[i].size + bl[j].size)) / 4;
                    if (distance < rad) {
                        if (bl[i].speedx * bl[j].speedx > 0) {
                            bl[i].speedx = -bl[i].speedx;
                        }
                        if (bl[i].speedy * bl[j].speedy > 0) {
                            bl[i].speedy = -bl[i].speedy;
                        }//检测碰撞与否,利用高中数学原理

                        bl[i].speedx = -bl[i].speedx + rnd.nextInt(1) - 0.7;
                        bl[i].speedy = -bl[i].speedy + rnd.nextInt(1) - 0.4;
                        bl[j].speedx = -bl[j].speedx + rnd.nextInt(1) - 0.5;
                        bl[j].speedy = -bl[j].speedy + rnd.nextInt(1) - 0.3;//如果碰撞了,不仅要反向,还要有变化,防止卡死

                    }
                }

                Ball ball = gui.bl[i];//值得注意的是,数组是地址传递,所以才可以使信息迭代
                ball.move();
                ball.drawball(g);

            }

            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }//让小球留在屏幕上的时间

            while (!gui.ll.flag/*取到监听器的flag来控制线程的进行*/) {
                try {
                    Thread.sleep(10);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }//利用while循环卡死

            g.setColor(Color.white);
            g.fillRect(0,150,1000,850);//通过白屏的手段消除之前图像,方便小球独立出来

        }
    }

值得回味的是,我们得到小球数目,即index的时候,我们并非利用什么构析方法,抑或是值传递而得到,而是通过Ballgame类的gui对象,来动态取得,如此才可以得到。

除此之外,我们应当牢记数组是采取地址传递的,故虽然每次循环时,我们都会建立一个临时Ball类的ball对象来进行move方法,使得坐标值发发生变化,而下个临时对象依然能得到改变后的信息,就在于数组的特殊性。

猜你喜欢

转载自blog.csdn.net/AkinanCZ/article/details/125997854