用html5 canvas和JS寫個數獨游戲


為啥要寫這個游戲?

  1. 因為我兒子二年級數字下冊最后一章講到了數獨。他想玩兒。
  2. 因為我也想玩有提示功能的數獨。
  3. 因為我也正想決定要把HTML5和JS搞搞熟。熟悉一個編程平台,最好的辦法,就是了解其原理與思想之后,做個真正完整的東西練練。

之前一直搞.net,后來管理事務多了,很多技術就沒跟上,看過一些JS的書,但一直沒動手,前幾個月,寫了第一個JS程序,是一個簡單的產品規則引擎,利用v8引擎集成在.net程序中,用腳本來處理產品費用有關的計算。但那個只涉及數值計算。

這幾天因為兒子的課本上學邏輯推理,有個數獨游戲,兒子大感興趣,玩了幾個,想到如果能自動計算可選數字的話,就會很容易解開數獨,在網上找來找去,發現都沒有這樣功能的數獨。正好有點空閑,就決定自已寫一個。

所以這個數獨是我寫的第二個JS程序。在寫的過程中也在同時學習。

幾個要點

canvas與windows的圖形程序原理的不同

一開始,免不了受之前經驗的影響,想用winform的圖形程序原理來處理html5 canvas的繪圖。但發現有點水土不服:windows的圖形程序原理是說系統不管保存程序自己窗口里內容,有需要顯示時——比如從后台切到前台啦、剛從別的程序下面露出臉來啦等等——就請程序自己再畫一遍。所以,程序只需要重寫form的OnPaint方法(對於win32程序,則是響應WM_PAINT消息),在其中繪制圖形就行了。

在windows程序中,不能直接隨時向窗口上畫圖,比如你想在鼠標點擊時畫個點,但你沒法在鼠標或鍵盤事件的響應方法中得到窗口的繪圖上下文句柄(對winform,是Graphics參數,對於win32程序是WM_PAINT消息里的某個參數),於是,你只好記下來“現在有個家伙點了鼠標了,某某地方應該有個點!”,然后調用Invalidate()方法,這個方法會強制系統向窗口程序發重繪消息,然后,你事先准備好的OnPaint方法被調用,在這個方法里,你有機會得到繪圖句柄了,於是你檢查之前有沒有記錄過要在某個地方畫點的,並在這個地方畫個點。

有點像MVC的意思,哈?

但在html5的canvas中,我發現瀏覽器是會幫canvas保存圖形的,無論是被其他窗口蓋到,切到后台,都沒問題,只要一露出到屏幕上,原來的圖形就還是在那里。這表示只要你並不想做動畫效果,用canvas寫圖形程序要比windows程序原理更簡單一些:你只要在合適的時候(鼠標點擊、鍵盤事件等)向canvas上畫圖就是了,畫上的東西就會總是在那里。繪圖上下文context也不會消失掉,我把它在一開始時做為構造方法的參數傳入,並保存為類成員,隨時用隨時取。

唯一要注意的,是要快點畫完,別占太長時間。

滾屏后座標的問題

從網上看到的代碼都是用e.pageXY來得到位置的。這個位置是鼠標事件在整個文檔中的絕對位置。也就是說,滾屏不會影響這個值。

只不過我用了getBoundingClientRect這個方法來取得canvas對應的box座標,用於把全局座標轉換到canvas內的座標。而這個方法取得的座標是相對於瀏覽窗口的,而不是相對於整個文檔的。這就與e.PageXY對不上了。

所以,這里只好用e.XY,工作得非常好。

支持Retina屏

一開始在一個舊筆記本上寫的這個程序,運行得挺好,但放到MacBook Pro上一看,功能挺正常,但內容很模糊。

仲么辦!

模糊的原理是canvas在瀏覽器中的大小是由style中的width與height來決定的,但其畫布的大小是以canvas.width與height決定的。如果兩者不一樣大,就會進行拉伸縮放,把畫布拉伸(或縮小)到style的大小。

在普通屏幕上,其style定義的像素大小與屏上的顯示結果是一對一的,所以沒問題。但在retina屏上,style的大小定義與屏幕上的像素大小是有個放大比例的(在MBP上,是2),也就是說,style定義的400px,顯示時會用到800px個屏幕像素。但由於canvas里畫布的大小是400px的,所以內容被拉伸,還自動消除了鋸齒,看起來就很模糊。

所以,解決辦法是就是:根據放大比例,把畫布的大小設置為比外部大小更大的大小。

但是注意,鼠標器事件中的座標是按原點數值來提供的。比如說,你內部畫布大小是800px, 但屏幕大小算成了400px, 當鼠標點擊后,給的位置是(100,100),這個位置是按屏幕點數來計算的,要在畫布中計算其對應的點,應該把這個值乘以那個放大系數才對。

可注意一下程序中的getPointOnCanvas函數。

源代碼在: https://github.com/haoxiaobo/SudoJS


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM