实现的步骤简单介绍:(具体后面贴代码)
1.通过JFrame设计出展示的窗口;
2.添加一个JPanel面板到窗口中
2.1单独创建了MainPanel类通过继承JPanel,重写JPanel中paint(Graphics g)方法,操作绘图
2.2通过实现Rannable接口开启一个线程用于定时重复的绘图(定义一个产生随机数的数学工具类)
3.人群的创建
3.1人移动实际是坐标的移动,此时创建一个点的对象,定义坐标属性;
3.2 创建人的对象,添加点对象,用于锁定人的位置;
3.3多个人群的实现我们要创建一个List集合用来存储
4.给人的属性添加健康状态,定义常量表示(由于要模拟被感染的情况,所以我们要计算两个人之间的距离,此时在数学工具类添加计算距离的方法。。。直接上代码看注释吧)
package com.ty;
import javax.swing.*;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
public class Main {
public static void main(String[] args) {
personInit();
frameInit();
}
/**
* 创建人群的方法
*/
private static void personInit(){
List<Person> persons =PersonPool.getPersonPool().getPersonList();
for (int i =1;i<=Paramer.TOTAL_SIZE;i++){
Person p = new Person(MathUtil.getGaussian(60)+250,MathUtil.getGaussian(60)+250);
p.setType(Person.HEALTH100);//设置人为健康状态
p.setHealth(new Random().nextInt(20)+80);//设置人的健康值为80-100
persons.add(p);
}
//随机添加一个病原体
Random r = new Random();
Person person = persons.get(r.nextInt(Paramer.TOTAL_SIZE));
person.setType(Person.HEALTH25);
person.setVirsu(Virsu.getVirsu());
//将病原对象放到病原集合中
PersonPool.getPersonPool().getVirusList().add(person);
//初始化社区人员,保存10个,使用set集合防止挑选的人重复
Set<Person> tempSet = new HashSet<>();
//先执行后判断雇用do-while循环
do{
int p = r.nextInt(Paramer.TOTAL_SIZE);//所有人员中随机抽选
Person person1 = persons.get(p);//集合中挑出
person1.setObserver(true);//设置为社区人员
tempSet.add(person1);//去重校验
}while (tempSet.size()<10);
//加入社区人池集合中
PersonPool.getPersonPool().getObserverList().addAll(tempSet);
}
/**
* 初始展示窗口的方法
*/
private static void frameInit() {
JFrame frame = new JFrame();
//设置窗体大小
frame.setSize(Paramer.WIN_WIDTH,Paramer.WIN_HIGHT);
//设置标题
frame.setTitle("疫情仿真程序");
//添加面板用于绘图
MainPanel panel = new MainPanel();
frame.add(panel);
//设置窗口可见
frame.setVisible(true);
//设置窗口退出方式
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//启动一个线程用于定时重复绘图
Thread t = new Thread(panel);
t.start();
}
}
package com.ty;
import javax.swing.*;
import java.awt.*;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;
public class MainPanel extends JPanel implements Runnable {
//调用人群集合显示在面板
private List<Person> persons = PersonPool.getPersonPool().getPersonList();
private List<Person> observers = PersonPool.getPersonPool().getObserverList();
//重写画图方法
@Override
public void paint(Graphics g) {
super.paint(g);
//设置背景色
this.setBackground(new Color(0x444444));
Color[] colors = {Color.white,Color.green,Color.yellow,Color.red,null,Color.black};
for(Person person:persons) {
//判断如果是隔离状态的人不在移动
if(person.getType()==Person.ISOLATION){
continue;
}
//调用人移动的方法
person.move();
//调用健康结算的方法
person.doHealth();
//画出人在的位置
// 程序优化,通过数组来代替
// if(person.getType()==Person.HEALTH100){
// g.setColor(Color.white);
// }else if(person.getType()==Person.HEALTH25){
// g.setColor(Color.red);
// }
g.setColor(colors[person.getType()]);
g.fillOval(person.getPoint().getX(), person.getPoint().getY(), 3, 3);
}
//打印信息
g.setColor(Color.white);
g.drawString("总人数:"+Paramer.TOTAL_SIZE,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y);
g.setColor(Color.white);
g.drawString("健康人数:"+(Paramer.TOTAL_SIZE-1-Paramer.HEALTH50_COUNT-Paramer.HEALTH90_COUNT),Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+20);
g.setColor(Color.green);
g.drawString("疑似人数:"+(Paramer.HEALTH50_COUNT+Paramer.HEALTH90_COUNT-Paramer.dealth_Count),Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+40);
g.setColor(Color.red);
g.drawString("发病人数:"+1,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+60);
g.setColor(Color.red);
g.drawString("死亡人数:"+Paramer.dealth_Count,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+80);
g.setColor(Color.white);
g.drawString("世界时间:"+Paramer.time,Paramer.MSG_BASE_X,Paramer.MSG_BASE_Y+100);
//发布通告在一定的世界时间
if(Paramer.time>40) {
Publish.publish(40, "通告:非常时期,大家保持警惕,继续居家隔离,减少外出活动!", g);
if(Paramer.time==60){
Paramer.move_Wish=0.6f;
}
}
//发布疫情通告在世界时间60
if(Paramer.time>60) {
Publish.publish2(60, "通告:火神山医院建成并投入使用!", g);
}
//调用画医院方法
if(Paramer.time>70) {
Hospital.getHospital().paintHospital(g);
}
//画出社区人员的监测范围
if(Paramer.time>80) {
g.setColor(new Color(0x79AEAC9D, true));
for (Person p : observers) {
//如果社区人员被隔离,不在执行画图
if(p.getType()==Person.ISOLATION){
continue;
}
int x = p.getPoint().getX() - 25;
int y = p.getPoint().getY() - 25;
g.fillOval(x, y, 50, 50);
}
}
}
//定义一个执行任务的内部类
class MyTask extends TimerTask{
@Override
public void run() {
//绘图操作
repaint();
//显示的世界世界++
Paramer.time++;
}
};
@Override
public void run() {
//此线程用于定时绘图
Timer timer = new Timer();
timer.schedule(new MyTask(),0,100);
}
}
package com.ty;
public class Point {
private int x;
private int y;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public Point() {
}
}
package com.ty;
import java.util.Random;
public class Person {
//定义常量代表人健康的状态
public static final int HEALTH100=0; //健康
public static final int HEALTH90=1; //接触未感染,疑似
public static final int HEALTH50=2; //接触感染,疑似
public static final int HEALTH25=3; //病源
public static final int ISOLATION=4; //被隔离
public static final int DEATH=5; //死亡
//人的状态属性
private int type;
//人的健康值100作为上限
private int health;
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
//人的坐标点
private Point point;
//病毒对象
private Virsu virsu;
//社区人员标记
private boolean observer;
public boolean isObserver() {
return observer;
}
public void setObserver(boolean observer) {
this.observer = observer;
}
public Virsu getVirsu() {
return virsu;
}
public void setVirsu(Virsu virsu) {
this.virsu = virsu;
}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public Person(int x,int y) {
this.point = new Point(x,y);
}
public Person() {
}
//定义人移动行为
public void move(){
//社区人员的巡检操作
if(this.isObserver()&&Paramer.time>80){
//检验辖区范围内每一个人
for(Person p : PersonPool.getPersonPool().getPersonList()){
//判断距离
int x = this.getPoint().getX();
int y = this.getPoint().getY();
int x1 = p.getPoint().getX();
int y1 = p.getPoint().getY();
if(Math.abs(x-x1)<25&&Math.abs(y-y1)<25){
//判断状态
if(p.getType()==Person.HEALTH50||p.getType()==Person.HEALTH90){
//送医院就诊
Hospital.getHospital().receieve(p,this);
return;//发现对象,停止监测
}
}
}
}
//判断如果死亡的人不在移动
if(this.getType()==Person.DEATH){
return;
}
//移动前根据意愿判断行为
//社区人员不受移动意愿的控制
if(Math.random()>Paramer.move_Wish && !this.isObserver()){
return;
}
//如果是社区人员,移动范围扩大
if(this.isObserver()){
int x = this.getPoint().getX() + MathUtil.getGaussian(4);
int y = this.getPoint().getY() + MathUtil.getGaussian(4);
}
int x = this.getPoint().getX() + MathUtil.getGaussian(2);
int y = this.getPoint().getY() + MathUtil.getGaussian(2);
//控制人活动的范围
x=x>Paramer.AREA_WIDTH?Paramer.AREA_WIDTH:x;
x=x<0?0:x;
y=y>Paramer.AREA_HIGHT?Paramer.AREA_HIGHT:y;
y=y<0?0:y;
this.getPoint().setX(x);
this.getPoint().setY(y);
//2.1如果距离在传染范围则被传染,停止比对并加入病原集合
//0.排除已经被感染人群的比对
if(getType()>1){
return;
}
//1.使用每一个人与带病的人进行比对
for(Person p :PersonPool.getPersonPool().getVirusList()){
//2.计算两者之间的距离
double distance = MathUtil.getDistance(this,p);
if(distance>5){
//放行检测下一个
continue;
}
//添加概率判断暂且定位40%的命中率
if(Math.random()<0.4f){
//接触未感染,再次被检测感染时要从源数据减去
if(this.getType()==Person.HEALTH90){
Paramer.HEALTH90_COUNT--;
}
//2.1范围内被感染修改状态
this.setType(Person.HEALTH50);
//病毒加载到病人身上
this.setVirsu(Virsu.getVirsu());
//2.2加入病原人群
PersonPool.getPersonPool().getVirusList().add(this);
//2.3计算传染的数量
Paramer.HEALTH50_COUNT++;
//2.4已经传染无需再比对,终止循环
break;
}else{
//接触,未感染,终止
if(this.getType()==Person.HEALTH90){
continue;
}
//计算接触未感染数量
Paramer.HEALTH90_COUNT++;
this.setType(Person.HEALTH90);
}
}
}
Random r = new Random();
//健康结算
public void doHealth(){
//无病毒的人不结算
if(this.getVirsu()==null) {
return;
}
//已经死亡的人不结算
if(this.getType()==Person.DEATH){
return;
}
//获取健康值-病毒的伤害保存到人健康属性中
this.setHealth( this.getHealth()-this.getVirsu().getDamage());
//免疫力的设定
this.setHealth( this.getHealth()+r.nextInt(7));
//判断健康值不能超过100
if (this.getHealth()>=100){
this.setHealth(100);//健康值设为100
this.setVirsu(null);//去掉病毒
//数据统计
if(this.getType()==Person.HEALTH50){
Paramer.HEALTH50_COUNT--;
}
//状态变为健康的状态
this.setType(Person.HEALTH100);
//从疑似病毒集合移除
PersonPool.getPersonPool().getVirusList().remove(this);
}
//判断如果健康值低于0需要去除病毒并修改人的状态
if(this.getHealth()<=0){
this.setVirsu(null);
this.setType(Person.DEATH);
//如果是社区人员,要从社区集合移除
if(this.isObserver()){
PersonPool.getPersonPool().getObserverList().remove(this);
}
//将死亡的人从病毒集合中移除
PersonPool.getPersonPool().getVirusList().remove(this);
//死亡数量要++
Paramer.dealth_Count++;
}
}
}
package com.ty;
import java.util.ArrayList;
import java.util.List;
public class PersonPool {
private static PersonPool personPool = new PersonPool();
private PersonPool(){}
public static PersonPool getPersonPool(){
return personPool;
}
//健康人的集合
private List<Person> personList = new ArrayList<>();
//病源集合
private List<Person> virusList = new ArrayList<>();
//社区人员的集合
private List<Person> observerList = new ArrayList<>();
public List<Person> getObserverList() {
return observerList;
}
public void setObserverList(List<Person> observerList) {
this.observerList = observerList;
}
public List<Person> getPersonList() {
return personList;
}
public void setPersonList(List<Person> personList) {
this.personList = personList;
}
public List<Person> getVirusList() {
return virusList;
}
public void setVirusList(List<Person> virusList) {
this.virusList = virusList;
}
}
package com.ty;
import java.util.Random;
public class MathUtil {
private static Random r = new Random();
//通过高斯获取一个随机数
public static int getGaussian(int range){
return (int)(r.nextGaussian()*range);
}
//计算两个人距离的方法
public static double getDistance(Person p1,Person p2){
Point point1 = p1.getPoint();
Point point2 = p2.getPoint();
int x = point1.getX()-point2.getX();
int y = point1.getY()-point2.getY();
return Math.sqrt(x*x+y*y);
}
}
package com.ty;
import java.awt.*;
public class Publish {
public static void publish(int time,String msg, Graphics g){
//公告栏的显示
msg = " "+msg+" ";
if((Paramer.time-time)/Paramer.MSG_SHOW_SPEED+20<msg.length()) {
String showMsg = msg.substring((Paramer.time-time) / Paramer.MSG_SHOW_SPEED, (Paramer.time-time) / Paramer.MSG_SHOW_SPEED + 20);
g.drawString(showMsg , Paramer.MSG_BASE_X, Paramer.MSG_BASE_Y + 120);
}
}
public static void publish2(int time, String msg, Graphics g) {
//公告栏的显示
msg = " "+msg+" ";
if((Paramer.time-time)/Paramer.MSG_SHOW_SPEED+20<msg.length()) {
String showMsg = msg.substring((Paramer.time-time) / Paramer.MSG_SHOW_SPEED, (Paramer.time-time) / Paramer.MSG_SHOW_SPEED + 20);
g.drawString(showMsg , Paramer.MSG_BASE_X, Paramer.MSG_BASE_Y + 140);
}
}
}
package com.ty;
import java.util.Random;
public class Virsu {
private static Virsu virsu = new Virsu();
private Virsu(){}
public static Virsu getVirsu(){
return virsu;
}
private int damage;
Random r = new Random();
//随机产生15-30的杀伤力
public int getDamage() {
return r.nextInt(3)+2;
}
public void setDamage(int damage) {
this.damage = damage;
}
}
package com.ty;
import java.awt.*;
public class Bed {
private int x;
private int y;
private Person person;
private Color bedColor = Color.GREEN;
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
public Person getPerson() {
return person;
}
public void setPerson(Person person) {
this.person = person;
if(person==null){
this.bedColor = Color.green;
return;
}
if(person.getType()==Person.DEATH){
this.bedColor = Color.orange;
return;
}
if(person!=null && person.isObserver()){
this.bedColor = Color.blue;
return;
}
this.bedColor = Color.red;
}
public Color getBedColor() {
return bedColor;
}
public void setBedColor(Color bedColor) {
this.bedColor = bedColor;
}
}
package com.ty;
import java.awt.*;
import java.util.Random;
public class Hospital {
private static Hospital hospital = new Hospital();
private Hospital(){}
public static Hospital getHospital(){
return hospital;
}
//定义一个二维数组,模拟床位
Bed[][] beds = new Bed[43][32];
//给床设置坐标
{
for(int i=0;i<beds.length;i++){
for(int j=0;j<beds[i].length;j++){
beds[i][j] = new Bed();
beds[i][j].setX(i);
beds[i][j].setY(j);
}
}
}
//绘制医院的方法
public void paintHospital(Graphics g) {
g.setColor(Color.green);
g.drawString("雷火医院",580,175);
g.drawRect(520,180,160,260);
for(int i=0;i<beds.length;i++){
for(int j=0;j<beds[i].length;j++){
/* g.drawLine(522+j*5,183+i*6,524+j*5,183+i*6);
g.drawLine(522+j*5,184+i*6,524+j*5,184+i*6);*/
g.setColor(beds[i][j].getBedColor());
g.fillRect(522+j*5,183+i*6,3,2);
}
}
}
//接收病人的方法
public void receieve(Person target,Person src){
//疑似病例判断,若感染,治疗
if(isHaveVirsu(target)){
treat(target);
}
//社区人员判断,若感染,治疗
if(isHaveVirsu(src)){
treat(src);
}else {
//回去继续工作
}
}
//治疗的方法
private void treat(Person p ){
//分配病床
out :
for(int i=0;i<beds.length;i++){
for(int j=0;j<beds[i].length;j++){
if(beds[i][j].getPerson()==null){
beds[i][j].setPerson(p);
//病人的状态修改为隔离状态
p.setType(Person.ISOLATION);
break out;//停止继续寻找
}
}
}
}
//治疗情况的计算方法
Random r = new Random();
//健康结算
public void doHealth(){
for(int i=0;i<beds.length;i++){
for(int j=0;j<beds[i].length;j++){
Bed b = beds[i][j];
Person p = b.getPerson();
//判断床位是否有病人,无直接下一个
if(p==null){
continue;
}
//如果死病床的也不结算
if(p.getType()==Person.DEATH){
continue;
}
//健康值的计算
int health = p.getHealth();
//病毒的杀伤力,判断排除掉疑似为感染病范
if(p.getVirsu()!=null){
health -= p.getVirsu().getDamage();
}
//免疫力
health += r.nextInt(6);
//医院的治疗
health += r.nextInt(3)-30;
p.setHealth(health);
//判断健康值不能超过100
if (p.getHealth()>=100){
p.setHealth(100);//健康值设为100
p.setVirsu(null);//去掉病毒
//状态变为健康的状态
p.setType(Person.HEALTH100);
//从疑似病毒集合移除
PersonPool.getPersonPool().getVirusList().remove(p);
//出院的腾出床位
b.setPerson(null);
}
//判断如果健康值低于0需要去除病毒并修改人的状态
if(p.getHealth()<=0){
p.setVirsu(null);
p.setType(Person.DEATH);
//如果是社区人员,要从社区集合移除
if(p.isObserver()){
PersonPool.getPersonPool().getObserverList().remove(p);
}
//将死亡的人从病毒集合中移除
PersonPool.getPersonPool().getVirusList().remove(p);
//死亡数量要++
Paramer.dealth_Count++;
b.setPerson(p);
}
}
}
}
//判断状态是否感染的方法
private boolean isHaveVirsu(Person p ){
return p.getType()==Person.HEALTH50||p.getType()==Person.HEALTH25;
}
}
package com.ty;
public class Paramer {
//疑似不带病人的数量
public static int HEALTH90_COUNT = 0;
//疑似带病人的数量
public static int HEALTH50_COUNT = 0;
//已经死亡人的数量
public static int dealth_Count = 0;
//定义一个世界时间
public static int time =0;
//移动意愿的定义
public static float move_Wish = 0.9f;
//定义消息显示的基本坐标
public static final int MSG_BASE_X=520;
public static final int MSG_BASE_Y=20;
//定义消息滚动速度(1最快)
public static final int MSG_SHOW_SPEED=5;
//设置窗口的宽和高
public static final int WIN_WIDTH =700;
public static final int WIN_HIGHT =500;
//设置总人数
public static final int TOTAL_SIZE =2000;
//设置区域的宽高
public static final int AREA_WIDTH=500;
public static final int AREA_HIGHT=500;
}