⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 billiards.java

📁 精通Java网络编程代码全部
💻 JAVA
字号:
//Billiards.java
import java.awt.*;
import java.applet.*;

//globals类设置了全局常量
class globals  
{
	public static int DrawScale = 10;
	//设置最小速度
	public static double MinVelocity = 0;
	//设置速度的范围
	public static double VelocityRange = 5;
	//最小尺寸
	public static double MinSize = 2;
	public static double SizeRange = 2;
	//球的数目
	public static final int BallCount = 10;
	//窗口的宽度和长度
	public static final int WindowWidth = 500; //applet和表格的大小
	public static final int WindowHeight = 500;
	public static double MaxV()
	{
		return MinVelocity + VelocityRange;
	}
}

public class Billiards extends Applet implements Runnable
{	
//用来在循环中设置移动球体的时间长度
	Thread BallTimer;	
	//采用两块缓冲区互换的方法
    Image offImage;
    Graphics offGraphics;
	
	//初始化BilliardTable并且采用全局常量的设置
	BilliardTable T = new BilliardTable(0,0,globals.WindowWidth / globals.DrawScale, globals.WindowHeight / globals.DrawScale);
	
	//初始化球的个数
	Ball B[] = new Ball[globals.BallCount];
	
	//设置颜色
	Color TableColor = new Color(0,0,0);

