選單

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

大家還記得暑假花

兩個星期

從零開發太空科幻小遊戲《星旅 StarTrek》的零零後

燒風

嗎?是的,他帶著新作品Plotter又來了!

燒風是華南師範大學軟體學院大一學生(2002 班),興趣廣泛並喜歡肝自己感興趣的事情,這次他帶來的 Plotter前身是用 HTML 和 JavaScript 寫的一個科學計算的程式,特點在於

非常強大的函式視覺化能力

Plotter 不是一個遊戲,而是一種

非常硬核、極少人願意去做,或者做好的軟體——數模軟體 / 計算器

。它是一個輕量級、跨平臺、不依賴網路的便攜性科學求解軟體。

Plotter 已經開源,應用市場連結和 GitHub 連結見文末。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

那麼這款使用 CCC 開發跨平臺應用軟體是怎樣開發出來的呢?它用到了哪些技術?它是怎樣的,它的特點是什麼?

燒風帶來了非常詳盡的技術分享,是 jare 看了深夜置頂的程度,建議大家閱讀收藏。

為保證閱讀體驗,參考連結見文末。

01

前言(關於星旅和 Plotter)

暑假花兩週爆肝開發《星旅 StarTrek》之後,發現 Cocos Creator(下面簡稱 CCC)真香!

從使用 CCC 編輯器進行遊戲場景的視覺化編輯,到用 TypeScript 進行遊戲程式碼的編寫,除錯非常容易,讓我的開發效率異常高!

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

星旅 StartTrek 上線後短短一個星期就獲得了

數千的玩家註冊量

單日 CDN 流量最高甚至突破了 4GB

,當天我非常震驚,然後立馬給企鵝充值續了伺服器流量。

開發星旅之前,我僅僅寫過一點點 JavaScript,也從來沒有正經和完整地開發一款遊戲。

在學校找同學組建了開發小組之後,我負責了大部分程式和遊戲內容策劃,從零開始上手 TypeScript 和 CCC。由於 TypeScript 和 CCC 這兩個工具都特別優秀,所以我們都可以幾乎很快地上手使用。

CCC 使用 TypeScript 是一個很不錯的選擇,TypeScript 是 JavaScript 的超集,有更好的型別推導能力,這讓程式碼在編寫過程中容易獲得 IDE 的提示,大大減少了 debug 的次數和避免隱藏的錯誤。

TypeScript 可以編譯生成任何版本的 JavaScript 程式碼,而 JavaScript 程式碼可以執行在幾乎任何平臺,又由於現代 JavaScript 引擎的最佳化,因此在大多數情況下 JavaScript 程式碼的執行效率非常高,可以比 Python 快甚至比未經最佳化的 C 程式碼還快。

開發了星旅之後,我就在想:

藉助 CCC 的優勢,我能不能開發一個應用軟體,而不是遊戲呢?

並沒有經過太多思考,我決定立刻開始開發試一試!

02

探索 CCC 的另外一些可能

Plotter 原本是我以前用 HTML 和 JavaScript 寫的一個科學計算的程式,特點在於非常強大的函式視覺化能力。

多年前我接觸過安卓開發,並且開發了很多簡單的 APP ,還在酷安網上架了好幾個,於是我想試一試:基於 CCC 開發一個安卓 APP 並上架應用市場。

在課餘時間,陸陸續續開發

一兩個星期

之後—— Plotter APP 終於誕生了!並且很快上架了酷安網。

功能如此硬核的一個 APP ,竟然在短短的

一週內下載量就超過 2000

,APP 的

討論熱度在三天內就突破了 3w

,還多次上了酷安網話題頭條,實屬誇張!

03

用 CCC 開發 APP 的可行性

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

CCC 可以

打包幾乎任何平臺

(包括但不限於 Web、Windows、OS X、Android、iOS 和各種小遊戲平臺),藉助這個優勢和 CCC 提供的大量 API,大多數程式碼一次編寫就可以全平臺執行,尤其是介面互動邏輯、網路操作和一些基礎的底層操作(如讀寫本地檔案、裝置震動等)。

即便是需要更加底層或者原生平臺的操作,也可以使用 CCC 提供的 jsb。reflection 介面,在 JavaScript 中呼叫原生平臺的方法:

Android 平臺:Java 方法或者 C++ 函式

iOS 等平臺:Objective-C 或 C++ 函式

