/**
* 設計聲明:
* 1、雖然岸本是日本人,而我個人作為其模仿者,依然想表示個人對其的敬意,希望作品不會玷污寫輪眼的名聲。
* 2、由於本次設計包含過多數學計算,所以強烈建議您通過《注意事項》中的5查看圖是如何設計的,先不要看源碼,
* 然後自己試圖去設計,而您僅需要知道:計算機計算開方、三角函數、反三角等會造成誤差,僅此而已。
* 3、由於我本人在《動態中國太極圖——Java原創》中改了一個注釋錯誤,導致《動態中國太極圖——Java原創》
* 不能再次通過系統的審批,不知何故,所以導致大家可能看不到《動態中國太極圖——Java原創》裡面詳細
* 的注釋,深表遺憾。同時也對我自己沒能認真做好本質工作表示深深的反思。
* 4、如果您對這個很好奇,那麼請現查閱本人發表的《動態中國太極圖——Java原創》(不知道還能不能通過審批)、
* 《動態眨眼效果——Java原創》,因為那兩個是這個設計的引導+鋪墊。
*
*
* 注意事項:
* 1、本程序為java程序,同時感謝您花費寶貴的時間來閱讀本文檔;
* 2、請注意包名為:practice,文件名為:SharinganJFrame(Sharingan是寫輪眼的英文),注意檢查,
* 以防一些不必要的麻煩;
* 3、在完成確認2中的內容後,本程序可以直接運行,因為本軟件說明都在注釋中;
* 4、由於本設計是繼《動態中國太極圖——Java原創》、《動態眨眼效果——Java原創》後編寫,所以在那裡
* 面已說明的東西,不再詳述,同時由於個人能力、閱歷等原因,有些細節可能並沒有詳細闡述,或者
* 有疏漏,請諒解。
* 5、您可以注釋paint()方法中的一些代碼,因為效果很直觀,也許這樣您理解得更快,建議如下:
* 5.1 先看paint()方法第1條語句效果,把paint()方法中的其它語句注釋掉;
* 5.2 再看paint()方法第1、2條語句效果,把paint()方法中的其它語句注釋掉;
* 5.3 再看paint()方法第1、2、3條語句效果,把paint()方法中的其它語句注釋掉;
* 5.4 以上面的方法類推,直到paint()方法中沒有語句被注釋,相信等您看完,您就理解了。
*
* 設計目標:在一個JFrame中繪制一個動態的寫輪眼(動漫《火影》中的特殊眼睛)。
*
* 設計說明:
* 相信很多人不喜歡看那些很長文字的說明,所以本人只簡單介紹一下個人想法及遇到的一些問題:
* 1、設計的源頭來自我和同桌(程夢真)無意中提到寫輪眼,所以打算把它用Java繪出來,而且要是動態的;
* 2、目前的版本的寫輪眼和最初設計的寫輪眼有很大差別,很多單詞的定義已經沒有了當初的味道。
* 3、繪制這個動態的寫輪眼的時候遇到最嚴重的的問題是計算誤差,就是蒼老師說的精確但不准確,所以
* angleErr是用來做誤差補償的,當然這個還是不是很准確,沒有更深入的去探究,由於本來就是娛
* 樂,所以沒打算去深究,如果你感興趣,想去琢磨,請注意一下angleErr所出現的地方,本人因為
* 這個誤差,重畫了進3遍才找出根本原因。
*
* 2014-1-14 星期二
*
*/
package practice;
import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JFrame;
public class SharinganJFrame extends JFrame {
//設置中心坐標,個人喜歡一種心點作為物體的坐標,物理裡面成為質點
int centerX = 1024/2;
int centerY = 768/2;
//外圓半徑,寫輪眼轉動所依賴的紅線
double extendCircleSemi = 25;
//寫輪眼的旋轉部分有一個固定的大小的圓,剛開始設計的時候是定義為白色的,後來改為了紅色,好看 ^_^
double whiteOfSharingan = extendCircleSemi/3;
//在上面的紅色的圓旁邊有一個隨著旋轉角度變大而變大的圓,其半徑為miniCircleSemi
double miniCircleSemi = 0;
//這裡用到了繪制太極時的思路,這個圓和上面的兩個圓(whiteOfSharingan和miniCircleSemi)外切
double sharinganSemi = 0;
//旋轉度角范圍的變量,您可以通過觀察旋轉的循環角度是120*2
int angleCircle = 0;
//小圓(miniCircleSemi)和白圓(whiteOfSharingan)在外圓(extendCircleSemi)上的角度
double angleOfWhiteMini = 0;
//寫輪眼溝玉圓(sharinganSemi)和白圓(whiteOfSharingan)在外圓(extendCircleSemi)的角度
double angleOfwhiteShar = 0;
//用於判斷圓是否到達極限位置,還句話說就是是否到達了正確的角度,進行下一次循環
boolean flag = true;
//溝玉球心到弦(whiteOfSharingan圓中心和miniCircleSemi圓中心所連成的線)中心距離;
double distansOfWhiteShar =0;
//溝玉球心到中心點的距離,這一步主要是為了計算坐標
double distansOfSharSemi = 0;
//在繪圖過程中,由於計算機計算開方、三角函數、反三角等造成了誤差,這是一個補償值,但要注意真正補償的
//誤差為這個誤差的angleErr*2/3,因為這個值是本人通過理想設置臨界狀態得到的值。
double angleErr = 0.02500260489936114;
//溝玉球(whiteOfSharingan)中的黑球半徑,這個值是動態的
int blackOfWhiteSemi = 0;
//中心眼睛所占的長度
int eyeLength = 300;
//眼睛幅值
int amplitude = 50;
public SharinganJFrame() {
this.setTitle("Sharingan");
this.setSize(centerX*2, centerY*2);
this.getContentPane().setBackground=\'#\'" startRun();
this.setVisible(true);
}
@Override
public void paint(Graphics graphics) {
super.paint(graphics);
//繪制一個眼睛作為背景
graphics.setColor(Color.red);
for (int i = 0; i < eyeLength; i++) {
graphics.drawLine( centerX-eyeLength/2+i,
centerY-(int)(Math.sin(Math.PI*i/eyeLength)*amplitude),
centerX-eyeLength/2+i,
centerY+(int)(Math.sin(Math.PI*i/eyeLength)*amplitude));
}
//在眼睛的中心繪制一個黑色的圓
graphics.setColor(Color.black);
graphics.fillOval( centerX-90/2,
centerY-90/2,
90,
90);
//在眼睛的中心繪制一個白色的圓
graphics.setColor(Color.white);
graphics.fillOval( centerX-60/2/2/2,
centerY-60/2/2/2,
60/2/2,
60/2/2);
//用於繪制3個不同角度、在不斷變化、不同位置的太極圖,圖是有順序的
for (int i = 0; i < 3; i++) {
//繪制寫輪眼球(sharinganSemi)
graphics.setColor(Color.red);
graphics.fillArc( (int)(centerX-sharinganSemi+Math.cos(Math.PI*(angleCircle+90+(i*120))/180-angleOfWhiteMini/2+angleOfwhiteShar+angleErr*2/3)*distansOfSharSemi),
(int)(centerY-sharinganSemi-Math.sin(Math.PI*(angleCircle+90+(i*120))/180-angleOfWhiteMini/2+angleOfwhiteShar+angleErr*2/3)*distansOfSharSemi),
(int)(sharinganSemi*2),
(int)(sharinganSemi*2),angleCircle+i*120,180);
//繪制寫輪眼固定圓(whiteOfSharingan)
graphics.setColor(Color.red);
graphics.fillOval( (int)(centerX-whiteOfSharingan+Math.cos(Math.PI*(angleCircle+90+(i*120))/180)*extendCircleSemi),
(int)(centerY-whiteOfSharingan-Math.sin(Math.PI*(angleCircle+90+(i*120))/180)*extendCircleSemi),
(int)(whiteOfSharingan*2),
(int)(whiteOfSharingan*2));
//繪制寫輪眼黑球(miniCircleSemi)
graphics.setColor(Color.black);
graphics.fillOval( (int)(centerX-miniCircleSemi+Math.cos(Math.PI*(angleCircle+90+(i*120))/180-angleOfWhiteMini)*extendCircleSemi),
(int)(centerY-miniCircleSemi-Math.sin(Math.PI*(angleCircle+90+(i*120))/180-angleOfWhiteMini)*extendCircleSemi),
(int)(miniCircleSemi*2),
(int)(miniCircleSemi*2));
//繪制寫輪眼固定球內黑球(blackOfWhiteSemi)
graphics.setColor(Color.black);
graphics.fillOval( (int)(centerX-(blackOfWhiteSemi+0.0)/120*whiteOfSharingan/2+Math.cos(Math.PI*(angleCircle+90+(i*120))/180)*extendCircleSemi),
(int)(centerY-(blackOfWhiteSemi+0.0)/120*whiteOfSharingan/2-Math.sin(Math.PI*(angleCircle+90+(i*120))/180)*extendCircleSemi),
(int)((blackOfWhiteSemi+0.0)/120*whiteOfSharingan),
(int)((blackOfWhiteSemi+0.0)/120*whiteOfSharingan));
}
//繪制外圓
graphics.setColor(Color.red);
graphics.drawOval( (int)(centerX-extendCircleSemi),
(int)(centerY-extendCircleSemi),
(int)(extendCircleSemi)*2,
(int)(extendCircleSemi)*2);
}
public void startRun() {
new Thread(){
public void run() {
while(true){
if (flag) {
angleCircle += 2 ;
//溝玉白球中的黑球半徑
blackOfWhiteSemi = angleCircle;
//System.out.println(angleCircle);
//根據目前寫輪眼溝玉球轉過角度來確定mini小球目前的對應的半徑
miniCircleSemi = (angleCircle+0.0)/120*whiteOfSharingan;
//System.out.println(miniCircleSemi);
//溝玉球半徑
sharinganSemi = miniCircleSemi+whiteOfSharingan;
//System.out.println(sharinganSemi);
//由於白球和mini小球都是在外圓上,所以通過弦對應的角度來求的小圓落後於白球的角度
angleOfWhiteMini = Math.asin(sharinganSemi/2/extendCircleSemi)*2;
//System.out.println(angleOfWhiteMini);
//溝玉球心到白球中心距離
distansOfWhiteShar = (whiteOfSharingan-miniCircleSemi)/2;
//溝玉球心到中心點的距離
distansOfSharSemi = Math.sqrt( extendCircleSemi*extendCircleSemi
-((whiteOfSharingan+miniCircleSemi)/2)*((whiteOfSharingan+miniCircleSemi)/2)
+((whiteOfSharingan-miniCircleSemi)/2)*((whiteOfSharingan-miniCircleSemi)/2));
//溝玉球心和白求在中心圓上所成的角度
//通過這裡可以可以求出由於計算機計算產生的計算誤差為(0.02500260489936114)
//System.out.println(distansOfSharSemi);
angleOfwhiteShar = Math.asin(distansOfWhiteShar/2/distansOfSharSemi);
//System.out.println(angleOfwhiteShar);
if (angleCircle == 120) {
flag = false;
}
}else {
angleCircle += 2;
//溝玉白球中的黑球半徑
blackOfWhiteSemi = 240-angleCircle;
//根據目前寫輪眼溝玉球轉過角度來確定mini小球目前的對應的半徑
miniCircleSemi = (240.0-angleCircle)/120*whiteOfSharingan;
//miniCircleSemi = (angleCircle+0.0)/120*whiteOfSharingan;
//溝玉球半徑
sharinganSemi = miniCircleSemi+whiteOfSharingan;
//由於白球和mini小球都是在外圓上,所以通過弦對應的角度來求的小圓落後於白球的角度
angleOfWhiteMini = Math.asin(sharinganSemi/2/extendCircleSemi)*2;
//溝玉球心到白球中心距離
distansOfWhiteShar = (whiteOfSharingan-miniCircleSemi)/2;
//溝玉球心到中心點的距離
distansOfSharSemi = Math.sqrt( extendCircleSemi*extendCircleSemi
-((whiteOfSharingan+miniCircleSemi)/2)*((whiteOfSharingan+miniCircleSemi)/2)
+((whiteOfSharingan-miniCircleSemi)/2)*((whiteOfSharingan-miniCircleSemi)/2));
//溝玉球心和白求在中心圓上所成的角度
angleOfwhiteShar = Math.asin(distansOfWhiteShar/2/distansOfSharSemi);
if (angleCircle == 240) {
angleCircle = 0;
flag = true;
}
}
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
repaint();
}
};
}.start();
}
public static void main(String[] args) {
new SharinganJFrame();
}
}
動態眨眼效果---Java實現強大的作品 http://www.linuxidc.com/Linux/2014-01/95249.htm