	//当时间更新时使用
	public void run()	{	
		int i = 0; //For loop counters
		int x = 0;
		int y = 0;
		
		double pX[] = new double[globals.BallCount];
		double pY[] = new double[globals.BallCount];
		
		System.out.println("Run");
		Graphics g = getGraphics();
		
		while (true)
		{
			offGraphics.setColor(TableColor);
			offGraphics.fillRect((int)T.Left * globals.DrawScale, (int)T.Top * globals.DrawScale, (int)T.Width * globals.DrawScale, (int)T.Height * globals.DrawScale);
			offGraphics.setColor(Color.black);
			
			for(i = 0; i < globals.BallCount; i++)
			{
				pX[i] = B[i].Px;
				pY[i] = B[i].Py;

//移动小球一点
				B[i].Move(.05);			}
			
			for(i = 0; i < globals.BallCount; i++)
			{

//当小球碰壁后的处理
				CheckWallBounce(B[i]);			}
			
			if (globals.BallCount > 1)
			{
				for(x = 0; x < globals.BallCount; x++)
				{	//检测每个球之间的情况
					for(y = x + 1; y < globals.BallCount; y++)					{
						if (Separation(B[x],B[y]) <= RadSum(B[x],B[y]))						{
							Collide(B[x],B[y]); //COLLISON!!!!
						}
					}
				}
			}
			
			for(i = 0; i < globals.BallCount; i++)
			{

//绘制每一个小球
				B[i].Draw(offGraphics);			}

			//绘制边界
			T.DrawBorder(offGraphics); 

//暂停一段时间
			try { Thread.sleep(20); }
			catch (InterruptedException e) { }
			
			g.setColor(Color.white);
			g.drawImage(offImage, 0, 0, null);
		}
	}

//返回一个随机颜色
	public Color RandColor()
	{
		int r,g,b;
		r = (int)(Math.random() * 256);
		g = (int)(Math.random() * 256);
		b = (int)(Math.random() * 256);
		return new Color(r,g,b);
	}
	public void init() //开启线程并初始化
	{	
		//设置applet的大小
		setSize(globals.WindowWidth, globals.WindowHeight);
		
		offImage = createImage((int)(T.Width + T.Left) * globals.DrawScale,(int) (T.Height + T.Top) * globals.DrawScale);
		offGraphics = offImage.getGraphics();
		
		double tmpRad; //存储临时半径
		double tmpX, tmpY; //存储随机的位置
		boolean overlap; //被用在循环中用来测试碰撞
		int x; 
		
		double dX, dY, Rads; //计算球体之间的距离
		
		for(int i = 0; i < globals.BallCount; i++)
		{ //初始化各个小球并给出随机位置
			
			tmpRad = Math.random() * globals.SizeRange + globals.MinSize;
			
			do
			{
				overlap = false;
				
				//给出随机的位置
				tmpX = Math.random() * T.Width + T.Left;
				tmpY = Math.random() * T.Height + T.Top;
				
				for(x = 0; x < i; x++) //测试每一个球是否都获得了合适的位置
				{
					dX = B[x].Px - tmpX;
					dY = B[x].Py - tmpY;
					Rads = B[x].Radius + tmpRad;
					if (Math.sqrt(dX * dX + dY * dY) < Rads) //是否它们之间的距离已经足够
						overlap = true; //它们确实重叠了
				}
			} while (overlap);
			
			B[i] = new Ball(tmpX, tmpY, tmpRad);
			B[i].Vx = (Math.random() * globals.VelocityRange + globals.MinVelocity) * PosNegRand();
			B[i].Vy = (Math.random() * globals.VelocityRange + globals.MinVelocity) * PosNegRand();
			B[i].BallColor = RandColor();
		}
		repaint(); //确定已经得到了绘制
		BallTimer = new Thread(this); //设置一个新的线程
		BallTimer.start(); //启动了run方法
	}
	public int PosNegRand()
	{
		double a = Math.random() * 2;
		if (a >= 1)
			a = 1;
		if (a < 1)
			a = -1;
		
		return (int)a;
	}
	public void CheckWallBounce(Ball B) 
	{
		double Xleft = B.Px;
		double Ytop = B.Py;
		double Ybottom = B.Py + 2 * B.Radius; //记录下左上角的位置
		double Xright = B.Px + 2 * B.Radius;  //记录了右下角的位置
		
		if (Xleft < T.minX())
		{
			B.Px = T.minX();
			B.WallBounceX();
		} 
		
		if (Ytop < T.minY())
		{
			B.Py = T.minY();
			B.WallBounceY();
		}
		
		if (Xright > T.maxX())
		{
			B.Px = T.maxX() - 2 * B.Radius;
			B.WallBounceX();
		} 
		
		if (Ybottom > T.maxY())
		{
			B.Py = T.maxY() - 2 * B.Radius;
			B.WallBounceY();
		}
	}
	public void PrintData()//为了调试
	{
		double TotalM = 0.0;
		double TotalK = 0.0;
		
		for(int i = 0; i < globals.BallCount; i++)
		{
			System.out.println("Ball " + i + ": ");
			B[i].PrintData();
			System.out.println();
			TotalM += B[i].Momentum();
			TotalK += B[i].Kinetic();
		}
		
		System.out.println("Total Momentum:  " + TotalM);
		System.out.println("Total Kinetic:  " + TotalK);
		System.out.println();
	}
	public void paint(Graphics g) //重绘整张表
	{
		T.Draw(g, TableColor);
	}
	public double Separation(Ball B1, Ball B2) //给出两个球之间的距离
	{ 
		double X1, X2, Y1, Y2;
		X1 = B1.Px + B1.Radius;
		X2 = B2.Px + B2.Radius;
		Y1 = B1.Py + B1.Radius;
		Y2 = B2.Py + B2.Radius;
		
		return Math.sqrt((X2 - X1) * (X2 - X1) + (Y2 - Y1) * (Y2 - Y1));
	}
	public double RadSum(Ball B1, Ball B2) //计算两个球之间的半径和
	{
		return (B1.Radius + B2.Radius);
	}
	public void Collide(Ball B1, Ball B2)
	{
		
	/*以下代码绘制了发生碰撞的时候产生的效果*/
		
		double Dx1, Dx2, Dy1, Dy2; //碰撞的距离
		double X1, X2, Y1, Y2; //中心点和碰撞点的距离
		double DxR, DyR; //实际距离 (碰撞覆盖)
		double Dx, Dy; //假设的距离 (假设没有重叠)
		double Vp1, Vp2, Vs1, Vs2; //速度设置
		double newVs1, newVs2; //在计算过程中记录相应的速度
		double distance; //球中心之间的真实距离
		X1 = B1.Px + B1.Radius;
		X2 = B2.Px + B2.Radius;
		Y1 = B1.Py + B1.Radius;
		Y2 = B2.Py + B2.Radius;
		DxR = (X2 - X1); 
		DyR = (Y2 - Y1);
		
		distance = Math.sqrt(DxR * DxR + DyR * DyR); 
		Dx = RadSum(B1,B2) * DxR / distance; //为了获得理想的碰撞所需要的数据
		Dy = RadSum(B1,B2) * DyR / distance;
		
		
		if (B1.Mass < B2.Mass)
		{
			X1 = (X1 - (Dx - DxR));
			Y1 = (Y1 - (Dy - DyR));
			
			B1.Px = X1 - B1.Radius;
			B1.Py = Y1 - B1.Radius;
		}
		else
		{
			X2 = (X2 + (Dx - DxR));
			Y2 = (Y2 + (Dy - DyR));
			
			B2.Px = X2 - B2.Radius;
			B2.Py = Y2 - B2.Radius;
		}		
		
		//找到x和y各自到球中心节点的距离
		Dx1 = (B1.Radius / RadSum(B1,B2)) * (X2 - X1);
		Dx2 = (B2.Radius / RadSum(B1,B2)) * (X2 - X1);
		
		Dy1 = (B1.Radius / RadSum(B1,B2)) * (Y2 - Y1);
		Dy2 = (B2.Radius / RadSum(B1,B2)) * (Y2 - Y1);
		
		Vs1 = StraightVelocity(B1.Vx, B1.Vy, Dx1, Dy1, B1.Radius);
		Vp1 = PerpendicularVelocity(B1.Vx, B1.Vy, Dx1, Dy1, B1.Radius);
		
		Vs2 = StraightVelocity(B2.Vx, B2.Vy, Dx2, Dy2, B2.Radius);
		Vp2 = PerpendicularVelocity(B2.Vx, B2.Vy, Dx2, Dy2, B2.Radius);
		
		newVs1 = CollisionVelocity(Vs1, Vs2, B1.Mass, B2.Mass);
		newVs2 = CollisionVelocity(Vs2, Vs1, B2.Mass, B1.Mass);
		
		B1.Vx = XVelocity(newVs1, Vp1, Dx1, Dy1, B1.Radius);
		B1.Vy = YVelocity(newVs1, Vp1, Dx1, Dy1, B1.Radius);
		
		B2.Vx = XVelocity(newVs2, Vp2, Dx2, Dy2, B2.Radius);
		B2.Vy = YVelocity(newVs2, Vp2, Dx2, Dy2, B2.Radius);
	}
	public double StraightVelocity(double Vx, double Vy, double Dx, double Dy, double R)
	{
		return Vx * Dx / R + Vy * Dy / R;
	} //速度值
	public double PerpendicularVelocity(double Vx, double Vy, double Dx, double Dy, double R)
	{
		return Vy * Dx / R - Vx * Dy / R;
	}
	public double XVelocity(double Vs, double Vp, double Dx, double Dy, double R)
	{
		return Vs * Dx / R - Vp * Dy / R;
	} //x 从S和P的速度值
	public double YVelocity(double Vs, double Vp, double Dx, double Dy, double R)
	{
		return Vs * Dy / R + Vp * Dx / R;
	} //y 来自S和P的速度值
	public double CollisionVelocity(double V1, double V2, double m1, double m2) //碰撞之后返回速度值
	{
		return V1 * (m1-m2) / (m1+m2) + V2 * (2 * m2) / (m1 + m2);
	}
}

