多线程游戏开发

一.什么是线程?

-单线程

一个线程只能做一件任务

-多线程

多线程可以同时做多个任务

很多多线程是模拟出来的,真正的多线程指有多个cpu,即多核,如服务器

而在只有一个cpu模拟出来的多线程中,在同一时间点,cpu只能执行一个代码,因为切换的快,所以产生了同时执行的错觉

以人脑为例,在人看似边吃饭边玩手机时,由于人脑只有一个,在极短的瞬间中,我们其实只是在做吃饭和玩手机中的一件事

即使自己不创建线程,后台也有多个线程,如main线程、gc线程(java中基本所有程序都是多线程的)

-进程与线程

进程是执行一次程序的过程,一个进程包含多个线程

以美剧为例,想要看美剧,必须有声音、图像、字幕等,它们分别对应有自己的线程,同时运行这几个线程,完成了美剧播放这个进程。

二.实现线程

1)继承:Thread类

public class ThreadDemo1 extends Thread{
    //重写run方法

    @Override
    public void run() {
        for(int i=0;i<50;i++){
            System.out.println("任务1正在执行..."+i);
        }
    }
}

2)接口实现:Runnable接口

public class RunnableDemo1 implements Runnable{
    //重写run方法
    public void run() {
        for(int i=0;i<50;i++){
            System.out.println("任务2正在执行..."+i);
        }

    }
}

都需要重写run方法

run方法的作用:把需要同时运行的代码放入run方法中

三.启动线程

需要使用Thread类的start方法

不要调用成run方法

那么run方法就会被当成是普通方法被使用(即变成了以main线程,单线程实现程序)

public class ThreadTest {
    public static void main(String[]args){
    ThreadDemo1 td1=new ThreadDemo1();
    //ThreadDemo1继承了Thread,其对象可以直接调用Thread类的start方法
        td1.start();
    RunnableDemo1 rd1=new RunnableDemo1();
    //RunnableDemo1没有继承Thread类,不可直接调用start方法
    //需要先创建Thread类的对象,在启动线程
    Thread t2=new Thread(rd1);
    //构造方法的参数是调用其run方法的对象
    t2.start();


}}

启动这两个线程后,main线程就结束了(代码仍旧在跑)

线程如何结束?

等run方法执行完成

四.线程游戏实现

游戏效果

点击屏幕,创建一个小矩形,加入动态运行中

1)创建窗体(添加鼠标监听)

public class GameUI extends JFrame {
    TongueListener tl=new TongueListener();
    public GameUI(){
        setTitle("快乐小狗");
        setSize(1000,800);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
        addMouseListener(tl);
        tl.g=getGraphics();

    }
    public static void main(String[]args){
        new HappyDogv1.GameUI();
    }

2)小矩形运行的线程

public class DrawTongue extends Thread{
    int x,y,speedx;
    Graphics g;

    public DrawTongue(int x, int y, int speedx, Graphics g) {
        this.x = x;
        this.y = y;
        this.speedx = speedx;
        this.g = g;
    }

    @Override
    public void run() {

        for(;;) {
            x+=speedx;
            g.setColor(Color.red);
            g.fillRect(x, y, 15, 5);
            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            g.setColor(new Color(238,238,238));
            g.fillRect(x,y,15,5);
          //擦除矩形之前的轨迹

        }
    }
}

3)点击一个地方,多一个动态矩形(即点击一个地方启动一个线程)

监听器继承MouseAdapter就可以只重写需要需要的方法

public class TongueListener extends MouseAdapter {
    Graphics g;
    @Override
    public void mousePressed(MouseEvent e) {
        int x=e.getX();
        int y=e.getY();
        Random ran=new Random();
        int speedx= ran.nextInt(5)+1;
        DrawTongue dt=new DrawTongue(x,y,speedx,g);
        dt.start();
    }

在画动态矩形时暴露出来的问题

出现有残影,矩形重叠在一起时闪烁较为严重

happydogv1存在的问题

在消除轨迹时,采用画一整块与窗体颜色相同的白板,可以不留下残影

但是由于每加一个小矩形,就是一个新的线程,在虚拟的多线程中,短时的不断切换,使画笔议会儿红一会儿白发生错乱,且闪烁更加严重

happydog1多线程问题

这个时候减少线程数量就显得尤为重要

4)创建一个全局队列

代码实现

1>窗体类

public class GameUI extends JFrame {

    GameUI(){
    setTitle("快乐小狗");
    setSize(1000,800);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
    //搞一个队列的全局共享变量,它的作用就是用来存储要画在界面上的舌头的相关数据
    ArrayList<Tongue> al=new ArrayList<Tongue>();
    TongueListener tl=new TongueListener(getGraphics(),al);
    addMouseListener(tl);
    DrawThread dt=new DrawThread(getGraphics(),al);
    dt.start();
    }
    public static void main(String[]args){
       new GameUI();
    }
}

2>监听类

public class TongueListener extends MouseAdapter {
    private Graphics g;
    private ArrayList<Tongue> al;
    TongueListener(Graphics g,ArrayList<Tongue> al){
        this.g=g;
        this.al=al;
        //与画笔类似,窗体和监听共用一个队列
    }
    @Override
    //用click会导致有时候点不出来
    public void mousePressed(MouseEvent e) {
        int x=e.getX();
        int y=e.getY();
        Tongue t=new Tongue();
        t.x=x;
        t.y=y;
        al.add(t);

    }
}

3>线程类

public class DrawThread extends Thread{
    private Graphics g;
    private ArrayList<Tongue> al;
    int speedx;
    DrawThread(Graphics g,ArrayList<Tongue> al){
        this.g=g;
        this.al=al;

    }
    @Override
    public void run() {
        //run方法的作用,每间隔100ms,把队列中的舌头取出,在窗体上画一下
        for(;;){
            g.setColor(new Color(238,238,238));
            g.fillRect(0,0,1000,800);
            for(int i=0;i<al.size();i++){
                Tongue t= al.get(i);
                Random ran=new Random();
                speedx=ran.nextInt(10);
               t.x+=speedx;

               g.setColor(Color.red);
               g.fillRect(t.x,t.y,15,5);
            }

            try {
                Thread.sleep(30);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }


        }

    }
}

程序效果

happdogv2优化效果

五.进一步实现的效果

1.在右方加入绿色小球,相向运动

加入目标小球

2.用图片代替红色小矩形

用图片替换矩形

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值