反過來,如果原生平臺的程式要執行 JavaScript 裡的邏輯,不管是 Java、C++ 還是 obj-C 都可以使用 evalString 方法執行 JavaScript 裡的邏輯。具體參考官方文件Java 原生反射機制 · Cocos Creator。

下文的技術分享裡,我會以複製文字到安卓平臺剪貼簿,隱藏安卓 Activity 裡的一個 ImageView 為例,告訴大家如何使用 JSB 反射機制。

為什麼我想用 CCC 來開發一個應用軟體呢?它有何優勢?

使用 CCC 構建軟體的互動介面非常容易,可以視覺化的編輯互動介面,並用指令碼來控制互動邏輯

Canvas 的 Fit Width 和 Fit Height 可以保證渲染範圍的自適應,利用 cc。view。getVisibleSize() 我甚至可以知道目前軟體的可視範圍大小,以響應不同使用者的螢幕尺寸來適配佈局,也支援了裝置的多解析度。

關於多解析度適配還可以參考官方文件多解析度適配方案 · Cocos Creator 4

利用 CCC 現有的 Sprite、Layout、Canvas、ScrollView、ScrollBar、Button、Label、ProgressBar、EditBox 等元件 ,我可以非常自由地設計出自己喜歡的 UI 控制元件並直接使用

使用 CCC 的緩動方法 cc。Tween,我可以很容易為軟體增加符合使用者感知和視覺引導以及提升使用者舒適度的動畫

軟體介面以場景或者節點形式組織,每個指令碼都是元件,每個控制元件都是一個具體的節點,而元件繫結在節點上,節點又可以繫結到元件上… 這種組織形式非常靈活和直觀,讓業務邏輯結構很清晰,易於管理和大型開發

用 npm 安裝需要的庫並直接使用!眾所周知,npm 的庫的數量非常非常的多,是一個非常大的寶藏,如果你想用到某一個複雜演算法或某種特定程式,不要造輪子!去 npm 查查有沒有現成的庫可以直接使用。但並不是所有 npm 庫都可以在 CCC 內穩定執行,後文會講原因

遊戲引擎級別的圖形渲染支援和物理支援

使用 CCC 開發出來的圖形介面執行效率仍然很高,並且非常靈活

對於特定需求,如軟體內 2D 或 3D 圖形的渲染支援、Shader 圖形渲染、剛體或流體物理模擬等,遊戲引擎無疑是一個巨大的優勢,可以極大的減少工作量

記得曾有一家公司,為了讓自己的網站達到原生級別的流暢度,他們完全使用 HTML 的 Canvas 來渲染整個網站的所有內容,最後效果確實很理想。

其實跟我使用遊戲引擎差不多,所以這對於我來說還是有優勢的。

那用 CCC 開發一個 APP 有什麼劣勢?

近段時間備受關注,讓很多開發者和公司直喊真香的 Flutter ,本質上可以說也是一個遊戲引擎。

Flutter 是谷歌開發的移動平臺 UI 框架,它使用谷歌的 Dart 語言來編寫使用者介面和互動邏輯。然而與原生 APP 不同,由於要載入 Flutter 支援庫和初始化,Flutter 開發的 APP 安裝包更大,啟動時間要更久。

在這一點上,使用 CCC 開發一個 APP 也會遇到同樣的問題,為了支援不同架構處理器的執行,相容和適配更多機型,就得編譯更多份 。so 二進位制檔案,安裝包會變大比較大。

同樣 APP 第一次開啟時要初始化支援庫、OpenGL ES、JavaScript 引擎,所以啟動時間會比原生 APP 更長。

但經過我的測試,

即便如此 APP 的啟動時間仍然還是挺快的(至少比什麼微信、淘寶和大多數遊戲快得多了)

,與 Flutter 差別不會太大。

對於 APP 啟動時間的最佳化,以及對 CCC 打包的 APP 的啟動屏最佳化,下文的技術分享會提到。

04

技術分享

使用 npm 庫

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

在 CCC 專案工程根目錄中,可以直接使用 node。js 的包管理器 npm 安裝可能需要用到的 JavaScript 庫。

安裝方式也特別簡單,例如在命令列中輸入 npm install numeric 就可以安裝 numeric 這個數學求解庫。

為什麼像 math。js 這樣的庫可以正常匯入 CCC 裡並穩定釋出呢?

首先 math。js 不依賴於瀏覽器環境——也就是不需要 window document 等物件。其次 math。js 不依賴於JavaScript的 eval() 函式,保證了即便是在微信小遊戲上也能夠正常執行。

多解析度屏幕布局適配

