多人运动!挑战极限!——Java模拟3人千米赛跑

题目:
利用多线程技术编写模拟三个同学的一次赛跑比赛的程序,赛道长1000米,甲同学速度为0-20米/秒之间的随机数,乙同学速度为0-18米/秒之间的随机数,丙同学的速度为0-16米/秒之间的随机数。每10秒各个同学的速度更新,并刷新显示每位同学跑过的距离,直到到达终点,给出名次及各自的完成时间。
用图形方面类似进度条画出赛道,显示三个人的比赛过程。

效果:
在这里插入图片描述
素材: (真多人运动)
在这里插入图片描述 1在这里插入图片描述2在这里插入图片描述3在这里插入图片描述4在这里插入图片描述5在这里插入图片描述6在这里插入图片描述7在这里插入图片描述8

代码说明:

暂时没追求很好的逻辑结构。

RunFrame窗口包含三个面板,和一个开始按钮。
每个面板绑定一个运动员,并实现Runnable接口,以此来重绘小人。
单击开始后,?添加?或者叫?启动?线程。
 

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.concurrent.*;

import javax.swing.*;

public class _1千米赛跑 extends JFrame {

	public static void main(String[] args) {

		RunFrame rf = new RunFrame();

	}
}

//窗口:包含三个跑步面板,一个开始按钮:单击开始后?启动线程?
class RunFrame extends JFrame {
	private int width = 1500, height = 900;

	private RunPanel rp1 = new RunPanel(0, 30, 20);
	private RunPanel rp2 = new RunPanel(0, 250, 18);
	private RunPanel rp3 = new RunPanel(0, 500, 16);

	public RunFrame() {
		super("千米赛跑");
		setSize(width, height);
		setLocation(50, 50);
		setResizable(false);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setLayout(null);

		JButton start = new JButton("开始");
		start.setBounds(20, 10, 100, 20);
		add(start);

		add(rp2);
		add(rp1);
		add(rp3);
		setVisible(true);

		start.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				start.setEnabled(false);//单击后不可再单击
				//?启动线程????:
				ExecutorService exec = Executors.newCachedThreadPool();
				exec.execute(rp1);
				exec.execute(rp2);
				exec.execute(rp3);
				exec.shutdown();
			}
		});
	}
}

//运动员类:包含最大速度、当前速度、
class Runner {

	private int maxSpeed;// 最大速度
	public int speed;// 当前速度
	public int time;// 记录每5s,即5000ms更换一次速度

	public int basex, basey;
	public double x, y;
	// 在界面中的初始位置,和当前位置。最开始都站在最左边,从上到下
	// 实际上 直跑道 从左向右跑,y是不变的

	public double distance = 1000;// 剩余距离

	private Random rd = new Random();// 随机速度

	public static Image[] image = new Image[8];
	public int id = 0;// 第几张图

	public Runner(double x, double y, int maxS) {
		this.basex = (int) x;
		this.x = x;
		this.basey = (int) y;
		this.y = y;
		maxSpeed = maxS;
		for (int i = 0; i < 8; ++i)
			image[i] = new ImageIcon("E:\\run_0" + (i + 1) + ".jpg").getImage();
	}

	public void changeSpeed() {
		speed = rd.nextInt(maxSpeed + 1);
		// 左闭右开,[0,maxSpeed+1)
	}

}

//RunPanel显示小人和路线,每个RunPanel绑定一个运动员,可以获取Runner类的相关信息
class RunPanel extends JPanel implements Runnable {
	private int width = 1500, height = 200;//面板的长宽
	private int x, y;//面板在窗口中的坐标
	private Runner runner;//绑定运动员
	
//凡是xxL:Label,凡是xxT:TextField:
	
	//速度、已跑、用时:
	private JLabel speedL = new JLabel("当前速度m/s:"), lengthL = new JLabel("已跑距离m:"), timeL = new JLabel("已用时s:");
	private JTextField speedT = new JTextField(10), lengthT = new JTextField(10), timeT = new JTextField(10);

	//加速,可选的
	private JButton accelerate = new JButton("加速");
	
//构造函数:
	public RunPanel(int x, int y, int maxS) {
		this.x = x;
		this.y = y;
		setSize(width, height);
		setLocation(x, y);
		setBackground(Color.white);//小人图片背景是白色的,所以面板设置为白色背景

		runner = new Runner(100, 50, maxS);//运动员,在该面板的起始坐标和最大速度
		
//time 是更换速度的计时,设置为一个较大的数,保证开始时即换速,换速的同时更新speedT:
//不过重点在更新speedT,因为要保证点开始按钮后,再给runner一个速度,并立即在speedT中显示这个速度
		runner.time = 9900;
	
		//不可编辑:
		speedT.setEditable(false);
		lengthT.setEditable(false);
		timeT.setEditable(false);

		//添加各组件:
		add(accelerate);
		add(speedL);
		add(speedT);
		add(lengthL);
		add(lengthT);
		add(timeL);
		add(timeT);
		//已跑距离和耗时最开始是0:
		lengthT.setText("0.00");
		timeT.setText("0.00");

		//加速并更新TextField:
		accelerate.addActionListener(new ActionListener() {

			public void actionPerformed(ActionEvent e) {

				if (!speedT.getText().equals("")) {
					runner.speed += 10;
					speedT.setText(Integer.parseInt(speedT.getText()) + 10 + "");
				}
			}
		});
	}

	//根据runner的坐标画路线和小人:
	public void paintComponent(Graphics g) {

		super.paintComponent(g);
		g.drawLine(runner.basex, runner.basey, (int) runner.x, (int) runner.y);
		g.drawImage(Runner.image[runner.id++], (int) runner.x, (int) runner.y, this);
	}

	
	public void run() {
		
		//还没跑完:
		while (runner.distance > 0) {
			try {
				TimeUnit.MILLISECONDS.sleep(100);//休眠100ms
				
				//每5s更换速度,time清零,准备下一个5s:
				runner.time += 100;
				if (runner.time >= 5000) {
					runner.changeSpeed();//换速
					runner.time = 0;//清零
					speedT.setText("" + runner.speed);//更新speedT
				}
				
				runner.distance -= runner.speed * 0.1;//剩余距离更新
				runner.x += runner.speed * 0.1;//当前x坐标更新

				//已跑和耗时更新:
				lengthT.setText(String.format("%.2f", Double.parseDouble(lengthT.getText()) + runner.speed * 0.1));
				timeT.setText(String.format("%.2f", Double.parseDouble(timeT.getText()) + 0.1));
				
				repaint();//画小人和路线
				
				//小人图片共8张,id在paint()中会+1,在这儿也可以,这一行放在paint()里应该也行:
				runner.id = runner.id % 8;

			} catch (InterruptedException e) {
				e.printStackTrace();
			}

		}
	}
}
  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值