2019年9月8日 星期日

從 C 呼叫 Lua 函式

故事是這樣子的,小弟在公司裡面,主要是負責維護一個沒人在用的產品,遠觀來說這個產品滿複雜的,內建兩種不同的演算法實作,為的是要應對不同的狀況,有些狀況用第一種演算法比較快,有些用第二種。
那故事是這樣子的,我們的程式裡面有一個函式會在每筆資料結束之後,用上筆資料的結果來判斷下一次要選哪個演算法,問題是這個函式目前是直接寫在整個引擎的 C code 裡面,於是如果想要改變一下判斷的標準……sorry 重新 build,雖然公司弄了套分散編譯可以編很快但還是要幾分鐘。
上星期自己試了一下,成功把 Lua 編到公司的 code 裡面,就能把判斷邏輯寫在 Lua script 裡面,要改判斷標準只要改 Lua 就可以了;我一般聽到會這樣用的是遊戲公司,因為遊戲一樣涉及大量的邏輯判斷,例如血要扣多少之類的,而遊戲又會大量的去變動這些參數,使得彈性變得非常重要,總不能要改參數就把整個遊戲引擎全部重建構一次……說是這麼說我也不曾證實哪家公司真的這麼做就是,如果我的讀者真的是這樣搞的麻煩留個言讓我知道一下。

總之自己試過之後其實非常簡單,難怪大家都說 Lua 最厲害的就是嵌入到 C 程式當 Sup 角 ,我主要是參考這個網頁(看來是舊金山大學 CS 的課程頁面);下載 Lua 就從官網下載即可,哪一版應該是無所謂,或者是 Linux 的話安裝開發套件也 OK。
不愧是以輕量著稱的腳本語言,連 Makefile 看起來都是手寫的,直接下 Make 讓它編譯完成,雖然說我在這步被環境變數 TARGET_VAR 卡了很久,makefile 不知道為什麼自己把它加到編譯參數裡了。
再來做下面幾件事就能呼叫 Lua 函式了:

1. 引入 Lua 的標頭檔:

#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
然後在編譯的時候記得給一下 lua 標頭檔的位置,以及在連結的時候 -llua。

2. 生成 Lua state:

Lua 的 state 包含核心的函式,後面所有的函式都會需要這個 state;在 open 和 close 中間就能呼叫 Lua 函式了:
lua_State* L = luaL_newstate();
luaL_openlibs(L);
// write lua_call ... code here
lua_close(L);

3. 載入檔案,呼叫函式:

使用 luaL_dofile 打開 lua 檔案,等於是呼叫 lua 直譯器執行這個檔案,如果有直接執行的東西這時候就會有效果,像是 print("hello world") ,我們這裡只是定義變數 "add" 對應到相加的函式。
要呼叫 lua 函式,我們以函式 add 為例:
-- add.lua add function
add = function(a, b)
  return 42
end
那麼在 C 裡面就是:
luaL_dofile(L, "add.lua");
lua_getglobal(L, "add");
lua_pushnumber(L, a);
lua_pushnumber(L, b);
lua_call(L, 2, 1);  // 2 parameter, 1 return value
int sum = (int)lua_tointeger(L, -1);
lua_pop(L, 1)
簡單來說就是先用 lua_getglobal 拿到存在 global 裡面的函式 add(在 luaL_dofile 的時候建立的);把參數推到堆疊上;執行 lua_call,指定兩個參數跟一個回傳值,取出回傳值,把回傳值彈出堆疊。
如果函式有多個回傳值的話,會依序放在堆疊的 -1, -2 … 上;lua_pop 也要彈出更多值;Lua 的有一系列的函式來把東西推到堆疊上/彈出堆疊,簡單的應用,通常就是 lua_pushinteger/lua_tointeger, lua_pushnumber/lua_tonumber 來推/彈整數跟浮點數到堆疊上,詳情請參考文件

這裡只記錄最基礎的應用,實際上應該還有更複雜的應用,例如我要做決策的參數如果很多的時候該怎麼辦?或者其實我想要直接推一個 struct 進到 lua 是可以的嗎?
這兩個問題我目前都沒有答案,還有待研究,目前只知道 luajit 這個看起來好像停擺的專案有提供類似的東西,可以準備好 C 的 struct 來吃。
如果有大大們有答案的話麻煩教一下小弟,小弟現在很需要。

2019年9月4日 星期三

Rust 裡面那些 String 們