class Ball
{
	double Vx = 0; //x方向的速度
	double Vy = 0; //y方向速度
	double Px = 0; //x轴的位置
	double Py = 0; //y轴的位置
	
	double Density = 1; //球的密度
	double Radius; //球的半径
	double Mass;  
	
	Color BallColor = new Color(0,0,0); //球体初始化为白色
	public Ball(double x, double y, double radius) //构造函数
	{
		double Volume = 4.0/3.0 * Math.PI * radius * radius * radius; // v = 4/3 pi r^3
		Px = x;
		Py = y;
		Radius = radius;
		Mass = Density * Volume;
	}
	public void PrintData()//输出全部球的信息(仅用于测试)
	{
		System.out.println("Px:" + Px);
		System.out.println("Py:" + Py);
		System.out.println("Mass:" + Mass);
		System.out.println("Vx:  " + Vx);
		System.out.println("Vy:  " + Vy);
		System.out.println("V:   " + Velocity());
		System.out.println("Ek:  " + Kinetic());
		System.out.println("Mom: " + Momentum());
	}
	public void addVelocity(double x, double y)//增加球的速度
	{
		Vx+=x;
		Vy+=y;
	}
	public double Velocity() //返回球的当前速度
	{
		return Math.sqrt(Vx * Vx + Vy * Vy);
	}
	public double Momentum() 
	{ //p = mv
		return Mass * Vx + Mass * Vy;
	}
	public double Kinetic() //returns total kinetic energy of ball
	{// ke = 1/2 m v^2
		return .5 * Mass * Velocity() * Velocity();
	}
	public void WallBounceX() 
	{
		Vx = -Vx; //ball switches x velocity
	}
	public void WallBounceY() //球移动到了边界上
	{
		Vy = -Vy; //ball switches y velocity
	}
	public void Move(double t) //将球移动一圈
	{
		Px = Px + Vx * t;
		Py = Py + Vy * t;
	}
	public void Draw(Graphics g)
	{
		int top, left, size;
		left = (int)(Px * globals.DrawScale);
		top = (int)(Py * globals.DrawScale);
		size = (int)(2 * Radius * globals.DrawScale);
		
		g.setColor(BallColor); //绘制球的内部
		g.fillOval(left, top, size, size);
		//g.setColor(Color.black); //绘制小球的外边框
		//g.drawOval(left, top, size, size);
	}
	//绘制小球所在的当前位置的颜色
	public void Clear(Graphics g, Color TableColor)
	{
		int top, left, size;
		left = (int)(Px * globals.DrawScale);
		top = (int)(Py * globals.DrawScale);
		size = (int)(2 * Radius * globals.DrawScale);
		
		//覆盖了老的位置
		g.setColor(TableColor); 
		//确保所有的线条都覆盖到了
		g.fillOval(left-1, top-1, size+2, size+2);
	}
}

class BilliardTable
{
	double Left, Top, Width, Height;
	
	public BilliardTable(double L, double T, double W, double H)
	{
		Left = L;
		Top = T;
		Width = W;
		Height = H;
	}
	//球的最小的X值
	public double minX()
	{
		return Left;
	}
	//对于一个球来说最小的值
	public double minY() 
	{
		return Top;
	}

	public double maxX()
	{
		return Left + Width;
	}
	public double maxY()
	{
		return Top + Height;
	}

//绘制图表
	public void Draw(Graphics g, Color TableColor)
	{

//绘制所有的颜色
		g.setColor(TableColor);
		g.fillRect((int)(Left * globals.DrawScale), (int)(Top * globals.DrawScale), (int)(Width * globals.DrawScale), (int)(Height * globals.DrawScale));
		
		DrawBorder(g);
	}
	//绘制边界
	public void DrawBorder(Graphics g)
	{
		//采用了白颜色,更改方便
		g.setColor(new Color(255,255,255)); 
		g.drawRect((int)(Left * globals.DrawScale), (int)(Top * globals.DrawScale), (int)(Width * globals.DrawScale), (int)(Height * globals.DrawScale));
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -