[Tutorial][數(shù)學向]從零開始的MC特效(一 | 基礎(chǔ)在X, Z軸上的畫圓操作)

從零開始的MC特效

本教程轉(zhuǎn)自 [Tutorial][G-Second][應該全核心]從零開始的MC特效
原作者是我 (小聲

目錄:

  • 導讀
  • 數(shù)學與Minecraft的融合
  • 利用數(shù)學在Minecraft中畫一個圓
  • 利用數(shù)學在Minecraft中畫一個球

導讀

本教程需要讀者有一定的空間想象能力(因為我也懶得畫圖了233)
本教程使用的 Spigot1.10.2-R0.1-SNAPSHOT 核心
在閱讀之前請確保你具有高中數(shù)學必修4和Java基礎(chǔ)的知識
(沒有我也會適當?shù)慕忉尩?

<初中生>: 如果你是初中的話匠楚,別慌峻厚,你有函數(shù)的概念就可以讀懂本教程(應該吧...)
<高中生>: 如果你還未學到關(guān)于上面的兩本書,別慌學到了再來看也行233 (霧


數(shù)學與Minecraft的融合

首先我們都知道Minecraft是一個3D游戲韭寸,所以它就有了XYZ這三個軸,那么我們可以看如下的一張圖來了解一下

image

本教程暫不涉及關(guān)于Y軸的相關(guān)內(nèi)容潦匈,所以我們可以先從平面直角坐標系來分析

image

利用數(shù)學在Minecraft中畫一個圓

以下內(nèi)容需要sin函數(shù)與cos函數(shù)的相關(guān)知識烘嘱!
首先呢我們先來看一張圖(自己用word畫的2333)

image

分析:
首先這個坐標系有一個單位圓(半徑為1的圓),然后我們看到角α為30°尚粘,之后點P的橫坐標為 √3/2 縱坐標為 1/2

然后我們再看下圖

image

那么我們是否可以這么認為择卦,點P的橫坐標其實是 cos(30°) 而縱坐標就是 sin(30°)呢?

補充: 如果你已經(jīng)有了參數(shù)方程的概念那么郎嫁,這里你可以忽略了 —— 2019/1/12

PI 代表圓周率π, 之后π = 180° (別問我為什么秉继,課堂上自己學去233)*

P(cos(30°), sin(30°)), 弧度制: P(cos(PI/6), sin(PI/6))

那么P的橫坐標和縱坐標都是可以利用函數(shù) cos和sin 求出泽铛,那么我們?yōu)槭裁床豢梢?strong>遍歷一下把360°全部都給算出呢尚辑?所以我看寫出下方的代碼這樣我們就可以把一周角里所有的角度都給遍歷了一便,并且我們都算出了每個角度所對應的cos值和sin值吧盔腔,然后我們需要把他們作用到Minecraft當中

// 我們把玩家腳下的location作為是原點O 
Location location = player.getLocation(); 
for (int degree = 0; degree < 360; degree++) {
    double radians = Math.toRadians(degree);
    double x = Math.cos(radians);
    double y = Math.sin(radians);
}

那么在上圖的for循環(huán)語句塊中我們有兩個變量 x y杠茬,也就是 P(x, y) 吧,之后我們回頭看一下for循環(huán)語句塊外的那個變量location弛随,那個我們可以理解成是在上圖中的原點O瓢喉,那么我們做個假設(shè),我們需要把點P轉(zhuǎn)換成MC中的Location要怎么做撵幽?灯荧,其實很簡單

location.add(x, 0, y);

我們把location的X軸假想為0, Z軸假想為0(這里的X軸和Z軸指的是Minecraft中的那兩個軸)即圖中原點O為(0, 0)礁击,那么在Minecraft中不可能任何時候原點的X Z軸都是0盐杂,所以我們需要做相加的操作

(上面可能會聽得一頭霧水,簡單來說當原點O不為(0, 0)時哆窿,假設(shè)為(2, 2)链烈,那么我們要做的是給玩家的周圍建立圓吧,那么這時候點P的坐標應該為 P(2 + x, 2 + y))

要是還聽不懂的話那就去喝杯茶挚躯,洗個澡吧2333

那么我們可以做以下的操作了

location.add(x, 0D, y);
// 播放粒子
location.getWorld.playEffect(location, Effect.HAPPY_VILLAGER, 1);
// 為什么要減强衡?因為我們要確保原點是不變的狀態(tài)才可以哦~
location.subtract(x, 0D, y);

游戲內(nèi)效果


游戲內(nèi)的效果

完整代碼

// 我們把玩家腳下的location作為是原點O
Location location = player.getLocation();
for (int degree = 0; degree < 360; degree++) {
    double radians = Math.toRadians(degree);
    double x = Math.cos(radians);
    double y = Math.sin(radians);
    location.add(x, 0, y);
    location.getWorld().playEffect(location, Effect.HAPPY_VILLAGER, 1);
    location.subtract(x, 0, y);
}
利用數(shù)學在Minecraft中畫一個球

首先我們來觀察一下sin的函數(shù)圖像,具體如下

圖 2-1

從上圖可以看出 sin函數(shù) 始終在 1~-1 之間徘徊码荔,所以我們認為它是有周期性的漩勤,那么這跟球的生成有什么聯(lián)系呢?我們看下圖

圖 2-2

首先這是一個球?qū)Π伤踅粒缓竽匚以谇蛏袭嬃藥讉€橫截面(才不是什么旋風)出來越败,那么通過上圖我們是不是可以得出一個結(jié)論,一個球體其實是由無數(shù)個圓構(gòu)成的硼瓣?只是它們的半徑不同對吧究飞。那這跟sin函數(shù)有啥聯(lián)系呢?

首先我們回到sin的函數(shù)圖像,我們看當x在0~π之間時連起來的y軸是不是像一個半圓耙诟怠媒峡?而且它們的半徑(這里的半徑可以理解為sin函數(shù)中的y軸)也是不同的,那么我們是不是可以這么認為葵擎,我們只需要 0 ~ ****π 之間的x值谅阿,然后代入函數(shù)當中就可以求出對應的y軸的值了?

那么 0 ~ π 是什么值呢酬滤?其實在上面的圓中我就講過 π=180°奔穿,所以我們求得其實就是 sin(0 ~ 180°)。

那么有了上面的思路我們可以求出每個圓的半徑對吧敏晤,那么我們寫出下面的代碼

for (double i = 0; i < 180; i++) {
    double radians = Math.toRadians(i);     
    double radius = Math.sin(radians);
}

在上方的代碼當中我們求出了一個球中每個圓的半徑, 但是我們還需要考慮一件事贱田,我們是不是要規(guī)定一下每個圓之間的距離啊嘴脾?

那么我們引入cos的函數(shù)圖像

圖 2-3

從上圖可以看出 f(x) = cos(x),
x=0時, f(x)則為1.
x=π時男摧,f(x)則為-1.

那么我跟sin的函數(shù)圖像聯(lián)系一下, 在上面的代碼中我們發(fā)現(xiàn),radius的值是從小到大再到小译打,那么我們想一下耗拓,如果半徑是小的那么那個圓是也是小的,而我們要畫的圓是從上往下畫的(觀察圖 2-2)對吧奏司,所以我們是不是要給那個最小的圓的y軸是最高的乔询?(沒看懂?喝杯茶吧)而cos函數(shù)就可以幫我們達到這一點韵洋,所以我們寫出以下的代碼

double y = Math.cos(radians);
那么這樣我們就可以獲得當前for循環(huán)時那個圓的高度了竿刁。

在上面的結(jié)構(gòu)中我們得到了當前圓的半徑和高度,那么我們要怎么通過這兩個東西畫出來呢搪缨?

我們在第三章畫圓時曾經(jīng)做過這么一個操作

for (int degree = 0; degree < 360; degree++) {
    double radians = Math.toRadians(degree);    
    double x = Math.cos(radians);     
    double y = Math.sin(radians);
}

上方的代碼中我們只能制造出一個半徑為1的圓食拜,那么我們想擴大它的半徑需要怎么做?

我們這里又引入一個函數(shù)y=Asin(ωx + φ) (這里的sin也可以為cos)副编,其實這個函數(shù)跟sin函數(shù)差不多只不過多了幾個變量负甸,那么這里我們只需要考慮A的值,

為什么呢痹届?我們來看一下這個函數(shù)在數(shù)學上的定義:

  • φ(初相位):決定波形與X軸位置關(guān)系或橫向移動距離(左加右減)
  • ω:決定周期(最小正周期T=2π/|ω|)
  • A:決定峰值(即縱向拉伸壓縮的倍數(shù))

由于這里我們只考慮A所以我們可以把上方的函數(shù)簡寫為 y = Asin(x)呻待,假設(shè)我們的A為2,那就是sin(x) * 2了队腐,那么反應在函數(shù)圖像上是這樣的

image

那么有了上面的概念我們不妨使用 Math.cos(x) * 半徑 來擴大本次循環(huán)時所對應的半徑蚕捉,所以我們寫出以下的代碼

for (double j = 0; j < 360; j ++) {
    // 依然需要做角度轉(zhuǎn)弧度的操作 
    double radiansCircle = Math.*toRadians*(j);     
    double x = Math.*cos*(radiansCircle) * radius;     
    double z = Math.*sin*(radiansCircle) * radius;
}