故事是這樣子的,最近把小弟自幹的編譯器加上 rust 的 llvm wrapper llvm-sys,經過一陣猛烈的攪動之後,自幹的編譯器終於可以 dump LLVM IR 了,雖然只會輸出一個空殼子…但有第一步總是好的。
不過小弟在綁定的時候遇到一個大問題,也就是 Rust 裡面的 String,到底怎麼會有這麼多種,因為寫的時候一直沒搞清楚,然後就會被編譯器噴上一臉的錯誤,覺得痛苦,於是決定來打篇整理文。
簡單來說,Rust 的 std 有四種 String,每個 String 都有動態記憶體模式跟沒有 size 資訊(不是 Sized)的靜態模式,他們是:
std::string::String <-> std::str
std::ffi:OsString <-> std::ffi::OsStr
std::path::PathBuf <-> std::path::Path
std::ffi::CString <-> std::ffi::CStr
還有一個比較少用,只能表示 ascii 128 字元組成的字串的 std::ascii::asciiExt,這裡就不介紹了。

一般的程式語言在數字型態通常都很固定,Rust 就很明確的分為 i8, i16, i32, i64 …,就偏偏字串是個大坑,因為從 ASCII 到 unicode,字串實在有太多分岐,儘管有 unicode 也不是到處適用。Rust 從設計上一開始就直接採用 utf-8 作為設計標準,原生的 String/str 就是 utf 8 字串。
可是呢,並不是所有作業系統都玩 utf8 這套,因此 Rust 有另一個使用 wtf8 的 OsString,wtf8 跟 utf8 的差異在於 wtf8 算是<格式比較差>的 utf8,會出現一些 utf8 不允許的位元組,偏偏規格沒有要求一定要完美格式,造成 windows 或 javascript 有時會出現這種格式不良的 wtf8 字串,因此 OsString ,跟專門用來表示路徑的 PathBuf 就是使用 wtf8。
有關 wtf8 請參考:https://simonsapin.github.io/wtf-8/

上面的字串都是在型態中記錄字串長度,結尾不會有 \0 字元,CString 則是最傳統的 null-terminated 字串,在呼叫 C 函式的時候,一定要用 CString 傳遞才行。
順帶一提,一般寫在 code 裡面的 let hello = "hello world" 的型態是 &'static str:生命週期為 static 的靜態字串。

知道了以上幾個區別之後,就來看看要怎麼使用它們:
String 最簡單,裡面一定要是 utf8,產生就是從 static str 產生,或者是 new 之後慢慢 push 進去:
let hello : String = String::from("hello");
let mut world : String = String::new();
world.push_str("world");
world.push('!');
OsString 是類似的,但只能從 String 轉過來(注意 String 的所有權會轉給 OsString),或者一樣 new 之後 push String 進去:
use std::ffi::{OsString, OsStr};
let oshello : OsString = OsString::from(hello);
let mut world : OsString = OsString::new();
world.push("world!");
PathBuf 其實就想成 OsString 就好,兩者也可以互相用 from 轉換:
use std::path::{PathBuf, Path};
let p1 : PathBuf = PathBuf::from(oshello)
let mut p2 = PathBuf::new();
p2.push("/dev");
上面說了,OsString 跟 PathBuf 用的是 wtf8,是 utf8 的超集,因此一般只能單向從 String 到 OsString,反向是不行的,呼叫 OsString::into_string() 得到的是 Result<String, OsString>,也就是有可能會轉失敗;或者就是用 into_lossy_string 把編碼不完整的地方變成 U+FFFD,utf8 的 replacement character。
PathBuf 則是沒有 into_string 可以用,只能先轉換成 OsString 再轉過去,我也不知道為什麼 core team 要這樣設計。

剩下的就是函式了,很有趣的是 String, OsString, PathBuf 都是動態容器,操作內容都要轉換到 str, OsStr, Path 上面去:
str 有操作字串用的 split_whitespace, starts_with 等等
OsStr 沒有任何特殊的函式XD。
Path 有很多對路徑的操作:is_absolute, parent, with_extension 等等,很多函式操作後都會得到 Path 或是 OsStr 讓你做接下來的操作。

