如何用 JavaScript+Canvas 開發一款超級燒腦小遊戲?

2020-12-05 CSDN

作者 | huangjianke

責編 | 伍杏玲

【CSDN 編者按】據微信最新數據,微信小遊戲累計註冊用戶量已突破10億。那麼初學者如何開發一款好玩又燒腦的微信小遊戲呢?本文作者將詳細為大家講解。

「啟邏輯之高妙,因想像而自由。」層疊拼圖Plus是一款需要空間想像力和邏輯推理能力完美結合的微信小遊戲,偶消奇不消,在簡單的遊戲規則下卻有著無數種可能性,需要你充分發揮想像力去探索,看似簡單卻具有極大的挑戰性和趣味性,Talk is cheap. Show me the code!

層疊拼圖Plus微信小遊戲採用JavaScript+Canvas實現,沒有使用任何遊戲引擎,對於初學者來說,也比較容易入門。下面是小遊戲頁面:

如何解決Canvas繪圖模糊?

Canvas 繪圖時,會從兩個物理像素的中間位置開始繪製並向兩邊擴散 0.5 個物理像素。當設備像素比為 1 時,一個 1px 的線條實際上佔據了兩個物理像素(每個像素實際上只佔一半),由於不存在 0.5 個像素,所以這兩個像素本來不應該被繪製的部分也被繪製了,於是 1 物理像素的線條變成了 2 物理像素,視覺上就造成了模糊

繪圖模糊的原因知道了,在微信小遊戲裡面又該如何解決呢?

可以看到,我們先通過 wx.getSystemInfoSync().pixelRatio 獲取設備的像素比ratio,然後將在屏 Canvas 的寬度和高度按照所獲取的像素比ratio進行放大,在繪製文字、圖片的時候,坐標點 x、y 和所要繪製圖形的 width、height均需要按照像素比 ratio 進行縮放,這樣我們就可以清晰的在高清屏中繪製想要的文字、圖片。

可參考微信官方縮放策略調整

另外,需要注意的是,這裡的 canvas 是由 weapp-adapter 預先調用 wx.createCanvas() 創建一個上屏 Canvas,並暴露為一個全局變量 canvas。

如何繪製任意多邊形圖形?

任意一個多邊形圖形,是由多個平面坐標點所組成的圖形區域。

在遊戲畫布內,我們以左上角為坐標原點 {x: 0, y: 0} ,一個多邊形包含多個單位長度的平面坐標點,如:[{ x: 1, y: 3 }, { x: 5, y: 3 }, { x: 3, y: 5 }] 表示為一個三角形的區域,需要注意的是,x、y 並不是真實的平面坐標值,而是通過屏幕寬度計算出來的單位長度,在畫布內的真實坐標值則為 {x: x * itemWidth, y: y * itemWidth} 。

繪製多邊形代碼實現如下:

使用:

效果如下圖:

CanvasRenderingContext2D其他使用方法可參考:CanvasRenderingContext2D API 列表

1 + 1 = 0,「偶消奇不消」的效果如何實現?

1 + 1 = 0,是層疊拼圖Plus小遊戲玩法的精髓所在。

有經驗的同學,也許一眼就發現了,1 + 1 = 0 剛好符合通過異或運算得出的結果。當然,細心的同學也可能已經發現,上文有一句特殊的代碼:this.ctx.globalCompositeOperation = 'xor',也正是通過設置 CanvasContext 的 globalCompositeOperation 屬性值為 xor 便實現了「偶消奇不消」的神奇效果。

globalCompositeOperation 是指 在繪製新形狀時應用的合成操作的類型,其他效果可參考:globalCompositeOperation 示例

如何判斷一個點是否在任意多邊形內部?

當迴轉數為 0 時,點在閉合曲線外部。

講到這裡,我們已經知道如何在Canvas畫布內繪製出偶消奇不消效果的層疊圖形了,接下來我們來看下玩家如何移動選中的圖形。我們發現繪製出的圖形對象並沒有提供點擊事件綁定之類的操作,那又如何判斷玩家選中了哪個圖形呢?這裡我們就需要去實現如何判斷玩家觸摸事件的x,y坐標在哪個多邊形圖形內部區域,從而判斷出玩家選中的是哪一個多邊形圖形。