那么這樣就可以控制好本次循環(huán)我們需要這個圓多少半徑了,那么我們寫好之后就可以放在Minecraft中看看效果

完整代碼:

for (double i = 0; i < 180; i++) {
    // 依然要做角度與弧度的轉(zhuǎn)換
    double radians = Math.toRadians(i);
    // 計算出來的半徑
    double radius = Math.sin(radians);
    double y = Math.cos(radians);
    for (double j = 0; j < 360; j++) {
        // 依然需要做角度轉(zhuǎn)弧度的操作
        double radiansCircle = Math.toRadians(j);
        double x = Math.cos(radiansCircle) * radius;
        double z = Math.sin(radiansCircle) * radius;
        location.add(x, y, z);
        location.getWorld().playEffect(location, Effect.HAPPY_VILLAGER, 1);
        location.subtract(x, y, z);
    }
}

游戲內(nèi)的效果


效果

然后你就會發(fā)現(xiàn)你的游戲卡得一匹2333香到,因為我們是在360°全方位的進行渲染粒子的操作2333鱼冀,但實際業(yè)務(wù)中我們可能并不需要做這種需求报破,那么我們就需要做一個關(guān)于跳躍的操作唄,我們看下面的代碼

for (double i = 0; i < 180; i += 180 / 6) {
    // 依然要做角度與弧度的轉(zhuǎn)換
    double radians = Math.toRadians(i);
    // 計算出來的半徑
    double radius = Math.sin(radians);
    double y = Math.cos(radians);
    for (double j = 0; j < 360; j += 180 / 6) {
        // 依然需要做角度轉(zhuǎn)弧度的操作
        double radiansCircle = Math.toRadians(j);
        double x = Math.cos(radiansCircle) * radius;
        double z = Math.sin(radiansCircle) * radius;
        location.add(x, y, z);
        location.getWorld().playEffect(location, Effect.HAPPY_VILLAGER, 1);
        location.subtract(x, y, z);
    }
}

跟上面的代碼不同的是我在遍歷的時候修改了步長(step)千绪,那這一個有什么講究呢充易?我們在每一次循環(huán)給 i 和 j就加的是30了對吧,而不是自加1荸型,

那么我們看第一層循環(huán)盹靴,這一層循環(huán)控制的步長其實是我們其實需要多少圈,為什么呢瑞妇?我們看下面的圖來理解一下

image

這里我為了方便讀者理解我把圖 2-1 旋轉(zhuǎn)了一下稿静,上圖我們假想黑點是玩家的location,那么那幾個紅點就是我們把步長修改后所得到的產(chǎn)物

那么第二層循環(huán)我修改的步長又是什么意思呢辕狰?我們也拿張圖來理解一下
image

上圖中每個角的度數(shù)都是30°改备,那么我修改了步長之后是不是我只會在這幾個黑點上面做playEffect()的操作了?(看不懂的話喝口水再來看233)

修改了步長后游戲內(nèi)的效果:


image

結(jié)語

內(nèi)容依然是挺少的蔓倍。悬钳。希望能教給讀者一些東西吧233

莫老搞事,只搞真實 —— 撰寫: 一個來自普高文科的學生

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末偶翅,一起剝皮案震驚了整個濱河市默勾,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌聚谁,老刑警劉巖母剥,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異形导,居然都是意外死亡环疼,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門骤宣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來秦爆,“玉大人序愚,你說我怎么就攤上這事憔披。” “怎么了爸吮?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵芬膝,是天一觀的道長。 經(jīng)常有香客問我形娇,道長锰霜,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任桐早,我火速辦了婚禮癣缅,結(jié)果婚禮上厨剪,老公的妹妹穿的比我還像新娘。我一直安慰自己友存,他們只是感情好祷膳,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著屡立,像睡著了一般直晨。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上膨俐,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天勇皇,我揣著相機與錄音,去河邊找鬼焚刺。 笑死敛摘,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的乳愉。 我是一名探鬼主播着撩,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼匾委!你這毒婦竟也來了拖叙?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤赂乐,失蹤者是張志新(化名)和其女友劉穎薯鳍,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體挨措,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡挖滤,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了浅役。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片斩松。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖觉既,靈堂內(nèi)的尸體忽然破棺而出惧盹,到底是詐尸還是另有隱情,我是刑警寧澤瞪讼,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布钧椰,位于F島的核電站,受9級特大地震影響符欠,放射性物質(zhì)發(fā)生泄漏嫡霞。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一希柿、第九天 我趴在偏房一處隱蔽的房頂上張望诊沪。 院中可真熱鬧养筒,春花似錦、人聲如沸端姚。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寄锐。三九已至兵多,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間橄仆,已是汗流浹背剩膘。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盆顾,地道東北人怠褐。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像您宪,于是被迫代替她去往敵國和親奈懒。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內(nèi)容