本次的分享是一個基於jQuery實現的一個移動端射箭類小遊戲。主要實現了目標物、障礙物的隨機渲染,以及中箭效果的斷定等。
歡迎關注個人博客,不按期更新中——css
點我查看源碼倉庫。git
...
//基礎屬性
defaultOption = {}
//繪製總體畫面
function drawGame(defaultOption){}
//障礙物、目標物類
function Hinder(){}
Hinder.prototype.xxx
function Target(){}
Target.prototype.xxx
//循環渲染
function eventLoopHinder(){}
function eventLoopTarget(){}
//過時去除障礙物、目標物
function clearHinder(){}
function clearTarget(){}
//觸摸射箭事件監聽
function touchEvent(){}
...複製代碼
經過以上的結構劃分及效果圖的展現咱們能夠大概瞭解到,這個遊戲主要涉及的三個較爲關鍵的地方就是:github
故接下來做者會介紹下實現思路,至於具體細節有興趣的同窗能夠在issues下交流。web
對於目標物做者用了下面的類來表示:canvas
//如下代碼只做爲例子說明,與源碼有較大刪改
//爲了方便表示 random 爲一個假想的隨機值
function Target(id, nowTime, width, score, x, y, time) {
this.id = id //id即惟一標示
this.nowTime = nowTime //當前時間
this.score = score //表明分數
this.width = width || random // 可隨機一個寬度
this.x = x || random //可隨機一個x座標
this.y = y || random //可隨機一個y座標
this.time = time || random //可隨機一個過時時間
}複製代碼
在上面的示例代碼中咱們能夠知道,經過new Target()能夠獲得一個位置隨機,大小隨機,過時時間等等均爲隨機的一個目標物。固然這個隨機做者在代碼中作過限定,都是在一個特定的範圍內隨機出來的。那麼在這期間惟一須要咱們控制的,應該就是出現的位置了,爲何這麼說呢,由於出現的位置不該該重合。而若是隻憑這個類中的屬性來部署目標物,勢必會各類重合。數組
簡單看下實現過程:bash
//targetArray爲存放目標物對象的數組,每次new出實例後均會放入該數組
Target.prototype.draw = function(newTarget) {
var img = new Image(),
...
img.onload = function() {
...
targetArray.forEach(function(obj, index) {
var x = obj.x - newTarget.x,
y = obj.y - newTarget.y,
dis = Math.sqrt(x*x + y*y)
if(dis < newTarget.width / 2 + obj.width / 2) {
isOk = false //那麼這個對象就不要渲染了
}
if(isOk) {
//渲染該對象到dom
}
})
...
}
}
var newTarget = new Target(id, nowTime, width, scoreTarget)
newTarget.draw(newTarget)複製代碼
當new出一個目標物後,在調用draw方法時將其傳入到方法中。以後遍歷存放目標物對象的數組,暫且將目標物想象成圓,經過兩圓圓心距離與半徑之和的比來斷定要不要將其插入dom節點進行展現。若是童鞋們想要更精確的檢測「碰撞」的方式,能夠將遊戲在canvas畫布中進行實現。canvas中getImageData
方法能夠獲取圖像的像素點,經過兩對象其像素點是否重合能夠更爲精準的判斷。dom
關於障礙物的飛行採用了css中的transition來進行控制:oop
function setTransition(property, timing, speed) {
return {
'transition-property': property,
'-moz-transition-property': property,
'-webkit-transition-property': property,
'-o-transition-property': property,
'transition-timing-function': timing,
'-moz-transition-timing-function': timing,
'-webkit-transition-timing-function': timing,
'-o-transition-timing-function': timing,
'transition-duration': speed + 's',
'-moz-transition-duration': speed + 's',
'-webkit-transition-duration': speed + 's',
'-o-transition-duration': speed + 's',
}
}
Hinder.prototype.draw = function() {
var img = new Image(),
...
img.onload = function() {
...
$(img).css(setTransition('left', 'linear', this.speed))
...
}
}複製代碼
經過一個較通用的方法返回一個可配置的transition動畫對象,在障礙物類的原型方法中動態改變其css樣式,其中動畫的持續時間設定爲障礙物的速度屬性。這樣來達到每一個新生成的障礙物有着不一樣的飛行速度。動畫
因爲整個遊戲會一直跑循環來快速的生成新的目標和障礙物。同時會維護一個存儲目標和障礙物對象的數組,當有需求如碰撞檢測時須要遍歷整個數組。那麼這麼操做就意味着咱們的數組不能太大否則會極大地佔用內存。同時當障礙物移出屏幕後理應清理掉這個節點,釋放內存。故做者用兩個定時器來跑兩個檢測對象過時的方法:
function clearTarget() { //清理過時目標
var nowTime = new Date().getTime()
targetArray.forEach(function(item, index) {
if(item.time + item.now < nowTime) {
//當生成對象時間+持續時間 > 當前時間即爲過時
$('#' + item.id).remove()
targetArray.splice(index, 1)
}
})
targetTimer = setTimeout(clearTarget, xxx)
}
function clearHinder() { //清理過時障礙
hinderArray.forEach(function(item, index) {
if(item.shot) {
if('障礙物移出屏幕') {
$('#' + item.id).remove()
hinderArray.splice(index, 1)
}
}
})
setTimeout(clearHinder, xxx)
}複製代碼
一樣是採用粗略計算,採用弓箭的中心點和目標物/障礙物水平線兩側的點,以下圖的(X2, Y2)的連線,與水平線的夾角來判斷。
//yMax, yMin, xMax, xMin 爲方便展現使用。具體數值從上圖能夠很快求出
Target.prototype.angle = function() {
var anglemax = Math.atan2(yMax, xMax)
var anglemin = Math.atan2(yMin, xMin)
function angleCal(angle) { //轉化爲°數
return (angle / Math.PI * 180) < 0 ? angle / Math.PI * 180 - 90 : angle / Math.PI * 180
}
var angleMax = angleCal(anglemax)
var angleMmin = angleCal(anglemin)
return {
max: angleMax,
min: angleMmin
}
}複製代碼
需注意的是裏面使用了Math.atan2(y, x)方法。注意裏面參數順序哦=。=
不知道嘗試了這個遊戲的童鞋有沒有注意到,當點擊了某一個方向後,箭會順着這個方向射出,而且會沿途判斷有沒有射中什麼東西,若是射中了那麼就要停在那個對象身上,沒射中就無所謂了。那麼這一點的實現咱們就不能是使用如目標物身上綁定監聽事件來解決了。那麼如今再來看這個圖:
本次本來打算採用canvas來作這個遊戲,可是初步嘗試以後發現可能因爲繪製得太頻繁,手機顯示出來效果實在是。。固然也由於做者對這種小遊戲的實現經驗不足。只借此分享一個小case,歡迎指正。
慣例po做者的博客,不定時更新中——有問題歡迎在issues下交流,捂臉求star=。=