写一个带存档的js游戏

JavaScript021

写一个带存档的js游戏,第1张

关于写一个带存档的js游戏相关资料如下

最近使用 JS 写了一个贪吃蛇游戏,效果如下:

贪吃蛇作为一款经典又简单的小游戏,每个人都玩过。实现一个贪吃蛇游戏基本具有以下功能:

棋盘(也被称作 “地图”,我这里画的像一个围棋棋盘,索性就叫棋盘)

蛇 (细致一点分为:蛇头、蛇身、蛇尾)

方向(上下左右)控制,并且自动行走

碰撞检测(撞墙、撞自己)

食物在随机位置生成

蛇吃到食物,尾部生长一截

以上也便是我的实现步骤了,下面分享一些更详细的实现思路。

2019/02/07

我记得我年前的时候,我看过很多文章,包括一些论文,主题都是利用AI来玩贪吃蛇这种。他们利用的方法很多,例如利用搜索算法[1],还有利用监督学习来进行训练达到目的的,训练数据的来源是有自己玩游戏产生的(好像有算法是可以让他自己产生的,想不起来是在哪里看到的了。),当然这种正如他自己所说,后续的结果就是机器最多玩的和你一样好,最后一种见的比较多的就是利用强化学习,加上Q-Learning算法的方式。 针对搜索算法部分,可以看前面的一篇随笔《贪吃蛇游戏》。

那段时间看了不少这类的文章,我现在集中阅读一下,并简单理解一下这部分内容的关键部分。无论什么游戏,都有一个 相应的状态空间 的定义,这部分数据,本质上就是这个游戏能展现给我的所有的内容。那么怎么来利用这部分数据,就是你的能力了。

文章[2]中,他是用的方法同时结合了深度学习和强化学习。 (我也想深究一下,如果是仅仅使用强化学习,这个过程又是什么样的,得看我收集的文章中,是不是有这类部分的内容了;我记得好像强化学习就是利用Q-Learning这种算法来实现的) 但是这篇文章感觉说的不够清楚,最重要的那个点就是,强化学习到底是如何跟深度学习联合起来的。可能单单强化学习已经可以完成这个任务了。

我大概理解了这个过程,他是利用强化学习来作为自动化生成数据的过程了,一开始的时候,利用强化学习尽可能得到多的数据,然后采样或者怎么样使得最后的数据作为训练得到效果。 这篇文章讲述的并不是清楚,不推荐。 下面这个图从这篇文章中看到的,挺不错。

文章[3]基于强化学习Q-Learning完成了贪吃蛇的步骤,不过貌似他的这个效果并不是非常好。整个部分的源码他都是利用js来完成的, 讲解部分比较基础, 回答了前一小节的疑问。

本篇文章中,他介绍的另外一个内容挺不错,就是利用神经网络来玩谷歌浏览器的游戏。

文章[5]利用深度学习和遗传算法来训练玩游戏;这部分的文章一系列的内容,从使用pygame设计游戏,到后面自动化产生数据,最后使用GA+ANN直接不需要数据。他的思路 跟前面强化学习是不一样的。

前面部分讲到了自动化产生训练数据的部分,这个部分我感觉讲解的并不是非常好,他的自动化并不是说让游戏自己去探测这个各种内容。反而是根据某种公式来计算角度,最终实现这个过程。后续GA算法的时候又说道可以不是用训练数据。

他利用GA算法应该是使用了两个部分,第一个就是直接使用GA进行训练,他的适应函数(fittness function)部分,类似强化学习的部分,产生奖励和惩罚机制。第二个就是使用GA算法来选择神经网络的架构。 (这部分我也不是很确认,有点没看懂他要干什么) 对于神经网络中的权值部分他是如何进行实现的,这是我的一个疑问。 GA算法到底针对的是哪一部分的内容。这种文章还是有一定缺陷的。GA算法是两部分内容,首先就是权值更新内容。

虽然这篇文章感觉很基础,但我觉的写的不好。

利用学习的办法实现玩游戏的目标,比较重要的问题,有以下几个。

[1] Hawstein,如何用Python写一个贪吃蛇AI

[2] 如何让AI玩贪吃蛇:深度强化学习

[3] 利用强化学习玩贪吃蛇

[4] 谷歌小恐龙

[5] 深度学习与贪吃蛇

我原来用C语言,借助curses库实现了linux 终端下的贪吃蛇游戏。

这个javascript版本的贪吃蛇是http://www.veryhuo.com/game/tanchishe.html 的学习笔记,实现的原理和C版本基本一样。

--------------------

1.怎样表示一条snake

用一个二维数组存snake的各个点(x,y),同时标记这些点(x,y)为“cover”,这是用于以后检查snake的头是否撞到了snake的body。

//initialize snake

function initSnake() {

var pointer = randomPointer(len-1, len-1, WIDTH/2)

for(var i = 0 i < len i++) {

var x = pointer[0] - i,

y = pointer[1]

snake.push([x,y])

carrier[x][y] = "cover" //标记snake body

}

}

2.用js画出格子

用document.createElent()方法创建出table->tr->td, 然后用document.appendChild()方法追加到id为“snakewrap”的元素上:

//initialize grid 

function initGrid() {

var body = document.getElementsByTagName("body")[0]

var table = document.createElement("table"),

tbody = document.createElement("tbody")

for(var j = 0 j < HEIGHT j++) {  

var col = document.createElement("tr")  

for(var i = 0 i < WIDTH i++) {  

var row = document.createElement("td")

gridElems[i][j] = col.appendChild(row)  

}

tbody.appendChild(col)  

}

table.appendChild(tbody)

document.getElementById("snakewrap").appendChild(table)

}

3.生成食物的随机坐标

function randomPointer(startX,startY,endX,endY) {

startX = startX || 0

startY = startY || 0

endX = endX || WIDTH

endY = endY || HEIGHT

var p = [],

x = Math.floor(Math.random()*(endX - startX)) + startX,

y = Math.floor(Math.random()*(endY - startY)) + startY

//如果(x,y)有物体,则重新生成坐标

if(carrier[x][y]) {

return randomPointer(startX,startY,endX,endY)

}

p[0] = x

p[1] = y

return p

}

添加新的食物:

//addObject("food")

function addObject(name) {

var p = randomPointer() //get random position

var x = p[0]

var y = p[1]

carrier[x][y] = name

gridElems[x][y].className = name

}

4.方向键按下动作事件监听:允许左上右下这4个按键来改变snake的运动方向,注意,如果方向相反的话,不生效。

对于键盘上的每一个按键,都有一个key cord,我的这篇博客记录了javascript的key cord,可看到:

left arrow    37    

up arrow    38    

right arrow    39    

down arrow    40    

//keyboard event listener

function attachEvents(e) {

e = e || event

directkey = Math.abs(e.keyCode - directkey) != 2 && e.keyCode > 36 && e.keyCode < 41 ? e.keyCode : directkey 

return false

}