CString 比較棘手一點,它要在 new 的時候代入 Vec<u8> (或者有實作 Into<Vec<u8>> 的型態)來建立 CString,new 會自動在後面加上 \0 ,因此這個 Vec 裡面不應該有 \0。
其實我覺得把 CString 想得 Vec<u8> 的另一種型態就好了,它本身也提供 into_bytes, as_bytes 等函式轉換成 Vec<u8> 的型態。
如果要從 String 跟 OsString 轉換過來的話,String 要用 as_bytes() 轉成 Vec<u8>,OsString 因為 unix 跟 windows 會有不同的 OsString 實作,不一定都能轉成 Vec<u8>,在 unix 要引入 std::os::unix::ffi::OsStrExt 就可以將 OsString 用 as_bytes() 轉成 Vec<u8>;Windows 則建議轉成 String 再轉成 bytes ,請參考這個網址

用上了 CString,最重要的就是要交給外部的 C 函式去用,要用 as_ptr() 取出字串部分的 pointer,得到的就是 * u8 了,有必要的話再加上 as *const i8 轉型一下。
例如我要呼叫這個函式:
LLVMPrintModuleToFile (LLVMModuleRef M, const char *Filename, char **ErrorMessage)
這個函式,我的檔案名稱是一個 OsString:
use std::ffi::{CString, CStr};
use std::os::unix::ffi::OsStrExt;
llvm::core::LLVMPrintModuleToFile(
           self.module,
            path.as_bytes().as_ptr() as *const i8,
            ptr::null_mut());
看了這麼多,簡單整理一下大概是這樣:

老實說每次只要在 Rust 裡面弄到 Path 都會弄到懷疑人生……

2019年8月28日 星期三

十年一覺 N1 夢

