Cocos多邊形點選和解數獨

語言: CN / TW / HK

前言: 本文記錄了Cocos多邊形點選的兩種實現方式,和解數獨過程中的優化和思考。

01

Cocos多邊形點選

背景:正在用cocos做一個七巧板拼圖小遊戲,成品效果如下~

由於cocos提供的節點點選事件只支援矩形,這種模式下七巧板中的三角形實際點選區域是個矩形,表現就是視覺上沒有點到三角形卻響應了點選事件,嚴重影響體驗,所以需要優化點選區域的判斷

我總結了下面兩種方法:

  • 方法1:畫素透明度判斷

觀察三角形圖片發現:圖片分為三角形顯示區域和透明區域,需要響應點選的是顯示區域,只需要判斷出是否是透明區域即可。

判斷方法如下:將點選座標轉換為圖片對應畫素點,獲取畫素點alpha值進行判斷:

   /**
* 檢查點選位置的畫素alpha值,檢查閾值OPACITY
* @param x
* @param y
* @returns 是否不透明
*/
checkHit(x: number, y: number) {
let sprite = this.node.getComponent(Sprite);
if (!sprite) {
return false
}
let texture = <Texture2D>sprite.spriteFrame.texture;
// 3.x
let data = <HTMLImageElement>texture.image.data
// 2.x
// let data = texture.getHtmlElementObj();


let cvs = document.createElement("canvas");
let ctx = cvs.getContext("2d");
cvs.width = 1;
cvs.height = 1;
ctx.drawImage(data, x, y, 1, 1, 0, 0, 1, 1);
// 獲取畫素資料
let pxData = ctx.getImageData(0, 0, 1, 1).data;
console.log(pxData)
return pxData[3] > OPACITY;
}




  • 方法2:使用PolygonCollider2D元件

上圖是PolygonCollider2D元件根據圖片透明度自動圈出的多邊形頂點

通過判斷點選位置是否在多邊形內來判斷點中,這種方法更靈活,允許開發者手動修改點選區域,適用範圍更廣。

多邊形和點的位置關係判斷有一個簡單高效的方法:射線法,該演算法思想是從點出發向右水平做一條射線,計算該射線與多邊形的邊的相交點個數,當點不在多邊形邊上時,如果是奇數,那麼點就一定在多邊形內部,否則,在外部。最重要的是這個演算法也適用於凹多邊形。

 /**
* 檢測點選位置是否在多邊形內
* @param event 點選事件
* @returns
*/
checkHitPoly(event:EventTouch) {
let targetPos = event.touch.getUILocation();
let poly = this.node.getComponent(PolygonCollider2D)
if (!poly) {
return false;
}
let count = 0;
// 獲取多邊形的頂點,有序
let arrPoints = poly.worldPoints;
for (let i = 0; i < arrPoints.length; i++) {
let point1 = arrPoints[i];
let point2 = arrPoints[0];
if (i != arrPoints.length - 1) {
point2 = arrPoints[i + 1];
}
// 兩點y值差包含目標點的入選
if (point1.y < targetPos.y && point2.y > targetPos.y || point1.y > targetPos.y && point2.y < targetPos.y) {
let t = (targetPos.y - point1.y) / (point2.y - point1.y);
let xt = point1.x + t * (point2.x - point1.x);
// 在邊上,返回true
if (targetPos.x == xt) return true;
// 目標點向右射線與邊相交,加計數
if (targetPos.x < xt) ++count;
}
}
// 相交變數為奇數,在多邊形內
return count % 2 == 1
}




02

解數獨

另一個小遊戲是數獨,數獨規則很簡單,在9 * 9的表格內填入1 ~ 9使得行、列、宮內沒有重複數字, 像這樣~

這個遊戲的難點是題目的來源,數獨題目的質量很重要,所以我們選了專業的數獨書籍,從中摘取題目。

但是有個問題,怎麼檢查有沒有錄錯,即使不錄錯怎麼檢查原題目有且僅有唯一解。

人為檢驗不靠譜,那就寫個指令碼檢測下吧

第一步:初始化資料

其中this.rows每一行已使用數字應該是一個二維陣列,宣告一個一維陣列怎麼存的下呢?答案是未壓縮。

需要儲存的資料是9行,每行9個數字是否已使用,可以使用長度為9的陣列表示9行,每個元素用9位二進位制表示該行9個數字的使用情況,這樣二維降為一維

第二步:根據題目,填充資料

儲存空格子的set this.emptys同理this.rows,用一個8位2進製表示行列,左四位表示行,右四位表示列

第三步:解題

本步驟就是深度遍歷找可行解,找到一個之後可行解數量加一,由於要判斷是不是唯一解所以此時並不會結束而是回溯繼續找其他可行解。

解數獨技巧中有一項是從缺少數字最少的行、列、宮入手,這個技巧也可以加到程式中,就是每次選取空格子的時候選擇待嘗試解最少的格子,這個技巧與後續加入自動講解功能相契合。

指令碼完成,跑一下400關數獨可行解的數量:

結果顯示有29個關卡不符合唯一解,其中有錄入錯誤的,也有題目本身就不是唯一解的,定位題目重新錄入問題解決。

解個數獨用這麼花裡胡哨嗎?直接暴力法不就解決了嗎?

  1. 這個解數獨的方法不是隻用於查錄入錯誤,還要用到數獨小遊戲的自動解題和講解,有優化的必要性。

  2. 跑了一下暴力法,部分題目執行不通過,報JavaScript heap out of memory,更加印證了優化的必要性。

掃描下方二維碼新增 「好未來技術」 微信官方賬號

進入好未來技術官方交流群與作者實時互動~

(若掃碼無效,可通過微訊號 TAL-111111 直接新增)

- 也許你還想看 -

Web類系統的測試保障體系

Web 效能優化實戰之海外分校官網效能優化

場景編排技術模型

我知道你“在看”喲~