判斷一個點是否在任意多邊形內部有多種方法,比如:

射線法面積判別法叉乘判別法迴轉數法...在層疊拼圖Plus小遊戲內,採用的是迴轉數法來判斷玩家觸摸點是否在多邊形內部。迴轉數是拓撲學中的一個基本概念,具有很重要的性質和用途。當然,展開討論迴轉數的概念並不在該文的討論範圍內,我們僅需了解一個概念:當迴轉數為 0 時,點在閉合曲線外部。

圖源:http://www.html-js.com/article/1538

上面面這張圖動態演示了迴轉數的概念:圖中紅色曲線關於點(人所在位置)的迴轉數為 2。

對於給定的點和多邊形,迴轉數應該怎麼計算呢?

用線段分別連接點和多邊形的全部頂點

圖源:http://www.html-js.com/article/1538

計算所有點與相鄰頂點連線的夾角

圖源:http://www.html-js.com/article/1538

計算所有夾角和。注意每個夾角都是有方向的,所以有可能是負值

圖源:http://www.html-js.com/article/1538

最後根據角度累加值計算迴轉數。360°(2π)相當於一次迴轉。

在使用 JavaScript 實現時,需要注意以下問題:

JavaScript 的數只有 64 位雙精度浮點這一種。對於三角函數產生的無理數,浮點數計算不可避免會造成一些誤差,因此在最後計算迴轉數需要做取整操作。通常情況下,平面直角坐標系內一個角的取值範圍是 -π 到 π 這個區間,這也是 JavaScript 三角函數 Math.atan2() 返回值的範圍。但 JavaScript 並不能直接計算任意兩條線的夾角,我們只能先計算兩條線與 x 正軸夾角,再取兩者差值。這個差值的結果就有可能超出 -π 到 π 這個區間,因此我們還需要處理差值超出取值區間的情況。代碼實現:

如何判斷遊戲結果是否正確?

探索的過程固然精彩,而結果卻更令我們期待

通過前面的介紹我們可以知道,判斷遊戲結果是否正確其實就是比對玩家組合圖形的 xor 結果與目標圖形的 xor 結果。那麼如何求多個多邊形 xor 的結果呢?polygon-clipping 正是為此而生的。它不僅支持 xor 操作,還有其他的比如:union, intersection, difference 等操作。在層疊拼圖Plus遊戲內通過 polygon-clipping 又是怎樣實現遊戲結果判斷的呢?

目標圖形

多邊形平面坐標點集合:

獲取 多個多邊形 xor 結果:

xor結果:

同理計算出玩家操作圖形的xor結果進行比對即可得出答案正確與否。

需要注意的是,獲取玩家的 xor 結果並不能直接拿來與目標圖形xor 結果進行比較,我們需要將xor 的結果以左上角為參考點將圖形平移至原點內,然後再進行比較,如果結果一致,則代表玩家答案正確。

排行榜的展示

有人的地方就有江湖,有江湖的地方就有排行

在看本章節內容之前,建議先瀏覽一遍排行榜相關的官方文檔:好友排行榜、關係鏈數據,以便對相關內容有個大概的了解。

開放數據域開放數據域是一個封閉、獨立的 JavaScript 作用域。要讓代碼運行在開放數據域,需要在 game.json 中添加配置項 openDataContext 指定開放數據域的代碼目錄。添加該配置項表示小遊戲啟用了開放數據域,這將會導致一些限制。

在遊戲內使用 wx.setUserCloudStorage(obj) 對玩家遊戲數據進行託管。在開放數據域內使用 wx.getFriendCloudStorage(obj)拉取當前用戶所有同玩好友的託管數據展示關係鏈數據如果想要展示通過關係鏈 API 獲取到的用戶數據,如繪製排行榜等業務場景,需要將排行榜繪製到 sharedCanvas 上,再在主域將 sharedCanvas 渲染上屏。

sharedCanvas 是主域和開放數據域都可以訪問的一個離屏畫布。在開放數據域調用 wx.getSharedCanvas() 將返回 sharedCanvas。

在主域中可以通過開放數據域實例訪問 sharedCanvas,通過 drawImage() 方法可以將 sharedCanvas 繪製到上屏畫布。

