1. 程式人生 > >Java版小球碰撞

Java版小球碰撞

import java.awt.*;
import java.awt.geom.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.plaf.ComponentUI;
import java.util.*;

/**


 */
@SuppressWarnings("serial")
public class BallPanel extends JPanel 
{
	private ArrayList<Ball> balls = new ArrayList<Ball>();	//小球列表
	private BallComponent component = new BallComponent();	//小球畫板
	private JButton btnAdd = new JButton("Add");	//Add按鈕
	private JButton btnStopAndContinue = new JButton("Stop");	//Stop按鈕
	private JButton btnClear = new JButton("Clear");	//Clear按鈕
	private JComboBox colorCombo = new JComboBox();	//顏色選擇框
	private JComboBox speedCombo = new JComboBox();	//速度選擇框
	private JComboBox placeCombo = new JComboBox();	//小球出現方位
	private BallThread thread = new BallThread();	//小球運動執行緒
	private int delay = 5;	//小球運動的延緩時間
	
	/**
	 * 初始化小球面板
	 */
	public BallPanel()
	{
		setLayout(new BorderLayout());	//設定為BorderLayout的佈局
		add(component, BorderLayout.CENTER);	//將小球畫板加到面板中央
		component.setOpaque(true);				//設定畫板不透明,以便能新增背景色
		component.setBackground(Color.BLACK);	//設定背景色
		
		JPanel panel = new JPanel();	//建立用來放各種按鈕的面板
		panel.add(btnAdd);				//將Add按鈕放入該面板
		panel.add(btnStopAndContinue);	//將Stop/Continue按鈕放入該面板
		panel.add(btnClear);			//將Clear按鈕放入該面板
		panel.setBackground(Color.LIGHT_GRAY);
		add(panel, BorderLayout.SOUTH);	//將按鈕面板加到主面板南部
		
		panel = new JPanel(new GridLayout(0, 1));	//建立用來放各種選擇框的面板
		panel.add(new JLabel(" Color: "));	//新增標籤Color:
		panel.add(colorCombo);				//新增顏色選擇框
		panel.add(new JLabel(" Speed: "));	//新增標籤Speed:
		panel.add(speedCombo);				//新增速度選擇框
		panel.add(new JLabel(" From: "));	//新增標籤From:
		panel.add(placeCombo);				//新增方位選擇框
		panel.setBackground(Color.LIGHT_GRAY);
		add(panel, BorderLayout.EAST);		//將選擇框面板加到主面板東部
		
		//以下幾句話用來向顏色選擇框加入各種顏色選項
		colorCombo.addItem("red");
		colorCombo.addItem("orange");
		colorCombo.addItem("yellow");
		colorCombo.addItem("green");
		colorCombo.addItem("cyan");
		colorCombo.addItem("blue");
		colorCombo.addItem("magenta");
		
		//以下幾句話用來向速度選擇框加入各種速度選項
		speedCombo.addItem("slow");
		speedCombo.addItem("fast");
		//速度選擇框加入監聽器,及時改變小球的速度
		speedCombo.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent event)
				{
					String speed = (String)speedCombo.getSelectedItem();
					if (speed.equals("slow"))
					{
						delay = 5;
					}
					else
					{
						delay = 1;
					}
				}
			});
		
		//以下幾句話用來向方位選擇框加入各種方位選項
		placeCombo.addItem("Left-Top");
		placeCombo.addItem("Left-Bottom");
		placeCombo.addItem("Right-Top");
		placeCombo.addItem("Right-Bottom");
		
		//Add按鈕加入監聽器,當按下按鈕時新增小球
		btnAdd.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent event)
				{
					component.addBall();
				}
			});
		//Stop/Continue按鈕加入監聽器,當按下按鈕時暫停/繼續動畫
		btnStopAndContinue.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent event)
				{
					if (btnStopAndContinue.getText().equals("Stop"))	//如果當前按鈕的值為Stop
					{
						thread.setStop(true);	//將stop標誌置為true
						btnStopAndContinue.setText("Continue");	//將按鈕的標籤變為Continue
						btnAdd.setEnabled(false);	//Add按鈕不可用
					}
					else
					{
						thread.setStop(false);	//將stop標誌置為false
						btnStopAndContinue.setText("Stop");	//將按鈕的標籤變為Stop
						btnAdd.setEnabled(true);	//Add按鈕可用
					}
				}
			});
		//Clear按鈕加入監聽器,當按下按鈕時清空畫板
		btnClear.addActionListener(new ActionListener()
			{
				public void actionPerformed(ActionEvent event)
				{
					balls = new ArrayList<Ball>();	//將球的列表清空
					component.repaint();			//重畫畫板
				}
			});
		
		thread.start();	//畫畫板的執行緒開始
	}
	
	/**
	 * 主函式,主要用於測試
	 * @param args
	 */
	public static void main(String[] args)
	{
		EventQueue.invokeLater(new Runnable()
			{
				public void run()
				{
					JFrame frame = new JFrame("Hit Balls");	//設定測試框架的標題
					frame.add(new BallPanel());		//將小球碰撞動畫面板放上去
					frame.setSize(400, 300);		//設定框架大小
					frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);	//設定框架的預設關閉方式
					frame.setLocationByPlatform(true);	//將框架的定位交給系統實現
					frame.setVisible(true);			//設定框架可見
				}
			});
	}
	
	/**
	 * 小球運動執行緒
	 * @author zjf
	 */
	private class BallThread extends Thread
	{
		private boolean isStop = false;	//停止標記
		
		/**
		 * 執行緒體
		 */
		public void run()
		{
			while (true)	//讓它一直執行
			{
				if (!isStop)	//當沒有停止的時候
				{
					for (int i = 0; i < balls.size(); i++)
					{
						balls.get(i).move(component.getBounds());	//每個小球都移動一遍
					}
					component.repaint();	//重畫畫板
				}
				try {
					Thread.sleep(delay);	//執行緒延緩delay毫秒
				} catch (InterruptedException e) {	//捕獲異常
					e.printStackTrace();	//處理異常
				}
			}
		}
		
		/**
		 * 設定stop標誌
		 * @param isStop	是否停止
		 */
		public void setStop(boolean isStop)
		{
			this.isStop = isStop;
		}
	}
	
	/**
	 * 小球的畫板
	 * @author zjf
	 */
	private class BallComponent extends JComponent
	{
		public BallComponent()
		{
			//說實話,我不是很明白這段程式碼是幹什麼的,但是要用到背景色必須用到這段程式碼
			setUI(new ComponentUI() 	
			{
				public void installUI(JComponent c)
				{
					super.installUI(c);
					LookAndFeel.installColors(c, "Panel.background",
							"Panel.foreground");
				}
			});
		}
		/**
		 * 新增小球
		 */
		public void addBall()
		{
			double x = 0;	//小球開始的x座標
			double y = 0;	//小球開始的y座標
			String tmp = (String)placeCombo.getSelectedItem();	//得到方位的選擇項
			if (tmp.equals("Left-Top"))	//如果為左上
			{
				x = component.getBounds().getMinX();	//x設為畫板的最左邊的值
				y = component.getBounds().getMinY();	//y設為畫板的最上邊的值
			}
			if (tmp.equals("Left-Bottom"))	//下同
			{
				x = component.getBounds().getMinX();
				y = component.getBounds().getMaxY();
			}
			if (tmp.equals("Right-Top"))
			{
				x = component.getBounds().getMaxX();
				y = component.getBounds().getMinY();
			}
			if (tmp.equals("Right-Bottom"))
			{
				x = component.getBounds().getMaxX();
				y = component.getBounds().getMaxY();
			}
			
			Color color = Color.BLACK;	//小球開始的顏色
			tmp = (String)colorCombo.getSelectedItem();	//得到顏色的選擇項
			if (tmp.equals("red"))	//如果為red
			{
				color = Color.RED;	//顏色設為red
			}
			if (tmp.equals("orange"))	//下同
			{
				color = Color.ORANGE;
			}
			if (tmp.equals("yellow"))
			{
				color = Color.YELLOW;
			}
			if (tmp.equals("green"))
			{
				color = Color.GREEN;
			}
			if (tmp.equals("cyan"))
			{
				color = Color.CYAN;
			}
			if (tmp.equals("blue"))
			{
				color = Color.BLUE;
			}
			if (tmp.equals("magenta"))
			{
				color = Color.MAGENTA;
			}
			balls.add(new Ball(x, y, color));	//在小球的列表中加入新球,球的初始方位和顏色為前面的值
		}
		
		/**
		 * 繪製畫板
		 */
		public void paintComponent(Graphics g)
		{
			super.paintComponent(g);
			Graphics2D g2 = (Graphics2D)g;
			for (int i = 0; i < balls.size(); i++)	//將小球列表中的小球都畫到畫板上
			{
				Ball ball = balls.get(i);
				g2.setColor(ball.getColor());	//設定畫布中小球的顏色
				g2.fill(ball.getShape());		//畫出小球的形狀
			}
		}
	}
	
	/**
	 * 小球類
	 * @author zjf
	 */
	private class Ball
	{
		private static final double SIZE = 20;	//小球的直徑
		private double x = 0;	//小球所在的x座標
		private double y = 0;	//小球所在的y座標
		private double vx = Math.sqrt(2) / 2;	//小球在x軸的速度
		private double vy = Math.sqrt(2) / 2;	//小球在y軸的速度
		private Color color = Color.BLACK;		//小球的顏色
		
		/**
		 * 小球的建構函式
		 * @param x	小球所在的x座標
		 * @param y 小球所在的y座標
		 * @param color 小球的顏色
		 */
		public Ball(double x, double y, Color color)
		{
			this.x = x;
			this.y = y;
			this.color = color;
		}
		
		/**
		 * 小球在一個矩形邊框中移動
		 * @param bounds 矩形邊框
		 */
		public void move(Rectangle2D bounds)
		{
			x += vx;	//小球在x軸上的位移
			y += vy;	//小球在y軸上的位移
			double minX = bounds.getMinX();	//矩形邊界的最小x座標
			double minY = bounds.getMinY();	//矩形邊界的最小y座標
			double maxX = bounds.getMaxX();	//矩形邊界的最大x座標
			double maxY = bounds.getMaxY();	//矩形邊界的最大y座標
			if (x <= minX)	//如果小球越過左邊界
			{
				x = minX;	//小球的x座標變為矩形邊界的最小x座標
				vx = -vx;	//小球在x軸方向的速度反向
			}
			if (y <= minY)	//如果小球越過上邊界
			{
				y = minY;	//小球的y座標變為矩形邊界的最小y座標
				vy = -vy;	//小球在y軸方向的速度反向
			}
			if (x + SIZE >= maxX)	//如果小球越過右邊界
			{
				x = maxX - SIZE;	//小球的x座標變為矩形邊界的最大x座標減去小球的直徑
				vx = -vx;			//小球在x軸方向的速度反向
			}
			if (y + SIZE >= maxY)	//如果小球越過下邊界
			{
				y = maxY - SIZE;	//小球的y座標變為矩形邊界的最大y座標減去小球的直徑
				vy = -vy;			//小球在y軸方向的速度反向
			}
			for (int i = 0; i < balls.size(); i++)	//判斷小球間是否發生碰撞
			{
				Ball ball = balls.get(i);
				if (this.equals(ball))	//自己和自己不碰撞
					continue;
				if ((ball.x - x) * (ball.x - x) + (ball.y - y) * (ball.y - y) <= SIZE * SIZE)	//當兩球間的距離小於直徑時,可認為兩小球發生了碰撞
				{
					double degree = Math.atan((y - ball.y) / (x - ball.x));	//獲取自己與發生碰撞的小球之間所形成的夾角,因為夾角只能在-pi/2-pi/2之間,所以還需判斷兩球的x座標之間的關係
					if (x > ball.x)		//如果自己的x座標大於發生碰撞的小球的x座標,由數學知識可知自己應該往正向運動
					{
						vx = Math.cos(degree);	
						vy = Math.sin(degree);
					}
					else	//如果自己的x座標小於發生碰撞的小球的x座標,由數學知識可知應該朝負向運動
					{
						vx = -Math.cos(degree);
						vy = -Math.sin(degree);
					}
				}
			}
		}
		
		/**
		 * 獲取小球的形狀
		 * @return 形狀
		 */
		public Ellipse2D getShape()
		{
			return new Ellipse2D.Double(x, y, SIZE, SIZE);
		}
		
		/**
		 * 獲取小球的顏色
		 * @return 顏色
		 */
		public Color getColor()
		{
			return color;
		}
		
		/**
		 * 判斷兩個小球是否相同
		 */
		public boolean equals(Object object)
		{
			if (this == object) return true;	//如果所指的物件相同,即兩小球的確相同
			if (object == null) return false;	//如果要比較的小球不存在,則兩小球不同
			if (getClass() != object.getClass()) return false;	//如果自己的類名與另一個物件的類名不同,則兩小球不同
			Ball ball = (Ball)object;			//將另一個物件強制轉化為小球
			return x == ball.x && y == ball.y && color.equals(ball.color);	//通過方位,顏色判斷是否相同
		}
	}
}