Plotter 使用了三種方式進行不同屏幕布局的適配。

方法1:Canvas 的 Fit Width 和 Fit Height

對於這兩個選項勾選的作用,引用自官方文件。

由於要開發一個安卓手機 APP,這裡我預設螢幕尺寸是 9:16 並設定解析度為 1080*1920 。

但安卓早已進入全面屏時代了,手機螢幕變的更長了,如果我同時勾選這兩個選項。就會使得我的 APP 介面無論在哪臺裝置都是固定長寬比,上下就會出現大黑邊:

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

方法2:Widget

使用 Widget 元件可以使得一個節點對齊父節點的邊緣。

為了避免黑邊的出現,我就只勾選 Canvas 的 Fit Width,給背景色節點掛上 Widget 元件,並用 Widget 元件讓它充滿整個 Canvas ,這樣就避免了黑邊的出現。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

方法3:JavaScript 程式碼動態更改控制元件位置

雖然解決了黑邊問題,但是如果螢幕高度太小,控制元件離開了螢幕可視區域怎麼辦?

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

正如上圖,對於 APP 頂端的 Top 按鈕欄,如果是 iPhone X 就可以正常被現實出來,而如果是 iPhone 5,Top 按鈕欄就會被遮擋:

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

因此,我這邊在主指令碼的 onLoad 函數里,利用 JavaScript 程式碼判斷螢幕尺寸,以更改控制元件佈局,並更好地適配不同的螢幕。

APP 啟動速度最佳化

CCC 打包的安卓 APP 在啟動時都會經歷一小段黑屏載入時間,讓人感覺特別遲鈍,實際上我們可以對此進行最佳化,以達到更好的使用者體驗。

方法1:新增啟動圖

透過改變原生安卓啟動 Activity 的 Theme 和主介面佈局,可以為 APP 的啟動增加一個啟動圖,這樣開啟 APP 立馬就可以看到 Logo 而不是黑屏了,讓人感覺舒適很多。

這裡有大佬寫的文章特別細緻,我就不在此贅述了

Cocos Creator Android 原生啟動最佳化系列

Cocos Creator Android 原生啟動最佳化系列 1—— 黑屏原因分析

Cocos Creator Android 原生啟動最佳化系列 2—— 自定義啟動頁

區別在於我在 layer-list 中圖示的下面加了一行字。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

另外,在 hideSplash 函式中,我使用 Android 的 animate 讓啟動圖淡出消失,而不是瞬間消失,達到更好的效果。

上述程式碼是在 CCC JavaScript 這邊主場景載入完成後,使用 jsb。reflection 呼叫 Java 方法,以隱藏原生介面裡的啟動圖。

方法2:減少主場景的複雜度

透過減少主場景的節點以及元件數目,加快場景載入時間。最佳化主場景每個節點掛載指令碼的 onLoad 函式的執行效率。用此最佳化方法,也可以大大加快 APP 的啟動時間。

ScrollView最佳化

最佳化 Content 內節點數目

ScrollView 在可視範圍內的節點數目一般很少,然而如果 ScrollView 中有數千個專案,我就建立數千個節點的話,不僅消耗大量記憶體,而且會讓執行效率變得特別低。

所以不如讓 ScrollView 內節點數目固定,剛剛好可以鋪滿就行,然後在滑動 ScrollView 時改變節點的位置,然後動態回收利用已有的節點進行展示。

對子節點所掛載指令碼單獨最佳化

在 Plotter APP 的上方,有一個暫存器列表,點選之後可以展開暫存器列表,檢視暫存器中已有的變數。

對於暫存器列表裡的每一條專案,它們都是“活”的——響應式。即它們會知道當前運算核心中自己所屬的變數值有沒有改動,如果改動了,它們就會立刻改變此專案 Label 裡的文字內容,如果沒有改動,它們就不做任何操作。

另外,如果列表中這一條專案使用者看不到,那它就處於休眠狀態,不受響應。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

使用反射機制實現複製文字到剪下板

CCC 提供的反射機制 jsb。reflection 可以呼叫原生宿主平臺的方法(如 Java 方法、C++ 方法和 Objective-C 方法),以實現與底層邏輯的互動。這裡我以複製文字到剪貼簿——一個應用軟體的常見需求為例。

在構建的 Android Studio 工程目錄下,找到 src/org/cocos2dx/javascript/APPActivity。java 檔案,這是 CCC 打包的安卓 APP 的入口活動(Activity)。

