[原创]html5游戏_贪吃蛇
代码随便写写,尚有许多不足,PC与手机端皆可运行
手机端滑屏操作,PC端方向键操作
疑问:
生成食物,与判断是否可以移动方面
有两种实现方式,
1.使用js内存,数组循环判断
2.使用dom的query方法
哪种比较快,哪种比较好?
目前的代码是用第二种方法实现
在线地址:
http://wangxinsheng.herokuapp.com/snake
截图:
部分代码:
html:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="description" content="html5 snake game">
<meta name="keywords" content="snake,html5,canvas,web,game">
<meta name="author" content="WangXinsheng">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="viewport" id="viewport" content="width = device-width, initial-scale = 1, minimum-scale = 1, maximum-scale = 1, user-scalable=no">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta http-equiv="Pragma" content="no-cache">
<meta http-equiv="Cache-Control" content="no-cache">
<meta equiv="Expires" content="0">
<meta http-equiv="content-script-type" content="text/javascript">
<title>CopyRight©WangXinsheng</title>
<script src="game/requestNextAnimationFrame.js"></script>
<style type="text/css">
html {color:#000;background:gray;margin:0px; overflow:hidden;}
body {-webkit-user-select:none;margin:0px;}
#gameWorld {background-color:#C6EEC6}
#opp{color:red; font-size:30px; font-weight:bold; text-align:center;vertical-align:middle; cursor:pointer;}
</style>
</head>
<body>
<canvas id="gameWorld" style="position: absolute; left: 0px; top: 0px;">
<p>You need a modern browser to view this.</p>
</canvas>
<div id="opp" style="position: absolute; left: 0px; top: 0px;">点击开始游戏</div>
<ul style='display:none' id='dataDom'></ul>
</body>
<script src="game/snakeGame_min.js"></script>
</html>
js使用dom方法:
1.初期往页面放入dom
/*put data dom*/
var dataDom = document.getElementById("dataDom");
// document.querySelector("#dataDom");
var domInner = "";
for(var i = 1;i<=blockWNum;i++){
for(var j = 1;j<=blockHNum;j++){
domInner += liStr
.replace("{%x%}",i)
.replace("{%y%}",j)
.replace("{%s%}","0");
}
}
dataDom.innerHTML =domInner; //domInner;
2.判断是否撞到自己
result =
("1"==document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"))
?false
:true;
3.蛇移动:1)移动目的地作为头部插入蛇身体。2)删除蛇尾部
switch(dir){
case "N":
this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y-1});
break;
case "S":
this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y+1});
break;
case "W":
this.body.splice(0,0,{"x":this.body[0].x-1,"y":this.body[0].y});
break;
case "E":
this.body.splice(0,0,{"x":this.body[0].x+1,"y":this.body[0].y});
break;
default:;
}
this.setSnakeSts(this.body[0].x,this.body[0].y,1);
document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
this.setSnakeSts(this.body[this.body.length-1].x,this.body[this.body.length-1].y,0);
this.body.splice(this.body.length-1,1);
4.事件绑定
if(!v){
document.addEventListener("keyup", onKeyPress, false);
}else{
caObj.addEventListener("touchstart", onTouchStart, false);
caObj.addEventListener("touchmove", onTouchMove, false);
caObj.addEventListener("touchend", onTouchEnd, false);
}
window.addEventListener("resize", doSize, false);
逻辑流程:
1.初期化canvas大小,位置和蛇身体单格大小
2.生成蛇,食物
3.蛇动作:可否移动,移动,吃食
4.循环动画[定期生成食物,移动操作蛇]
这个非常简单,js完整源码:
;
var debug = true;
var gameWorld = function () {
/*function init params*/
function doVarInit() {
//started = true;
if(debug)
console.log("hello snake powered by WangXinsheng");
}
/*function on resize the window*/
function doSize() {
// should start again
var minLength = window.innerWidth>window.innerHeight
?window.innerHeight
:window.innerWidth,
maxLength = window.innerWidth<window.innerHeight
?window.innerHeight
:window.innerWidth;
blockW = Math.floor(minLength / blockMinNum);
var caMin = blockW * blockMinNum;
var caMax = Math.floor(maxLength / blockW) * blockW; caW = window.innerWidth>window.innerHeight
?caMax
:caMin;
caH = window.innerWidth<window.innerHeight
?caMax
:caMin; blockWNum = caW / blockW;
blockHNum = caH / blockW; var top = (window.innerHeight - caH) * 0.5,
left = (window.innerWidth - caW) * 0.5; //if(debug)
//console.log(blockWNum,blockHNum,top,left);// caObj.width = caW;
caObj.height = caH;
caObj.style.width = caW + "px";
caObj.style.height = caH + "px";
caObj.style.left = left + "px";
caObj.style.top = top + "px";
oppDiv.width = caW;
oppDiv.height = caH;
oppDiv.style.width = caW + "px";
oppDiv.style.height = caH + "px";
oppDiv.style.left = left + "px";
oppDiv.style.top = top + "px";
oppDiv.style.lineHeight = caH + "px"; /*put data dom*/
var dataDom = document.getElementById("dataDom");
// document.querySelector("#dataDom");
var domInner = "";
for(var i = 1;i<=blockWNum;i++){
for(var j = 1;j<=blockHNum;j++){
domInner += liStr
.replace("{%x%}",i)
.replace("{%y%}",j)
.replace("{%s%}","0");
}
}
dataDom.innerHTML =domInner; //domInner;
//var oldDom = document.querySelector("#dataDom");
//removeDom(oldDom); lastFpsUpdateTime = (+new Date);
lastFpsUpdateTimeFood = (+new Date);
}
function setSnakeSts(x,y,s){
document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
}
function gen(name) {
/*product object*/
switch(name){
case "snake":
var body = [];
body.splice(0,0,{"x":1,"y":1});
body.splice(0,0,{"x":2,"y":1});
body.splice(0,0,{"x":3,"y":1});
body.splice(0,0,{"x":4,"y":1});
setSnakeSts(1,1,1);
setSnakeSts(2,1,1);
setSnakeSts(3,1,1);
setSnakeSts(4,1,1); snakeObj = new snake(snakeColor,true,"E",blockW,initSpeed,body);
snakeObj.draw(caCt);
break;
case "food":
var allFood = document.querySelectorAll("#dataDom [data-s='0']"),
foodX,foodY,index;
if(allFood.length==1){
index = 0;
}else if(allFood.length>1){
index = Math.round(Math.random()*(allFood.length-1));
}
if(allFood.length>=1){
foodX = parseInt(allFood[index].getAttribute("data-x"));
foodY = parseInt(allFood[index].getAttribute("data-y"));
allFood[index].getAttribute("data-s","2");
foodObj.x = foodX;
foodObj.y = foodY;
foodObj.live = true;
}
drawFood();
break;
default:
}
}
function picIsLoaded() {
return true;
}
function loadPics() {
/*load pic to objectList*/
}
function loadedImg() {
/*if image loaded do here*/
}
function drawObject(name){
/*draw object to canvas*/
}
function animate(time) {
if (started) {
var now = (+new Date);
if (now - lastFpsUpdateTime > snakeObj.speed) {
/*animate*/
if(snakeObj.canMove(snakeObj.dir,blockWNum,blockHNum)){
if(snakeObj.canEat(snakeObj.dir,foodObj)){
snakeObj.doEat(snakeObj.dir,foodObj);
}else{
snakeObj.doMove(snakeObj.dir);
}
}else{
// over
started = false;
oppDiv.style.display = "block";
oppDiv.innerHTML = "点击再次游戏";
return;
} caCt.save();
caCt.fillStyle = "#C6EEC6";
caCt.fillRect(0,0,caW,caH); caCt.font = '40px Helvetica';
caCt.textAlign = "center";
caCt.textBaseline = "middle";
caCt.fillStyle = '#8CCDD8';
caCt.strokeStyle = '#8CCDD8';
caCt.fillText("WangXinsheng", caW/2,caH/2);
caCt.strokeText("WangXinsheng", caW/2,caH/2); caCt.restore(); snakeObj.draw(caCt); // draw food
drawFood(); lastFpsUpdateTime = (+new Date);
} if (now - lastFpsUpdateTimeFood > snakeObj.speed*5) {
if(!foodObj.live){
gen("food");
}else{
lastFpsUpdateTimeFood = (+new Date);
}
}
}
window.requestNextAnimationFrame(animate);
}
function drawFood(){
if(foodObj.live){
caCt.save();
caCt.fillStyle = foodObj.color;
caCt.fillRect(
(foodObj.x-1)*blockW,
(foodObj.y-1)*blockW,
blockW,
blockW
);
caCt.restore();
}
}
function eventBund(){
if(!v){
document.addEventListener("keyup", onKeyPress, false);
}else{
caObj.addEventListener("touchstart", onTouchStart, false);
caObj.addEventListener("touchmove", onTouchMove, false);
caObj.addEventListener("touchend", onTouchEnd, false);
caObj.addEventListener("touchcancel", stopEvent, false);
caObj.addEventListener("gesturestart", stopEvent, false);
caObj.addEventListener("gesturechange", stopEvent, false);
caObj.addEventListener("gestureend", stopEvent, false);
}
window.addEventListener("resize", doSize, false);
}
function onKeyPress(e){
//console.log(e);
var dir = "";
switch(e.keyCode){
case 38:
dir =snakeObj.dir=="S"?"":"N";
break;
case 40:
dir =snakeObj.dir=="N"?"":"S";
break;
case 37:
dir =snakeObj.dir=="E"?"":"W";
break;
case 39:
dir =snakeObj.dir=="W"?"":"E";
break;
default:;
}
if(dir!="")
snakeObj.dir = dir;
}
function onTouchEnd(e){
e.preventDefault();
if(mouseTObj.x!=null && mouseTObj.y!=null
&& mouseTMObj.x!=null && mouseTMObj.y!=null){
var diffX = mouseTMObj.x - mouseTObj.x,
diffY = mouseTMObj.y - mouseTObj.y,
dir = "";
if(Math.abs(diffY)>Math.abs(diffX)){
dir = diffY>0?"S":"N";
}else if(Math.abs(diffY)<Math.abs(diffX)){
dir = diffX>0?"E":"W";
}
switch(dir){
case "N":
snakeObj.dir =snakeObj.dir=="S"?"S":"N";
break;
case "S":
snakeObj.dir =snakeObj.dir=="N"?"N":"S";
break;
case "W":
snakeObj.dir =snakeObj.dir=="E"?"E":"W";
break;
case "E":
snakeObj.dir =snakeObj.dir=="W"?"W":"E";
break;
default:;
}
mouseTObj.x = null;
mouseTObj.y = null;
mouseTMObj.x = null;
mouseTMObj.y = null;
}
e.stopPropagation();
return false;
}
function onTouchMove(e){
e.preventDefault();
var touch = e.touches[0];
mouseTMObj.x = touch.pageX;
mouseTMObj.y = touch.pageY;
e.stopPropagation();
return false;
}
function onTouchStart(e){
e.preventDefault();
var touch = e.touches[0];
mouseTObj.x = touch.pageX;
mouseTObj.y = touch.pageY;
e.stopPropagation();
return false;
}
function stopEvent(e) { e.preventDefault(); e.stopPropagation(); }
var v = navigator.userAgent.toLowerCase().indexOf("android") != -1 || navigator.userAgent.toLowerCase().indexOf("iphone") != -1 || navigator.userAgent.toLowerCase().indexOf("ipad") != -1,
caW = window.innerWidth,
caH = window.innerHeight,
caObj = document.getElementById("gameWorld"),
caCt = caObj.getContext("2d"),
oppDiv = document.getElementById("opp"),
lastFpsUpdateTime = new Date,
lastFpsUpdateTimeFood = new Date,
started = false,
blockW = 0,
blockMinNum = 20,
blockWNum = 0,
blockHNum = 0,
snakeObj = null,
snakeColor = "gray",
initSpeed = 150,
liStr = "<li data-x='{%x%}' data-y='{%y%}' data-s='{%s%}'></li>", //s:0-empty,1-snake,2-food
foodObj = {"x":0,"y":0,"live":false,"color":"red"},
mouseTObj = {"x":null,"y":null},
mouseTMObj = {"x":null,"y":null}
; this.init = function () {
//*********init params*******
doVarInit();
//*********init size and vars*******
doSize();
//*********product bell and rabit*******
gen("snake");
gen("food");
//gen("yyy");
//*********Event***********
eventBund();
//*********Gen***********
//*********animate***********
animate();
}
this.start = function(){
oppDiv.style.display = "none";
started = true;
}
} /*
* object
*/
function snake(bgC,live,dir,blockW,speed,body) {
this.bgC = bgC; // 涂色
this.live=live; // 存活状态 true,false
this.dir=dir; // 移动方向 N,S,W,E
this.blockW=blockW; // 方块边大小
this.speed=speed; // 速度 1000
this.body = body; // 蛇身体
}
snake.prototype.draw = function (context) {
context.save();
context.fillStyle = "gray";
for(var i = 0;i<this.body.length;i++){
context.fillRect(
(this.body[i].x-1)*this.blockW,
(this.body[i].y-1)*this.blockW,
this.blockW,
this.blockW
);
}
context.restore();
}
snake.prototype.canMove = function (dir,xMax,yMax) {
var result = false,
nx = this.body[0].x,
ny = this.body[0].y;
// 边框检测
switch(dir){
case "N":
result = this.body[0].y==1?false:true;
ny--;
break;
case "S":
result = this.body[0].y==yMax?false:true;
ny++;
break;
case "W":
result = this.body[0].x==1?false:true;
nx--;
break;
case "E":
result = this.body[0].x==xMax?false:true;
nx++;
break;
default:;
}
// 自己检测
//console.log(document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"));
if(result)
result =
("1"==document.querySelector("#dataDom [data-x='"+nx+"'][data-y='"+ny+"']").getAttribute("data-s"))
?false
:true;
return result;
}
snake.prototype.canEat = function (dir,food) {
var sx=this.body[0].x,
sy=this.body[0].y;
switch(dir){
case "N":
sy--;
break;
case "S":
sy++;
break;
case "W":
sx-1;
break;
case "E":
sx+1;
break;
default:;
}
return (food.x==sx && food.y==sy);
}
// push第一个,pop最后一个
snake.prototype.doMove = function (dir) {
this.doEat(dir,null);
this.setSnakeSts(this.body[this.body.length-1].x,this.body[this.body.length-1].y,0);
this.body.splice(this.body.length-1,1);
}
// push第一个
snake.prototype.doEat = function (dir,food) {
switch(dir){
case "N":
this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y-1});
break;
case "S":
this.body.splice(0,0,{"x":this.body[0].x,"y":this.body[0].y+1});
break;
case "W":
this.body.splice(0,0,{"x":this.body[0].x-1,"y":this.body[0].y});
break;
case "E":
this.body.splice(0,0,{"x":this.body[0].x+1,"y":this.body[0].y});
break;
default:;
}
this.setSnakeSts(this.body[0].x,this.body[0].y,1);
if(food!=null)
food.live = false;
}
snake.prototype.setSnakeSts = function(x,y,s){
document.querySelector("#dataDom [data-x='"+x+"'][data-y='"+y+"']").setAttribute("data-s",s);
} var gameWorldObj = null;
window.onload = function () {
document.getElementsByTagName('title')[0].innerHTML = "[WXS]贪吃蛇";
snakeGameGo();
}
function snakeGameGo(){
if(gameWorldObj == null)
gameWorldObj = new gameWorld();
gameWorldObj.init();
var opp = document.getElementById("opp");
opp.addEventListener("click", doPlay, false);
}
function doPlay(){gameWorldObj.init();gameWorldObj.start();}
运行文件下载地址:
http://download.csdn.net/detail/wangxsh42/8515975
[原创]html5游戏_贪吃蛇的更多相关文章
- [原创]html5游戏_五线谱打音符
html5手机游戏—五线谱打音符 1.[用五线谱打唱名] 2.[用唱名打五线谱] 3.[无限练习模式] 用来熟悉五线谱上音符的位置 代码不难,这回注释还是有认真写的[只是废代码没有全部删除...] 效 ...
- JavaScript与html5写的贪吃蛇完整代码
JavaScript与html5写的贪吃蛇完整代码 查看运行效果可访问http://www.codesocang.com/texiao/youxitexiao/2014/0402/7045.html# ...
- JS小游戏:贪吃蛇(附源码)
javascript小游戏:贪吃蛇 此小游戏采用的是面向对象的思想,将蛇,食物,和游戏引擎分为3个对象来写的. 为方便下载,我把js写在了html中, 源码中暂时没有注释,等有空我在添加点注释吧. 游 ...
- Python:游戏:贪吃蛇原理及代码实现
一.游戏介绍 贪吃蛇是个非常简单的游戏,适合练手.先来看一下我的游戏截图: 玩法介绍:回车键:开始游戏空格键:暂停 / 继续↑↓←→方向键 或 WSAD 键:控制移动方向. 食物分红.绿.蓝三种,分别 ...
- WebGL实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
- 100行JS实现HTML5的3D贪吃蛇游戏
js1k.com收集了小于1k的javascript小例子,里面有很多很炫很酷的游戏和特效,今年规则又增加了新花样,传统的classic类型基础上又增加了WebGL类型,以及允许增加到2K的++类型, ...
- C语言 小游戏之贪吃蛇
还记得非常久曾经听群里人说做贪吃蛇什么的,那时候大一刚学了C语言,认为非常难,根本没什么思路. 前不久群里有些人又在谈论C语言贪吃蛇的事了,看着他们在做,我也打算做一个出来. 如今大三,经过了这一年半 ...
- Canvas进阶——制作小游戏【贪吃蛇】
今天呢,主要和小伙伴们分享一下一个贪吃蛇游戏从构思到实现的过程~因为我不是很喜欢直接PO代码,所以只copy代码的童鞋们请出门左转不谢. 按理说canvas与其应用是老生常谈了,可我在准备阶段却搜索不 ...
- Python实战练习_贪吃蛇 (pygame的初次使用)
正如标题所写的那样,我将一步步的完成本次实战练习——贪吃蛇.废话不多说,感兴趣的伙伴可以一同挑战一下. 首先说明本次实战中我的配备: 开发环境:python 3.7: 开发工具:pycharm2019 ...
随机推荐
- 机器学习&数据挖掘笔记_15(关于凸优化的一些简单概念)
没有系统学过数学优化,但是机器学习中又常用到这些工具和技巧,机器学习中最常见的优化当属凸优化了,这些可以参考Ng的教学资料:http://cs229.stanford.edu/section/cs22 ...
- 碉堡了! 纯 CSS 绘制《辛普森一家》人物头像
这篇文章给大家分享一组纯 CSS 绘制的<辛普森一家>人物头像.<辛普森一家>(The Simpsons)是马特·格勒宁为美国福克斯广播公司创作的一部动画情景喜剧.该剧通过对霍 ...
- Android抓包方法(三)之Win7笔记本Wifi热点+WireShark工具
Android抓包方法(三) 之Win7笔记本Wifi热点+WireShark工具 前言 做前端测试,基本要求会抓包,会分析请求数据包,查看接口是否调用正确,数据返回是否正确,问题产生是定位根本原因等 ...
- Elasticsearch——Search的基本介绍
Elasticsearch最常用的方法莫过于查询了.Es支持以URI请求参数或者请求体的方式进行查询. 查询范例 Elasticsearch支持对多索引以及多类型进行查询. 比如,下面对某个特定索引的 ...
- 在SQL Server里为什么我们需要更新锁
今天我想讲解一个特别的问题,在我每次讲解SQL Server里的锁和阻塞(Locking & Blocking)都会碰到的问题:在SQL Server里,为什么我们需要更新锁?在我们讲解具体需 ...
- 3.openstack之mitaka搭建keystone认证服务
认证服务keystone部署 一:安装和配置服务 1.建库建用户 mysql -u root -p CREATE DATABASE keystone; GRANT ALL PRIVILEGES ON ...
- MVC应用程序的生命周期图
- 我读过的最好的epoll讲解--转自”知乎“
首先我们来定义流的概念,一个流可以是文件,socket,pipe等等可以进行I/O操作的内核对象. 不管是文件,还是套接字,还是管道,我们都可以把他们看作流. 之后我们来讨论I/O的操作,通过read ...
- 使用powerdesigner创建数据库表
(1 )新建概念模型 (2 )新建表,添加表各个属性 填写属性名称和类型,主键要勾选上P,M,D. (3) 如何各个表中有相同的字段名,需要设置Tool->Model Options,把红色区域 ...
- MySQL MHA配置常见问题
MHA在MySQL数据库中被广泛使用,它小巧易用,功能强大,实现了基于MySQL replication架构的自手动主从故障转移,从库重定向到主库并自动同步.尽管如此,在部署配置的过程中,由于疏忽总难 ...