相關推薦

Java小球碰撞

import java.awt.*; import java.awt.geom.*; import java.awt.event.*; import javax.swing.*; import javax.swing.plaf.ComponentUI; import jav

劍指Offer面試題15(Java):鏈表中倒數第K個結點

head 計數器 easy sta 相同 ret white style 輸出 題目: 輸入一個鏈表。輸出該鏈表中倒數第k哥結點。 為了符合大多數人的習慣,本題從1開始計數。即鏈表的尾結點是倒數第1個結點。 比如一個鏈表有6個結點。從頭結點開始它們的值依次是1。2。

撲克模擬,牌型判斷java

setvalue () ssa pri isp src [] break -c Card類 package com.company; public class Card { private String color;

排序算法(java

emp ive public while href ava 指針 循環 lec 1. 冒泡算法2. 快速排序3. 歸並排序4. 選擇排序5. 堆排序 排序算法 重要性不言而喻,很多算法問題往往選擇一個好的排序算法往往問題可以迎刃而解 1、冒泡算法

高速排序(Java

content 輸入 println pop package ati 遞歸 子列 大於 package com.love.test; import java.util.Scanner; /** * @author huowolf *高速排序實現 *快排是十

使用Chrome Headless 快速實現java數據的抓取

chrome headless java調webkit 參考《使用Chrome快速實現數據的抓取(一)——概述》和《使用Chrome快速實現數據的抓取(二)——協議》。各協議客戶端實現參考:https://github.com/ChromeDevTools/awesome-chrome-devtoo

JS (canvas) 兩個小球碰撞

隨機數 ack parseint ++ arc req dia doc all <style media="screen"> * { margin: 0; padding: 0;

Escape加解密Java

java[java] view plain copy /** * 中文加密 * Created by geo on 2017/7/4. */ public class EscapeUtils { /** * Escape編碼 * @p

Java2048

code graphic java版 退出 c++ 找到 -s 繼續 事件 功能要求:2048的基本界面,能夠實現2048的遊戲功能。 總思路:兩個類:Game和GameListener。   Game負責界面的實現和paint方法的重寫   GameListener負責

劍指Offer面試題43(Java):n個骰子的點數

pac pos max mod ins pri class pro bili 題目:把n個骰子仍在地上。全部骰子朝上一面的點數之和為s,輸入n,打印出s的全部可能的值出現的概率。 解法一:基於遞歸求骰子的點數,時間效率不夠高 如今我們考慮怎樣統計每個點數出現的次數。要向

玩玩微信公眾號Java之二:接收、處理及返回微信消息

log med iou set arch weixin b- rom data- 前面已經配置了微信服務器,那麽先開始最簡單的接收微信消息吧~ 可以用我們的微信號來直接進行測試,下面先看測試效果圖: 這是最基本的文本消息的接收、處理及返回,來看看是怎麽實現的

JAVA-微信語音.speex轉.wav

-a 微信 nothing reat making btool com ase 1.8 功能介紹:PC端將.speex文件解碼為*.wav文件 ### 環境:1. MAC OS 10.12.5/Linux2. Xcode 3. Gcc4. JDK 1.85. speex 1

傻瓜方法求集合的全部子集問題(java

post 分解 ipp targe 找到 creat dojo class length 給定隨意長度的一個集合。用一個數組表示,如{"a", "b","c"},求它的全部子集。結果是{ {a},

quicksort(java)

大於 for 實現 string 第一個 sort 完全 dex algorithm 相信大家都知道幾種排序算法,比如說冒泡排序,選擇排序,插入排序等等,這些個算法都不是很難,自己多多理解理解就能掌握了,而今天我們要談的就是重頭戲就是快速排序。 引用大牛的思想來對排序算法解

快速排序,一個愛情故事-java

-- .com span 得到 跳出循環 div public while 五步 public static void myquicksort(int[] ages,int girl,int boy){ //這是一個站在數組兩端,追求完美愛情的故事 //年齡

小米2017秋招真題——電話號碼分身問題(Java

imp spa ray 描述 mov lose port next can 原題描述如下: 通過對各個數字對應的英文單詞的分析,可以發現一些規律: 字母Z為0獨占,字母W為2獨占,字母U為4獨占,字母X為6獨占,字母G為8獨占; 在過濾一遍0、2、4、6、8後,字母O為1

java雲筆記(二)

blank app mar emc mt4 雲筆記 shu cmm ndt qC50f曬06渙hx厙咆2http://www.docin.com/nwghs11486 評z謁64a癡嘶06棵自暮0http://jz.docin.com/zdng396 5crl71也

Java雙向冒泡排序算法

交換 color ava back 好的 一個 經典的 時間 保持 冒泡排序算法是一種較為簡單的並且穩定的排序算法,該算法的時間復雜度最好為O(n),最差時為O(n^2),需要的空間復雜度為O(1)。 這裏的算法穩定性是指 經過排序後,各元素仍然能保持它們在排序之前的相對次

jieba分詞/jieba-analysis(java

日本 word amp b- exception 鏈接 arp not unit 簡介 支持分詞模式Search模式,用於對用戶查詢詞分詞Index模式,用於對索引文檔分詞特性支持多種分詞模式全角統一轉成半角用戶詞典功能conf 目錄有整理的搜狗細胞詞庫因為性能原因,最新的

獲取服務端https證書 - Java

https certificate 接上篇,用java代碼實現一下獲取遠程服務端證書,還是拿新浪首頁測試,上代碼:package org.test;import java.net.URL;import java.security.MessageDigest;import java.security.c