在 APPActivity 類底下加入私有靜態變數 App。

在 onCreate 方法的最下面為 app 設定引用。

然後在類中新增一個靜態方法 JavaCopy。

上述程式碼中的 “plotter” 你可以隨意改為你需要的 Label。

然後當需要呼叫安卓 API 複製文字到剪貼簿時,就透過 CCC 的 Java 反射實現。

關於 jsb。reflection ,更加具體的資訊可以查閱官方文件。

使用類似的方法,我們還可以實現呼叫 iOS 的 API 複製到剪貼簿。

這裡我寫了一個支援瀏覽器、微信和安卓的方法,大家可以直接複製拿去使用~

裝置震動 API

有時候我們點選一個按鈕,需要有震動反饋,那麼應該如何實現呢?

當然我也可以使用上述反射的方法自己實現,但查閱了 CCC 的原始碼之後,發現 CCC 已經有震動的API,在 cocos2d-x/cocos/scripting/js-bindings/auto/jsb_cocos2dx_auto。cpp

這裡我們也看到,在 jsb。Device 這個名稱空間中,CCC 還提供了一些其它原生方法。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

最後我這裡實現了一個支援三個平臺的震動的方法:

然而,如果僅僅是這樣,呼叫震動方法之後 APP 會閃退!

不能忘記在 AndroidManifest。xml 中給 APP 宣告所需震動許可權!

靈活使用緩動

在 Plotter 裡,我大量使用了緩動函式 cc。Tween ,為 APP 新增更多的控制元件動畫,並且利用緩動的性質,這些動畫都是可以被中途打斷並復原的,也就是各大手機廠商為自己系統吹的“打斷動畫”或者“補間動畫”。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

WebView 的 JS 注入和使用 WebView 顯示 SVG

在 Plotter APP 中,有一個特色功能是將LATEX程式碼渲染成漂亮的書寫體,這是怎麼實現的呢?

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

我使用了 npm 中 MathJax 這個開源庫,利用它的 Tex2Svg。js 可以把 TeX 程式碼渲染為 SVG 格式的向量圖(實際上是一串字串),然後將此 SVG 顯示出來即可。

那麼在 CCC 中,如何顯示出 SVG 格式的向量圖呢?CCC 商城有一套 SVG 外掛,然鵝我窮呀,所以就只能自己另闢蹊徑了。

我使用 CCC 支援的 WebView ,然後用 HTML、JS 和 CSS 注入的方法。

實際上 HTML、CSS 的注入本質上還是 JS 注入,透過執行指定的 JS 程式碼就可以改變網頁的 DOM 。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

上圖程式碼中,我為了讓網頁中 svg 圖片居中,注入了這樣一段 JS 程式碼,改變了 svg 的 style。

實際上注入 JS 還有另一種奇怪的方法:透過改變 url 來注入 JS

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

上述兩種方法也可以在 Java 安卓裡以類似的方法同樣實現。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

另外,透過改寫 CCC 的 Cocos2dxWebView。java 實現 WebView 的透明背景以及自由縮放。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

多執行緒和高效能計算

眾所周知,JavaScript 的 一大槽點是 JavaScript 程式碼是單執行緒執行的。

大部分併發都可以透過 JavaScript 的非同步實現,但在要進行 CPU 密集型運算時不可避免的需要用到多執行緒,以防止主執行緒的 UI 互動等邏輯卡死,可以透過 Web Worker 或者前文講到的反射機制呼叫原生平臺的 API 來實現多執行緒並行運算。

另外,還可以將需要執行的複雜 JavaScript 程式放到 WebView 中,然後呼叫 WebView 的 evaluateJS 函式執行此程式。

當我們的程式需要

非常高效能

的計算時,還有兩種方法。

一種是

使用 Web­Assembly

,現有的工具可以把像 C 或者 Rust 這樣的高效能程式編譯為位元組碼,直接在瀏覽器內執行,執行效率非常高。

另外一種是當需要大量並行的浮點運算、或大矩陣的運算時(通常是圖形學計算、物理模擬、深度學習等所需要),可以透過

利用 OpenGL ES、或者 WebGL 進行 GPU 加速運算。

總結來說就是:

多執行緒

高效能

透過反射機制,呼叫 C++ 程式WebAssembly使用 WebGL 等進行 GPU 加速運算 。

向量圖示的製作

以前我曾製作過一個 APP 的圖示,但是由於時間久遠,找不到原始素材了,然而現在的這個圖示解析度太低,我想將它轉換為更加清晰的 Logo 怎麼辦?

在網上可以找到標量圖轉向量圖的工具,將圖示轉換為無論方法多少倍都不會模糊的 SVG 向量圖,再對這個向量圖進行修改,就可以獲得更加清晰的 Logo 啦!

最後經過數次修改,得到了新的 APP 圖示。

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

另外推薦兩個獲取好看的 APP 圖示的網站:

Icon 圖示線上製作工具(p2hp。com)

Material Design Icons

05

最後聊聊 Plotter

Plotter 的特點使得它所面向的使用者有:

中小學生:分數帶單位的四則運算、簡單的函式繪圖、組合學運算、統計學運算

大學生:向量 / 矩陣的運算、數值微積分、多元函式的極值等

工程師:複數運算和求解,全平臺——無論在哪臺裝置都能允許,且可以離線執行

程式設計師:各種進位制之間的轉換和運算,超高精度浮點數或者大整數的運算

教育工作者:透過影象和更具化的運算方式帶給學生更深刻的概念

科研工作者:

便攜性使得無論何時何地產生了靈感,立馬就可以拿出裝置進行計算和實驗

帶單位的運算使得科研人員能在計算時帶單位運算,在任何時候可以進行帶單位數值的轉換,還使得在計算資料時保證量綱不出錯

在任何時候引入高精度帶單位的常量進行運算,例如普朗克常數、阿伏伽德羅常數等

支援複數運算,多元函式最最佳化,解微分方程數值解等

Created with Cocos | 硬核開源數模軟體技術歷程大公開!

在此也回答一些大家可能困惑的問題:

Q:

教育工作者已經有像 Desmos、Geogebra 這樣的專業軟體了,不同的工程師也有各自領域的專業軟體,科研工作者更是有像 MATLAB、Mathematica、Python 這樣的專業工具了,那 Plotter 的意義何在?

A:

Plotter 的願景是讓科學計算變得更加簡單和容易。Plotter 封裝了不同領域都可能用到的功能,使其受眾較廣泛,其設計使得它能夠在任何平臺上離線執行,尤其是移動端,這使得軟體的通用性和便攜性很強。

Q:

讓科學計算變得更加簡單和容易能帶來什麼?

A:

現代科學技術的突飛猛進離不開計算機的產生。無論是對 DNA 的測序還是蛋白質結構的模擬,讓現代生物學突飛猛進發展到新的階段,產生了生物資訊學。

同樣對大腦神經元的模擬推進了腦科學的發展,對醫藥資料的分析帶來的科學發現造福了無數疾病中的苦難人群。

有限元分析使得我們能夠在計算機上模擬物理過程,廣泛運用於工業。對天體執行的模擬造就了現在的天文學和航天學。

對化學分子運動的模擬而發現了新的催化劑…不知道多少科學家用 MATLAB 分析實驗資料,獲取了一次又一次科研突破,多少數學家用 Mathematica 進行符號運算,減少了手工計算導致的出錯率,提高了數學研究的效率…

因此可以說:新的科學發現是在以人類智慧驅動下的科學計算中產生的。

計算機科學家、粒子物理學家 Stephen Wolfram 曾提到計算本身也是一種新科學,

純粹的計算也可能發現宇宙的規律

Plotter 的體量並沒有那麼大,它僅僅是做到了輕量便攜和離線而已,但它的願景仍是

使得科學計算變的更加簡單和容易

~

感興趣的同學歡迎戳連結閱讀我的其他文章:

06

參考連結

Plotter GitHub 開源地址

https://github。com/HK-SHAO/Plotter

Plotter APP 應用市場連結

https://www。coolapk。com/apk/284166

Java 原生反射機制 · Cocos Creator

https://docs。cocos。com/creator/manual/zh/advanced-topics/java-reflection。html

多解析度適配方案 · Cocos Creator

https://docs。cocos。com/creator/manual/zh/ui/multi-resolution。html

npm

https://www。npmjs。com/

Canvas 元件

https://docs。cocos。com/creator/manual/zh/components/canvas。html#%E9%80%89%E9%A1%B9

Cocos Creator Android 原生啟動最佳化系列 1 —— 黑屏原因分析

https://www。jianshu。com/p/2df139d48539

Cocos Creator Android 原生啟動最佳化系列 2 —— 自定義啟動頁

https://www。jianshu。com/p/21d269c8ef09

Icon 圖示線上製作工具

Material Design Icons

https://materialdesignicons。com/