sharedCanvas 本質上也是一個離屏 Canvas,而重設 Canvas 的寬高會清空 Canvas 上的內容。所以要通知開放數據域去重繪 sharedCanvas。

需要注意的是:sharedCanvas 的寬高只能在主域設置,不能在開放數據域中設置。

遊戲性能優化

性能優化,簡而言之,就是在不影響系統運行正確性的前提下,使之運行地更快,完成特定功能所需的時間更短。

一款能讓人心情愉悅的遊戲,性能問題必然不能成為絆腳石。那麼可以從哪些方面對遊戲進行性能優化呢?

離屏 Canvas

在層疊拼圖Plus小遊戲內,針對需要大量使用且繪圖繁複的靜態場景,都是使用離屏 Canvas進行繪製的,如首頁網格背景、關卡列表、排名列表等。在微信內 wx.createCanvas() 首次調用創建的是顯示在屏幕上的畫布,之後調用創建的都是離屏畫布。初始化時將靜態場景繪製完備,需要時直接拷貝離屏Canvas的圖像即可。Canvas 繪製本身就是不斷的更新幀從而達到動畫的效果,通過使用離屏 Canvas,就大大減少了一些靜態內容在上屏Canvas的繪製,從而提升了繪製性能。

內存優化

玩家在遊戲過程中拖動方塊的移動其實就是不斷更新多邊形圖形的坐標信息,然後不斷的清空畫布再重新繪製,可以想像,這個繪製是非常頻繁的,按照普通的做法就需要不斷去創建多個新的 Block 對象。針對遊戲中需要頻繁更新的對象,我們可以通過使用對象池的方法進行優化,對象池維護一個裝著空閒對象的池子,如果需要對象的時候,不是直接new,而是從對象池中取出,如果對象池中沒有空閒對象,則新建一個空閒對象,層疊拼圖Plus小遊戲內使用的是官方demo內已經實現的對象池類,實現如下:

垃圾回收

小遊戲中,JavaScript 中的每一個 Canvas 或 Image 對象都會有一個客戶端層的實際紋理儲存,實際紋理儲存中存放著 Canvas、Image 的真實紋理,通常會佔用相當一部分內存。

每個客戶端實際紋理儲存的回收時機依賴於 JavaScript 中的 Canvas、Image 對象回收。在 JavaScript 的 Canvas、Image 對象被回收之前,客戶端對應的實際紋理儲存不會被回收。通過調用 wx.triggerGC() 方法,可以加快觸發 JavaScriptCore Garbage Collection(垃圾回收),從而觸發 JavaScript 中沒有引用的 Canvas、Image 回收,釋放對應的實際紋理儲存。

但 GC 具體觸發時機還要取決於 JavaScriptCore 自身機制,並不能保證調用 wx.triggerGC() 能馬上觸發回收,層疊拼圖Plus小遊戲在每局遊戲開始或結束都會觸發一下,及時回收內存垃圾,以保證最良好的遊戲體驗。

多線程 Worker

對於遊戲來說,每幀 16ms 是極其寶貴的,如果有一些可以異步處理的任務,可以放置於 Worker 中運行,待運行結束後,再把結果返回到主線程。Worker 運行於一個單獨的全局上下文與線程中,不能直接調用主線程的方法,Worker 也不具備渲染的能力。Worker與主線程之間的數據傳輸,雙方使用 Worker.postMessage() 來發送數據,Worker.onMessage() 來接收數據,傳輸的數據並不是直接共享,而是被複製的。

需要注意的是:Worker 最大並發數量限制為 1 個,創建下一個前請用 Worker.terminate() 結束當前 Worker

其他 Worker 相關的內容請參考微信官方文檔:多線程 Worker

結語

短短的一篇文章,定不能將層疊拼圖Plus小遊戲的前前後後講明白講透徹。其實最讓人心累的還是軟著的申請過程,由於各種原因前前後後花了將近三個月的時間,後續可以給大家分享軟著申請相關的內容,希望可以幫助到需要的童鞋。

江湖不遠,我們遊戲裡見!

作者簡介:huangjianke,高級iOS開發/前端開發工程師,五年開發經驗。

需要體驗小遊戲的童鞋可在微信小程序搜索層疊拼圖Plus。