故事是這樣子的,8/27 剛公佈 2019 年第一次日文檢定的成績,經過了三次不合格之後,這次通過 N1 ,天氣好不用再散步可以跑步啦(什麼。


先來個有圖有真相:
配個歷年成績,一開始真的是慘不忍睹……:
2016/12:語言知識 23/60  讀解 32/60  聽解 22/60   77/180   Not Passed
2017/07:語言知識 26/60  讀解 33/60  聽解 30/60   89/180   Not Passed
2017/12:語言知識 36/60  讀解 32/60  聽解 31/60   99/180   Not Passed
2019/07:語言知識 38/60  讀解 58/60  聽解 33/60  129/180  Passed

上次就已經來到只差一分合格,理應再準備一下就可以過關,但認真應考還是太累,年初工作剛到任還在適應中,決定一口氣延一年半到今年 7 月,還很幸運的在台灣大學新的大樓應考(不過新教室有一點問題,之後再說),這次總算通過啦。
這次的準備沒有特別久,如果我沒記錯的話應該是四月初開始認真準備,不過真要說的話其實是沒多認真啦…,我覺得投的時間比之前考前都還要少,下面會提一下各區塊的準備方式,有些可能會有業配嫌疑,不過我保證沒有,反正這個小 blog 跟現在工作做的產品一樣都沒人在意(欸:
  • 語彙、閱讀
語彙跟閱讀這次是放在一起……沒有準備,這次是從閱讀下手,在上班通勤時間陸續看了utsuki 給我的<哪啊哪啊~神去村>,還有許久以前從 BookOff 搬回來都沒看的<嫌疑犯X的獻身>,兩本都是看過中文再看日文,避免日文看不懂的狀況,一開始的單字量會比較大一點,看多頁之後就會比較順,還會發現一些作者愛用字,像是神去村作者很喜歡用うなずく;題庫只有寫一本<全攻略新日本語能力試驗N1讀解問題集>,這本我覺得題型跟真的考試的 correlation 有點差異。

以這次的結果論,閱讀我覺得是有效的(我現在反而超好奇我是錯了哪題www),至少不合格的三次閱讀題寫得滿抖的,趕在最後一分鐘的時間寫完;相對的這次閱讀題看得滿順,寫完還剩 40 分鐘,我還一度以為 N1 是不是變簡單了,還回去推敲了文法排序的幾題(以結果來看效果沒有很好就是);單字的話可能效果不如預期,畢竟言語知識分數沒往上,但文法有被評為 A,所以很可能是單字被扣。
言語字彙年輕的時候可以用 anki 之類的背單字軟體,不過我是覺得老了之後有點用不起來,一直盯手機太累了,還不如輕鬆看小說,然後買個迷你記事本把不會的單字記下來,在走路的時候拿出來複習。
  • 文法
文法在自我學習上是用之前用過的兩本:<TRY!日本語能力試驗從文法掌握N2> 跟 <TRY!日本語能力試驗從文法掌握N1>,這兩本文法的好處是有附 10 篇含所教文法的短文跟CD,很早以前考 N2 時是自己讀,那時還是拿奇怪的文法整理手冊在背,現在看來覺得效果沒有很好,這次乾脆把 CD 倒出來,然後反覆的聽跟跟讀到熟,像是睡覺前就放一篇聽到睡著、或是在工作中重複播放,我猜兩本書的 CD 我至少聽過 50 遍以上 。

課程的話,這次是在 utsuki 推薦的 Cafetalk 上面找老師,基本上只要是日文老師都會開 JLPT 專門的課程,結算是上了 28 堂,平均下來大約一週上兩次 50 分鐘的課程;老師是用<日本語パワードリル N2>跟<日本語パワードリル N1>,寫大量的題目跟講解,基本上絕對是有練有差,有些題目用的文法是同一個,錯兩遍就記下來了;而且意外的發現自己在<選出最符合文章的文法選項>這大題非常的弱。
另外老師有用一本<日本語総まとめ N1 語彙>,裡面有整理疊字詞跟副詞,在考前背過一陣,我覺得多少是有用的。

考試結果來看至少文法的評定結果是 A,不過我個人覺得在<重組文法>這題上面,做過的練習題難度都不到真正考試的難度,Correlation 很差,平常寫練習題都很順手,上場考試卻排不太出來,我也不知道該怎麼改善就是了。
  • 聽力
聽力的話…就真的是放水流了……沒有認真準備啊結果也變醬糊,考試結束就覺得跟之前比沒有脫胎換骨的感覺…還是一樣,沒 Fu,聽一聽就是會掉字,偏偏在日文掉關鍵字很致命;然後第四大題真的是我的罩門,真的不知道要回什麼,每個 3 都好像是答案……;這次的聽力還證實了我的閱讀跟聽力是連不上的,有一題聽力講了一堆 りんぎょう,我就一直在想りんぎょう 是啥……見鬼<林業>啦…,,真的是愧對我還看完神去村小說。

準備上我是建議把字幕丟掉,小弟也是 2016 考爆之後,從 2017 的<動物朋友>開始遮字幕看動畫,至現在雖然不是內容 100% 聽得懂,像搖曳露營有關千元鈔票的地方就沒聽懂,但意思都能抓個大概,如<Lovelive Over the Rainbow>跟<紺青之拳>在電影院也盡量遮字幕看。
動畫之外就是把比較紅的<逃避雖可恥但有用>、<半澤直樹>、<房仲女王>的日劇,一樣看完中文之後遮字幕看日文同時跟讀、在上班重複聽上面幾部日劇,或是狂聽 NHK 之類(不過 NHK 其實重複的內容很多,像是颱風、天氣、股市一直重複,其實不算太好的素材);其他就是強者我同學 GGM 大大借我的<新日檢聽解一本搞定>,有意思意思聽過一輪。

綜觀練習狀況,我覺得這次比上次還要穩定許多,我會給的建議,也是我第二次不合格之後,在 N1 衝刺班上老師給的學習建議:
  1. 從聽開始:把字幕丟了,聽動畫、日劇跟綜藝節目,看過中文再聽一遍也可以;反正一定有足夠簡單的內容,比如說動物朋友(O。
  2. 跟讀:超痛苦,但是是讓舌頭聽話的有效方法,必要的時候像房仲女王,可以考慮用 0.8 倍速跟讀,也比較輕鬆一點。
我覺得先不管日檢,至少這兩年練下來耳朵是有變靈敏的,至少看動畫會知道在講啥,練習題會莫名的知道它想講什麼,甚至聽沒聽過的歌也能聽出一些單字,這邊引用研究好像是吊書袋,但之前看過的研究是指出:沒字幕對學語言的效果最好,有其他語言的字幕有一點效果,有字幕基本上就沒效果了(如果有人知道這個研究的話煩請讓我知道一下)。

考場上也沒什麼太大問題,就是新教室比較大,有人反應聽力的聲音不夠大聲,讓大家聽了 8 遍<天氣好的話去散步吧>,真的很靠北……


細數從大三的時候心血來潮(?)修了日文一,到今天通過 N1,差不多也要十年了,十年間進進退退,修完日文一之後停了一年,接著修了日文二跟後續的一些進階課程;13 年 7 月第一次挑戰N3,那時候在實驗室忙得要死要活,考前一天還失眠睡不著,準備不週又完全沒睡上場考試(回想起來沒考到睡倒真是奇蹟),結果 97/180 比及格高2分浮過去了。
14 年 12 月通過N2,那次準備比較充足些,總分:107/180;後來因為兵役的關係,從 15 年到 16 年進去當個兵出來什麼都忘了,以致連續三次被 N1 壓在地上打QQ。

N1雖然及格了,但從聽說讀寫來看,也只有讀算勉強過關:
現在的口說帶有一種奇怪的口音,重音位置超奇怪,被真的會日語的人指稱她完全聽不懂我在說啥,之前參加多國語言交換咖啡,也是被一位日本人瘋狂糾正,每說一句都有文法上的錯誤,跟 Cafetalk 的老師對話也是零零落落的,他能聽得懂我想講什麼根本奇蹟;試著跟讀也是很吃力,舌頭沒辦法動這麼快的感覺。

俗話說:「N1 考過了只是剛開始」。
誠哉斯言,個人經驗來講,所謂的多益、N1,其實都是能夠訓練的,就像軟體公司面試要刷題,文法、閱讀也能透過刷題解決,這次考前文法粗估應該刷了 300-400 題吧。但除去考試,語言能力或者任何能力,除了實際上場幹架之外,有什麼是考試考得出來的呢?考過了其實什麼都沒有;不過,現下已經知道了進步的方法,剩下就是慢慢努力,務求聽說讀寫能力俱備了。

十年一覺 N1 夢,夢醒時分繼續努力。

2019年8月19日 星期一

第一次在 COSCUP 當講者就上手

故事是這樣子的,在上周結束了兩天的 COSCUP 行程,總算達成人生成就:參加 COSCUP (欸。
這次是以講者的身分去的,畢竟搶票什麼的實在是太難了,就跟搶普悠瑪一樣難,當講者好像比較簡單(True Story)。

這次準備的題目其實都是準備許久的,一個是本次 COSCUP 有開 Rust 議程軌,就把之前寫 computationbook-rust 裡面當範例的 simple language ,配上研究一小段時間的 PEG parser 挑出來,攪一攪投出去。本來這是想要去年的 MOPCON 投的,但畢竟 MOPCON 是以網路為主體,跟這 programming language 還是格格不入被拒絕了。

下面是投影片:


blog 的話,可見實作麻雀雖小五臟俱全的程式語言剖析表達文法 PEG 簡介使用 rust pest 實作簡單的 PEG simple 剖析器使用 procedence climbing 正確處理運算子優先順序幾篇。

另外一個議題則是去年 8-10 月做的 Nixie Tube Clock,COSCUP 有非常適合的硬體議程軌,老實說 Rust 議程軌我覺得不一定會上,硬體議程軌我就真的滿確定會上,畢竟講硬體的本來就少,Nixie Tube Clock 也滿完整的,果然最後就上了一場。
投影片在此:


blog 筆記總計有十篇:
0. 前言
1. 材料取得
2. 自組高壓電路
3. 驅動電路
4. 控制電路
5. 電路板基礎
6. 電路板實作 layout
7. 焊接
8. 寫 code
9. 後記

個人小小的體悟是,先不要想 COSCUP,先想著把某件事情做好,時候到了投稿自然會上;就像會上一位大大說的,因為沒搶到票決定每周用 golang 寫一個 project,52 週之後就當講者了。
這次投上的題目,無論是 PEG + programming language,還是 Nixie Tube Clock,都是一年前甚至兩年前開始的嘗試,PEG 還搞了個失敗的 C parser,blog 寫了好幾篇的題目,做到這種程度才能換到 40 分鐘的上台時間;也許現在就該來想一下要做什麼新題目了。

----

第一次參加 COSCUP ,這次真的融合了超多議程軌人超級多,據說直接突破 2000 人,大拜拜的意味滿重的,像 Pycon 這樣同時段 3 場的都很常兩場一定要選的,COSCUP 同時開 14 場議程,從一開始聽議程就不是目的了。
實際下來比較像:三分聽議程,七分面基友。
細數一下我到底遇到多少在網路上見過面的大大:像是從荷蘭遠道而來的呂行大大、台灣軟體界照世明燈郭神大大、久未見面的 jserv 大大、好高興教授大大、TonyQ 大大、在會前酒會遇見上海大殺四方的 Richard Lin 大大、曾經在高雄氣爆的時候幫我提升 Google Map 權限的 pingooo 教授大大;認識了台灣 maker 社群、Python HsinChu User Group - PyHUG。
不過我覺得比較扯的還是呂行大大,走一走每個攤位都能遇到人,真的是神猛狂強溫爽發。

記得以前參加 PyCon,總會在那邊要求自己盡量的聽,連可能不知道在講什麼的、 lightning talk 都聽完之類的,這幾年終於改掉這樣的習慣,發現時間寶貴,聽一些跟自己太遠的東西其實是浪費時間,還不如放點時間出來跟大家聊聊天,真的沒想聽的就早早離開會場沒差;網路上常講:
小孩子才做選擇,成年人當然是我全都要。
但其實,成年人才知道自己要什麼、不要什麼、有能力要什麼、沒能力要什麼,我覺得是反過來的:
成年人才做選擇,小孩子才是我全都要。

我想最後還是要感謝一些人,像是強者我同學 JJL 大大幫小弟 review 投影片;強者我同學 wmin0 大大幫小弟生出一個 Nixie Tube 的講題,這個題目應該給大大講才是。
明年希望大家也都能成為 COSCUP 講者。

2019年8月3日 星期六

Minecraft 火車站相關系統的設計

小弟玩 Minecraft 一段時間,其實一直想蓋一個大型火車站,然後連續兩次因為伺服器更新所以蓋不完XDD,不過在蓋火車站的期間,還是累積了一些火車站相關系統的設計,蓋不完還是可以介紹一下:
1. 快速向上電扶梯
2. 驗票閘門
3. 平面停開車系統
4. 礦車減速系統

快速向上電扶梯:


快速向上電扶梯其實跟火車站沒什麼關係,但就…火車站常有的東西,這版是用一組向上活塞跟向前活塞交錯推進做成,小心控制紅石信號的延遲就能把人快速的往上推。
當然其實好像沒什麼必要啦…畢竟在 Minecraft 裡面把樓梯又快又不浪費體力,而且電扶梯一堆活塞運作起來其實很吵…。

驗票閘門:

第一版:
第二版:

驗票閘門是腦洞大開做出來的,基本概念是像真的驗票閘門一樣,讓使用者必須投入指定的物品閘門才會開啟,通過之後閘門關上,不小心一口氣就設計了兩個版本:
第一種是投票之後就會開閘門
第二種使用者要從另一個 dropper 裡面取票閘門才會開,更像真實的驗票機

這部分用文字跟圖片說也說不清楚,也許最簡單的還是看影片。

系統的核心如下圖,第二個漏斗裡的東西是裝滿的,這樣使用者只能投入特定的東西(車票);比較器比較投入漏斗跟參考漏斗物品數量是否相同,就能感知<使用者是不是投入車票>這件事,利用這個信號控制漏斗下的另一個漏斗,就能夠控制每次只通過一個物品。

因為我們要求的是投入物品的漏斗,放入物品之後發出的訊號要跟參考值一樣,查一下 wiki,投入物品的漏斗的物品數量要是 22 個,參考漏斗則是 23 個,放入東西之後訊號強度會升到 2,讓比較器打開。

後來就只是基本電路的操作,把物品通過的訊號截出來設定 SR latch,過閘門的踏板重設 SR latch,藉此控制閘門活塞的動作 現在的 SR latch 除了可以用標準的 2x4 雙火把之外,也可以用雙漏斗的 SR latch 設計,如下圖所示,兩者都是 SR latch。

差別在於兩個漏斗的版本,兩個控制信號必須是 1,設定的時候短暫變為 0 來釋放漏斗內的東西;火把設計則是反過來。

平面停開車系統:


這個是很以前設計的東西,因為以前在 Minecart 上是完全不能移動的,所以一定要有一個發車的系統,最一般的就是用凹洞或凸起構成的斜面,加速鐵軌就會朝下加速,不然在平面上加速鐵軌就算有電也不會加速。
這個平面的系統利用活塞,在車子開過去之後把停車位置的背面從鐵軌換成方塊,這樣加速鐵軌就能在平面上讓車子啟動,中間要注意的只有活塞進推的時序問題;不過說起來只是為了改善使用者體驗,不然簡單斜坡就有一樣的效果了。

礦車減速系統:

當初採用減速系統是在火車站的入口,讓使用者能選擇要進站或過站不停。
其實這部是很早以前也是從 Youtube 看到的,但後來完全找不到,幸好當時有先複製一份到測試 server 裡,現在才能蓋出來。
這個系統真的是非常巧妙,利用了比較器來計時,還有將脈衝保持在一個迴圈中來讓鐵軌進到減速模式,整個就是我自己做不出來的設計(yay,所以大家還是看影片吧

目前火車站大概是有這些設計,不過話說回來現在好像也沒什麼時間可以蓋火車站了(yay。
Related Posts Plugin for WordPress, Blogger...