[ロジックトレーニング]JavaScriptで小さなゲームを作る--2048(詳細版)
9353 ワード
前言今回はvueを用いて2048を記述し、主な目的はvueを復習することである. でもあまりvueのものは使われていないようです==!フレームワークを使わないことに慣れたかもしれません. 以前は時間の関係で実現過程について詳しく説明していなかったが、今回は比較的周回した関数 について詳しく説明する.紙面問題の簡単な関数のため詳しく説明しません コードアドレス:https://github.com/yhtx1997/S...
実装機能デジタル統合 現在の合計スコア計算 移動可能な数字がない場合は何もしない は移動可能ではなく、マージ可能な数字であり、新規作成できない場合は にゲームが失敗する. 2048ゲーム終了 使用する知識 ES6 vue部分テンプレート構文 vueライフサイクル 配列メソッド reverse() push() unshift() some() forEach() reduceRight()
数学の方法 Math.abs() Math.floor()
具体的な実装上下操作を左右操作 に変換する必要があるかどうか.データ初期化 連結数字 操作が無効か否かを判断する .ページ にレンダリング乱数 合計 を計算判断成功 判断失敗 全体の流れは以下の通りです
初期化
まずは基本的なHTMLタグとCSSスタイルを書きます
vueを使うのでhtml部分をレンダリングするコードは手書きで書く必要はありません
cssは长すぎて放さない前とほとんど変わらない
次はデータの初期化です
初期化を行うとこのような効果が得られるはずです
イベントリスニングの追加
mountedでのイベントリスニングの追加
なぜmountedにイベントを追加しますか?まずvueのライフサイクルについてお話しします beforeCreateインスタンスの作成前にこの段階で書いたコードはまだ 実行されていません. createdインスタンスの作成後、この段階で私たちが書いたコードはすでに実行されていますが、HTMLはページ にレンダリングされていません. mountedマウント後、この段階でhtmlがページにレンダリングされ、domノード に取得できます. beforeUpdateデータの更新前にhtmlを再レンダリングする必要がある前に同様の実行warpを呼び出す.innerHTML = html; 前の updatedデータ更新後HTML再レンダリング後に を呼び出す. destroyedインスタンス破棄後呼び出し私たちが書いたコードを破棄した後呼び出し errorCaptured子孫コンポーネントからのエラーをキャプチャするときに呼び出される2.5.0+ 追加注:私たちが書いたコードはただの代指で、理解しやすいように、私たちが書いたコード を指しているわけではありません.
だから早すぎるとdomノードが見つからないかもしれないし、遅すぎるとイベントの応答が最初にできないかもしれない.
操作を左右のみに簡略化
このコードは私はある日半夢半醒して考えたので、思考が好転しないかもしれません.コードの下の図を見てもいいです.
これにより、上向きの操作を左の操作、下向きの操作に変換して右の操作に変換します.
変換コード
データ初期化配列のうちの0はこの小作では占位としてのみ使用され、ゴミデータとみなされるため、開始前に処理する必要があり、終了後に を加える.の2つのデータフォーマットで、1つは詳細情報を含むもので、いくつかの判断に使用されます.1つは純粋な数字の2次元配列であり、その後、新しいレンダリングページ から使用される.
無効かどうかを判断するは、2つの数字の間に隙間があるかどうかを判断する 数字が一番端にあるかどうかを判断する これにより,基本的な判断が有効であるかどうか,失敗したかどうかの条件が得られ,データ初期化時にマージ可能な数字が得られたかどうかが得られる.
今ではすべてのデータがそうであるべきです
レンダリングページランダム空白に作成する数字 ここでは以前は再帰関数の形で判断していましたが、再帰関数を使うと多くの問題があり、最大の問題はスタックオーバーフローやカードダウン(再帰関数は関数の最後に自分を呼び出し、returnの条件を与えなければスタックオーバーフローやカードダウンしやすい)の可能性があるので今回は抽選モードに変更し、すべての空席の座標を取って、1つの配列に入れて、それからこの配列のランダムな下付きを取って、このように私達は1つの空席の座標を得ることができて、それから更にこの空席に対して処理します
以上が今回の2048の主なコードの最后に、ランダムに4が现れる确率は私が比较的に大きいため、それに応じていくつかの难易度を下げて、具体的にはすべての数字が左(最辺の上)に现れて、しかも数字と数字の间に隙间がなくて、更に左を押しても数字を生成します
実装機能
具体的な実装
command (keyCode) { //
this.WhetherToRotate(keyCode) //
this.Init() //
this.IfInvalid() //
this.Rendering(keyCode) //
}
初期化
まずは基本的なHTMLタグとCSSスタイルを書きます
vueを使うのでhtml部分をレンダリングするコードは手書きで書く必要はありません
: {{this.total}} // {{}} JavaScript
// v-for , arr.length
{{item>0?item:''}} // :class= JavaScript
cssは长すぎて放さない前とほとんど変わらない
次はデータの初期化です
data () {
return {
arr: [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], //
Copyarr: [[], [], [], []], //
initData: [], //
haveGrouping: false, //
itIsLeft: false, // ,
endGap: true, //
middleGap: true, //
haveZero: true, // 0
total: 0, //
itIs2048: false, //
max: 2048 //
}
}
初期化を行うとこのような効果が得られるはずです
イベントリスニングの追加
mountedでのイベントリスニングの追加
なぜmountedにイベントを追加しますか?まずvueのライフサイクルについてお話しします
だから早すぎるとdomノードが見つからないかもしれないし、遅すぎるとイベントの応答が最初にできないかもしれない.
mounted () {
window.onkeydown = e => {
switch (e.keyCode) {
case 37:
// ←
console.log('←')
this.Command(e.keyCode)
break
case 38:
// ↑
console.log('↑')
this.Command(e.keyCode)
break
case 39:
// →
this.Command(e.keyCode)
console.log('→')
break
case 40:
// ↓
console.log('↓')
this.Command(e.keyCode)
break
}
}
}
操作を左右のみに簡略化
このコードは私はある日半夢半醒して考えたので、思考が好転しないかもしれません.コードの下の図を見てもいいです.
これにより、上向きの操作を左の操作、下向きの操作に変換して右の操作に変換します.
WhetherToRotate (keyCode) { //
if (keyCode === 38 || keyCode === 40) { // 38 40
this.Copyarr = this.ToRotate(this.arr)
} else if (keyCode === 37 || keyCode === 39) { // 37 39
[...this.Copyarr] = this.arr
}
//
if (keyCode === 37 || keyCode === 38) { //
this.itIsLeft = true
} else if (keyCode === 39 || keyCode === 40) {
this.itIsLeft = false
}
}
変換コード
ToRotate (arr) { // x y y x
let afterCopyingArr = [[], [], [], []]
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
afterCopyingArr[i][j] = arr[j][i]
}
}
return afterCopyingArr
}
データ初期化
Init () { //
this.initData = this.DataDetails() //
this.Copyarr = this.NumberMerger() //
}
無効かどうかを判断する
IfInvalid () { //
//
this.MiddleGap() //
this.EndPointGap() //
}
MiddleGap () { //
// , x 1 ,
// x
let subarr = [[], [], [], []] //
let sumarr = [] //
this.initData.forEach((items, index) => {
items.forEach((item, i) => {
if (typeof items[i + 1] !== 'undefined') {
subarr[index].push(item.col - items[i + 1].col)
}
})
})
//
subarr.forEach((items) => {
sumarr.push(items.reduceRight((a, b) => a + b, 0))
})
sumarr = sumarr.map((item, index) => Math.abs(item / subarr[index].length))
// 1
sumarr.some(item => item > 1)
this.middleGap = sumarr.some(item => item > 1) //
}
EndPointGap () { //
//
this.endGap = true
let end
let initData = this.initData
if (this.itIsLeft) {
end = 0
this.endGap = initData.some(items => items.length !== 0 ? items[0].col !== end : false)
} else {
end = 3
this.endGap = initData.some(items => items.length !== 0 ? items[items.length - 1].col !== end : false)
}
// x
//
//
//
}
今ではすべてのデータがそうであるべきです
レンダリングページ
Rendering (keyCode) {
this.AddZero() //
//
if (keyCode === 38 || keyCode === 40) { // 38 40
this.Copyarr = this.ToRotate(this.Copyarr)
}
if (this.haveGrouping || this.endGap || this.middleGap) { //
this.RandomlyCreate(this.Copyarr)
} else if (this.haveZero) {
//
} else {
// ,
if (this.itIs2048) { // 2048
this.RandomlyCreate(this.Copyarr)
alert(' 2048!')
//
// this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
// this.RandomlyCreate(this.arr)
} else { //
this.RandomlyCreate(this.Copyarr)
alert(' !')
// this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
// this.RandomlyCreate(this.arr)
}
}
if (this.itIs2048) { // , 2048
this.RandomlyCreate(this.Copyarr)
alert(' 2048!')
// this.arr = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]
// this.RandomlyCreate(this.arr)
}
}
RandomlyCreate (Copyarr) { //
//
let max = this.max
let copyarr = Copyarr
let zero = [] //
let subscript = 0 //
let number = 0 //
// 0
copyarr.forEach((items, index) => {
items.forEach((item, i) => {
if (item === 0) {
zero.push({ x: index, y: i })
}
})
})
//
subscript = Math.floor(Math.random() * zero.length)
if (Math.floor(Math.random() * 10) % 3 === 0) {
number = 4 //
} else {
number = 2 //
}
if (zero.length) {
Copyarr[zero[subscript].x][zero[subscript].y] = number
this.arr = Copyarr
}
this.total = 0
this.arr.forEach(items => {
items.forEach(item => {
if (item === max && !this.itIs2048) {
this.itIs2048 = true
}
this.total += item
})
})
}
以上が今回の2048の主なコードの最后に、ランダムに4が现れる确率は私が比较的に大きいため、それに応じていくつかの难易度を下げて、具体的にはすべての数字が左(最辺の上)に现れて、しかも数字と数字の间に隙间がなくて、更に左を押しても数字を生成します