相關焦點

  • 用HTML5把Canvas緩衝區內容輸出到屏幕
    【IT168技術】歡迎來到我的HTML5遊戲編程小教程。我會儘量簡要說明如何使用HTML5 canvas元素和JavaScript創建簡單的遊戲。本教程將省略一些代碼,但絕非故意。您可以隨時查看我的遊戲演示。
  • 燒腦科幻解謎3D手遊《超級立方體》即將上架
    相信很多玩家肯定看過一部叫《盜夢空間》的電影,對片中那些燒腦的劇情留下了非常深刻的印象。最近有一款新遊《亞空間轉移(Warp Shift)》與這種燒腦影片十分相似,只不過在風格上顯得平易近人了許多,大家可以一起來了解一下。
  • 燒腦!JS+Canvas 帶你體驗「偶消奇不消」的智商挑戰
    本文原載於 SegmentFault 專欄 一個會小程序開發的iOSer 作者:huangjianke整理編輯:SegmentFault啟邏輯之高妙,因想像而自由層疊拼圖Plus 是一款需要空間想像力和邏輯推理能力完美結合的微信小遊戲。
  • 小遊戲大燒腦 《數字密語》開啟學霸模式
    《數字密語》是一款燒腦型的智力闖關小遊戲,移動指尖,重溫加減乘除的魅力!數字大作戰,這遊戲的燒腦程度,根本停不下來!小清新畫風,數字虐心畫風治癒!好友智商大排行,原來群裡竟然有一個隱藏的絕世高手!小遊戲大燒腦雖然畫風是走的是治癒風格,但是《數字密語》的關卡難度,有的時候可不是那麼小清新的哦。
  • 假期燒腦小清新遊戲 你玩過第一個麼?
    有句話說,遊戲與放假共存。所以今天小編要把自己的箱底跟大家分享下,一款很燒腦的小清新的3D遊戲,小編玩上後就無法自拔咯~大家小時候一定有用手投影動物吧,可憐小編只會大雁,所以覺得這樣的光影效果很是炫酷阿,還有點像皮影戲,小編建議要戴著耳機玩,因為音效超棒的哦!哦,對了,這貨叫《Shadowmatic》。
  • Kerbal Space Program一款特殊的燒腦Game你喜歡嗎?
    Kerbal Space Program一款特殊的燒腦Game你喜歡嗎?Kerbal Space Program確實是個很好的遊戲。接著我和大家談談我的體會,我姑且也算是一個KSP老玩家了(從0.21一直到現在1.4),從最開始的「宰人航天」變成「殖民航天」(滑稽)。
  • html5 canvas畫布繪製矩形和圓形
    html5為我們提供了非常有特色的標籤,canvas標籤為我們可以實現在網頁中畫畫提供了便利,接下來我們列舉他的常用操作。新建一個html5的文檔,建立一個canvas畫布,設置長寬,這裡需要特別注意,canvas標籤可以在標籤內設置width,height,也能通過css來設置,但是通過css來設置的標籤,當繪製圖形的時候會變形,所以我們建議直接在標籤內設置。
  • 使用HTML5和Javascript設計繪圖程序
    【IT168 專稿】前言  在本文中,將會介紹如何使用HTML5和Javascript去設計一個簡單的繪圖程序。HTML5的一個新的特性是canvas畫布功能,通過canvas畫布的強大功能可以實現繪畫不少圖形和其他絢麗的功能。
  • PS上最燒腦解謎遊戲,生化危機靠邊站,結局神反轉細思極恐
    PS上最燒腦解謎遊戲,生化危機靠邊站,結局神反轉細思極恐 說到Playstation上最出色的解謎類遊戲
  • 50個實用的JavaScript工具
    新的替代JavaScript和Ajax的開發框架  Clean AJAX  Clean一個開源的Ajax引擎,一組簡化AJAX開發的高級接口。此處Clean還集成兩個開源項目Google AJAXSLT:為Clean添加XSLT支持。
  • 玩的就是智商 盤點好玩燒腦的解謎類遊戲
    解謎遊戲是一類通過對遊戲中出現的信息或情節進行分析和處理,發掘線索解決各種謎題的益智健腦遊戲。下面給大家推薦幾款好玩燒腦的解謎類遊戲,希望大家能喜歡。1.不過,Machinarium遊戲時間將更長更複雜,這次畫面將由手畫,而玩家有個小物品欄。本遊戲在2009年獨立遊戲節上斬獲了視覺藝術獎。3.
  • 《我在七年後等著你》,「燒腦」遊戲,也是催淚遊戲
    本文原創侵權必究《我在七年後等著你》,「燒腦」遊戲,也是催淚遊戲因為世界上總是充滿了各種遺憾,所以時光倒流這個設定備受青睞,而這款幾乎沒有什麼可玩性的遊戲卻把它運用到了極致,單一的簡單操作,簡單的像素畫風和普通的
  • 聊聊半衰期-艾利克斯:如何開發一款優秀VR遊戲
    編輯導語:艾利克斯,是一款第一人稱線性冒險遊戲,一共有11章節近30小時的遊戲時長。遊戲畫面強到令人髮指,流程各種高能震撼不斷,堪稱VR遊戲教科書,其中革命性的操作設計更是讓遊戲獲得了驚世駭俗的沉浸感。今天,本文作者為我們分析了艾利克斯,總結了應該如何開發一款優秀的VR遊戲?
  • 編程遊戲開發:如何開發製作一款遊戲?你需要做哪些準備?
    關於遊戲開發,需要對從一開始到最後開發一款遊戲的一般過程有所了解。一般不是一個完整的,一步一步的指導完成的結果。你還需要自己找出相當多的東西才能有一個遊戲。
  • IBM發布相當燒腦的Hello Quantum量子比特遊戲
    IBM發布相當燒腦的Hello Quantum量子比特遊戲2018-07-24 11:58出處/作者:cnBeta.COM整合編輯:黑目責任編輯:廖俊輝 儘管量子計算已經成為了當前的一項研究熱門,但是對於普通人來說,想要理解它的工作原理,並不是一件容易的事情。
  • HTML 5 Canvas 遞歸畫樹
    上圖就是用html5隨機生成的大樹 : ) 但是你應該沒想到40+行代碼就可以搞定了吧~接下來就跟大家說說這棵大樹是如何實現的。同樣必須要有html容器。新建Index.html,代碼如下:<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>canvas tree</title> </head> <body> <script
  • 《地獄之刃》開發復盤:如何用有限的預算做一款獨立3A遊戲
    Ninja Theory此前曾向發行商展示一款代號為Razer的「大型服務型遊戲」的項目原型,但該作未能獲得發行商的支持。馬修斯和開發團隊發現隨著行業的變化,Ninja Theory之類的中等規模工作室的生存空間變得越來越狹窄。
  • 燒腦系微信小遊戲 《數字密語》勇闖智力關卡
    自微信小遊戲閃亮登場以來,大家是不是已經被種類繁多的小遊戲們,撩的眼花繚亂了呢?今天,就為大家隆重介紹一款風格獨樹一幟的,燒腦型微信小遊戲《數字密語》!不同於其他的微信小遊戲,《數字密語》在休閒風格的基礎上,還加入了智力闖關的遊戲元素。巧妙的玩法展現了遊戲精巧而優美的關卡設計。
  • AppStore每周新遊:這款奇特的遊戲用遊戲來講述了遊戲的進化歷程
    《進化之地2》《進化之地2》是一款RPG遊戲,講述了遊戲的變化歷程。在遊戲中,你將踏入超過20小時的史詩般冒險,走過電子遊戲的歷史,這裡充滿了許許多多有趣的經典遊戲劇情。玩家需要操控可愛的UFO,用它的機器爪完成如農場搬運貨物、支援啦啦隊的女孩子們、在餐廳製作上好的甜品等各種有趣的工作賺取酬勞,達成目標後還要保持一小段時間平衡才算成功。UFO很可愛,任務設計也很有腦洞。玩家還可以堆出腦洞大開或者充滿藝術感的形狀,再配合著歡快的「働~く~UFO~」的BGM,十分魔性。,可玩性較高,就是有部分閃退問題。
  • 又一款學習洛克人點陣遊戲《超級神力俠》開眾籌
    又一款學習洛克人點陣遊戲《超級神力俠》開眾籌 時間:2017-11-21 07:28:20