自制HTML5游戏《开心消消乐》

1. 引言

游戏介绍

《开心消消乐》是一款基于HTML5技术开发的网页游戏,以其简单的操作方式、轻松的游戏体验和高度的互动性,迅速在社交平台上获得了广泛的关注和传播。玩家通过消除相同类型的元素来获得分数,游戏设计巧妙,易于上手,同时富有挑战性,使其成为休闲娱乐的不错选择。

HTML5技术在现代网页游戏开发中的作用

HTML5技术为现代网页游戏开发带来了革命性的变化。它提供了一系列的新特性和改进,包括但不限于:

  • 图形和多媒体 :HTML5的<canvas><video>标签使得在网页上绘制图形和播放多媒体内容变得更加容易和高效。

  • 本地存储:通过localStorage和sessionStorage,网页游戏可以存储玩家数据,即使在浏览器关闭后也能保持。

  • 设备访问:HTML5允许网页访问用户设备的功能,如摄像头、麦克风等,为游戏增添更多互动元素。

  • 离线应用:通过缓存和离线应用技术,HTML5游戏可以在没有网络的情况下运行,提高了用户体验。

  • Web Workers:支持多线程处理,让游戏逻辑和渲染可以并行运行,提高了性能。

源码解析

逐步分析《开心消消乐》游戏的实现。

  • <!DOCTYPE html>:这行声明了文档类型,告诉浏览器这是一个HTML5文档。

  • <html>:根元素,包含整个页面的内容。class属性用于添加CSS类,style属性用于内联样式,这里设置背景和宽度。

  • <head>:包含了文档的元数据,如字符集定义、视口设置、网页标题等。

  • <meta>:定义了页面的多种元数据,例如字符集UTF-8,搜索引擎的索引和跟随指令,以及苹果设备的全屏模式。

  • <title>:定义了网页的标题,这对于SEO和用户在浏览器标签页上的可视性至关重要。

  • <style>:内联CSS样式,用于重置页面元素的默认样式,为游戏界面提供统一的字体设置。

  • <div id="spilgames-root">:这是游戏容器的HTML元素,游戏的主要内容将被挂载在这个元素上。

  • <script>:引入了游戏逻辑的JavaScript文件game.min.js,以及实现分享功能的脚本。

html 复制代码
<!DOCTYPE html>
<html class="SG-game-show" style="background:none;background-color:transparent; width:100%;">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <meta charset="UTF-8">
    <!-- 其他meta标签 -->
    <title>开心消消乐-杭州吃喝玩乐</title>
    <style type="text/css">
        * { padding: 0px; margin: 0px; cursor: default; }
        body { font: 12px/20px Palatino; }
    </style>
    <!-- JavaScript性能监控脚本 -->
</head>
<body>
    <!-- 游戏容器 -->
    <div id="spilgames-root"></div>
    <!-- 游戏逻辑脚本引入 -->
    <script type="text/javascript" src="SeaTreasureMatch_files/game.min.js"></script>
    <!-- 分享功能脚本 -->
    <script>
        // 分享功能实现的JavaScript代码
    </script>
    <!-- 其他脚本和统计代码 -->
</body>
</html>

2. 头部元数据(Head Metadata)

Content-Type

<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> 这个标签定义了文档的字符编码和类型。http-equiv 属性指定了一个HTTP头,这里指定了 Content-Typetext/html,意味着文档是HTML类型。charset=UTF-8 表明文档使用的字符编码是UTF-8,这是一种广泛使用的字符编码,可以表示世界上大多数语言的字符。

charset

<meta charset="UTF-8"> 这个标签是HTML5中推荐的指定字符编码的方式,它的作用与上面的 Content-Type 类似,但更为简洁。它直接告诉浏览器文档使用的字符编码是UTF-8。

apple-mobile-web-app-capable

<meta name="apple-mobile-web-app-capable" content="yes"> 这个标签专门用于iOS设备,当设置为 content="yes" 时,它允许Safari将网页添加到用户的主屏幕,作为一个"网络应用"运行,提供更接近原生应用的体验。

robots

<meta name="robots" content="index,follow"> 这个标签告诉搜索引擎的爬虫如何处理页面。content="index,follow" 指示爬虫应该索引页面(index)并跟随页面上的链接(follow)。

apple-touch-fullscreen

<meta name="apple-touch-fullscreen" content="yes"> 这个标签允许网页在iOS设备上以全屏模式运行,提供一个无干扰的用户体验。

description

<meta name="description" content=""> 这个标签提供了网页的简短描述。虽然在源码中 content 属性为空,但在实际使用中,这里应该填写一段简洁的描述文本,用于告诉用户和搜索引擎网页的主要内容。描述内容通常在搜索引擎结果页面(SERP)中显示,对吸引用户点击有重要作用。

<meta> 标签在HTML文档中扮演着重要角色,它们不仅帮助搜索引擎更好地理解页面内容,还影响着页面在浏览器中的呈现和行为。正确使用这些标签,可以提升网页的可访问性、用户体验和搜索引擎优化(SEO)。

4. JavaScript性能监控

_SPTimer 对象及其作用

_SPTimer 对象是一个自定义的JavaScript对象,用于监控和记录页面加载以及特定事件的时间。在您提供的源码中,_SPTimer 对象通过以下方式定义和使用:

html 复制代码
var _SPTimer = {
    w: {}, // 存储开始时间的字典
    start: function(a) {
        this.w[(a || "_")] = +new Date(); // 记录事件开始的时间
    },
    end: function(a) {
        var b;
        a = a || "_";
        if (this.w[a]) {
            b = new Date() - this.w[a]; // 计算事件持续的时间
            window._gaq = window._gaq || []; // 确保analytics数组存在
            window._gaq.push(["_trackTime", a, b]); // 将时间数据发送到analytics服务
        }
    }
};
作用分析:
  1. 时间记录_SPTimer 对象通过其 start 方法记录一个事件开始的时间,通常用于页面加载或特定功能的开始。

  2. 性能监控 :通过 end 方法,_SPTimer 计算从事件开始到结束所经过的时间,这对于性能分析非常有用。

  3. 数据收集_SPTimer 将记录的时间数据通过 window._gaq 发送到Google Analytics(或其他analytics服务),以便进行进一步的分析和报告。

页面加载时间的监控方法

页面加载时间是衡量网站性能的关键指标之一。在您的源码中,_SPTimer 被用来监控页面加载时间:

html 复制代码
var SpilGamesBrandTimer = +new Date(),
_SPTimer = {
    // _SPTimer的定义
};
_SPTimer.start('pageLoad');
  1. 开始监控 :在页面加载时,通过 _SPTimer.start('pageLoad') 记录下页面开始加载的时间。

  2. 结束监控 :通常在页面完全加载后,调用 _SPTimer.end('pageLoad') 来结束监控,并计算加载所需的总时间。

  3. 数据发送 :通过 _SPTimer.end 方法,将页面加载时间发送到analytics服务,例如Google Analytics,通过 window._gaq.push 方法。

5. 游戏容器设置

div#spilgames-root 的作用

在HTML文档中,div 元素通常用于分组和组织内容。当 div 元素带有特定的 id 属性时,它充当了页面上一个独特部分的容器,这个部分可以被CSS样式化,或者作为JavaScript操作的目标。在您提供的源码中:

javascript 复制代码
<div id="spilgames-root"></div>

div#spilgames-root 有以下作用:

  1. 容器 :它作为游戏内容的容器,所有的游戏元素和逻辑都将被挂载在这个 div 内部。

  2. 定位id 属性提供了一个明确的定位点,允许CSS和JavaScript准确地引用和操作这个元素。

  3. 样式和脚本作用域 :通过 id 选择器,CSS可以定义这个容器的特殊样式,JavaScript可以在这个容器内执行特定的脚本逻辑。

  4. DOM操作 :在JavaScript中,可以通过 document.getElementById('spilgames-root') 快速访问这个 div,然后对其进行操作,如添加事件监听器或插入子元素。

游戏逻辑脚本 game.min.js 的引入方式

在网页中引入外部JavaScript文件是实现网页功能的重要步骤。在您的源码中,game.min.js 脚本是这样引入的:

javascript 复制代码
<script type="text/javascript" src="SeaTreasureMatch_files/game.min.js"></script>
  1. <script> 标签:这是HTML中用于引入JavaScript文件的标准标签。

  2. type 属性type="text/javascript" 指明了脚本的类型,这是HTML4的遗留属性,在HTML5中可以省略,因为 <script> 默认就是JavaScript。

  3. src 属性src 属性指定了外部JavaScript文件的路径。在这个例子中,game.min.js 位于 SeaTreasureMatch_files 目录下。

  4. 文件名game.min.js 表明这个文件是游戏逻辑的压缩版本,.min 通常表示这是一个压缩过的文件,减少了文件大小,加快了加载速度。

  5. 加载时机 :脚本被放置在 div#spilgames-root 之后,这意味着容器元素已经存在于DOM中,当脚本加载并执行时,它能够找到并操作这个容器

效果图:

源代码:

html 复制代码
<!DOCTYPE html>
<html class="SG-game-show" style="background:none;background-color:transparent; width:100%;" manifest="manifest.mf">
<head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8"><meta charset="UTF-8">
<script type="text/javascript">
	var SpilGamesBrandTimer = +new Date(),
	_SPTimer={w:{},start:function(a){this.w[(a||"_")]=+new Date()},end:function(a){window._gaq=window._gaq||[],a=a||"_";if(this.w[a]){ 
	}}};
	_SPTimer.start('pageLoad');
</script>

<meta http-equiv="Content-Type" content="text/html">
<meta name="apple-mobile-web-app-capable" content="yes"> 
<meta name="robots" content="index,follow"> 
<meta name="apple-touch-fullscreen" content="yes">
<meta name="description" content="">		
<title>开心消消乐-杭州吃喝玩乐</title>		
<style type="text/css"> * { padding: 0px; margin: 0px; cursor: default; } body { font: 12px/20px Palatino; }</style>
<!--<script type="text/javascript">document.write('<script type="text/javascript" src="../resource/js/resource_loader.js?ver='+Math.random()+'"><\/script>')</script>-->
	
</head>
<body>

<div id="spilgames-root"></div>
<script type="text/javascript" src="SeaTreasureMatch_files/game.min.js"></script>

    <script>
        function dp_Ranking() {
            document.location.href = "http://www.yxkfw.com/forum.php";
        }
    </script>

    <div id="share" style="display: none">
			<img width="100%" src="bitmap/share.png" style="position: fixed; z-index: 9999; top: 0; left: 0; display: " ontouchstart="document.getElementById(&#39;share&#39;).style.display=&#39;none&#39;;">
		</div>
    <script>
        var mebtnopenurl = "http://mp.weixin.qq.com/s?__biz=MzA5MzU2MjU3Mw==&mid=218850712&idx=1&sn=53bfed8c43391843a6268706ccda8eb2&scene=1&key=1936e2bc22c2ceb5b8b45ee0ef26a5cc01639c3411c2cfd0bd74efb6f0a180003056abc9700e348732a0a5c963462d2f&ascene=1&uin=MjgxMTA4MTUwMQ%3D%3D&devicetype=Windows+7&version=61000721&pass_ticket=w4kQ%2FSFhaY2mmOE87ChVgbTRWP%2BctOhqXukbldnl%2FXb4%2BOxgCyIxSdzUjax%2FUmHK";
        var tit = "";
        var DFW = {
            appId: "",
            TLImg: "http://www.51tingweikeji.com/youxi/icon/kaixinlian.jpg",
            url: "http://www.51tingweikeji.com/youxi/games/kaixinlian/",
            title: "开心消消乐-多多游戏",
            desc: "我消,我消,我消...!"
        };
        var onBridgeReady = function () {
            WeixinJSBridge.on('menu:share:appmessage', function (argv) {
                WeixinJSBridge.invoke('sendAppMessage', {
                    "appid": DFW.appId,
                    "img_url": DFW.TLImg,
                    "img_width": "120",
                    "img_height": "120",
                    "link": DFW.url,
                    "title": DFW.title + tit,
                    "desc": DFW.desc
                }
                );
            });
            WeixinJSBridge.on('menu:share:timeline', function (argv) {
                WeixinJSBridge.invoke('shareTimeline', {
                    "appid": DFW.appId,
                    "img_url": DFW.TLImg,
                    "img_width": "120",
                    "img_height": "120",
                    "link": DFW.url,
                    "title": DFW.title + tit,
                    "desc": DFW.desc
                }
                );
            });
        };
        if (document.addEventListener) { 
            document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false);
        } else if (document.attachEvent) {
            document.attachEvent('WeixinJSBridgeReady', onBridgeReady);
            document.attachEvent('onWeixinJSBridgeReady', onBridgeReady);
        }
        function do_share(score) {
            document.title = "我获得了" + score + "分,一起来消星星吧!";

            document.getElementById("share").style.display = "";
            window.DFW.title = document.title;
        }
        function dp_submitScore(level,score) {
            //alert("你获得" + score + "分");
            if (score > 5000) {
                if (confirm("你获得了" + score + " 要不要通知下小伙伴们呢?")) {
                    do_share(score);
                }
            }
        }
    </script>
<div style="display: none;"><script type="text/javascript" src="http://tajs.qq.com/stats?sId=36313548" charset="UTF-8"></script></div>
</body></html>

JS源码

javascript 复制代码
SpilGamesBrand = function() {
	var d = window.document;
	documentElement = d.documentElement || {};
	element = d.createElement("div");
	container = d.getElementById("spilgames-root");
	emptyFn = function() {};
	globalSettings = {};
	api = {};
	updateBodyCheck = function(d) {
		var a, b = d,
			c = !1;
		return function(d, f) {
			b = d || b;
			c = f || c;
			clearTimeout(a);
			c && (a = setTimeout(function() {
				updateBodyCheck = function(a) {
					b = a || b;
					b()
				};
				b()
			}, 100))
		}
	}(emptyFn);
	updateSize = function() {
		var h = d.body || d.getElementsByTagName("body")[0];
		updateSize = function(a) {
			a = h.getElementsByTagName("*");
			for (var b = a.length, c = 0, k = element.style.zIndex, f = 0; f < b; f++) c++, a[f] !== element && a[f].style.zIndex > c && (c = a[f].style.zIndex), c > k && (k = c, updateBodyCheck());
			element.style.zIndex = k;
			element.style.width = (window.innerWidth || documentElement.clientWidth || d.getElementsByTagName("body")[0].clientWidth) + "px";
			element.style.height = (window.innerHeight || documentElement.clientHeight || d.getElementsByTagName("body")[0].clientHeight) + "px";
			waitId = setTimeout(updateSize, updateSpeed)
		};
		updateSize()
	};
	und = function(d) {
		return void 0 === d
	};
	fadeOut = function(d) {
		var a = d.style,
			b = function() {
				_SPTimer.end("splashscreen");
				clearTimeout(waitId);
				globalSettings.container.removeChild(d)
			};
		return und(a.webkitTransition) && und(a.MozTransition) && und(a.transition) ? (a.opacity = 1, function() {
			console.info("opacity")
		}) : function() {
			a.opacity = 0;
			a.webkitTransition = a.MozTransition = a.transition = "opacity 500ms ease 0ms";
			d.addEventListener("webkitTransitionEnd", b);
			d.addEventListener("mozTransitionEnd", b);
			d.addEventListener("transitionend", b)
		}
	}(element);
	waitId = null;
	updateSpeed = 100;
	endTriggered = !1;
	element.id = "splashscreen";
	api.show = function(d) {
		d = d || {};
		globalSettings = {
			time: d.time || 2500,
			onEnd: d.onEnd || emptyFn,
			onStart: d.onStart || emptyFn,
			container: d.container || container,
			css: d.css || ""
		};
		0 > globalSettings.time && (globalSettings.time = 0);
		setTimeout(function() {
			updateSpeed = 300
		}, 3E4);
		updateSize();
		globalSettings.container.appendChild(element);
		element.style.cssText = globalSettings.css;
		_SPTimer.start("splashscreen");
		globalSettings.onStart()
	};
	api.end = function() {
		var d = !1,
			a;
		end = function() {
			a = d ? 0 : globalSettings.time;
			updateBodyCheck(emptyFn);
			0 > a ? fadeOut() : setTimeout(fadeOut, a)
		};
		return function(b) {
			endTriggered || (d = b || !1, endTriggered = !0, b ? end() : updateBodyCheck(end, !0))
		}
	}();
	return api
}(window);
SpilGamesBrand.show({
	css: "top: 0px; left: 0px; z-index: 9999; position: absolute; background: #d0e8fd url('logo.png') no-repeat center; -webkit-background-size: 320px 320px !important;"
});
window.FZ = {};
(function() {
	window.Gamehub && (window.SpilGames = {
		_: function(d) {
			var h = arguments,
				a = 0;
			return d.replace(/%s/g, function(b) {
				a++;
				return void 0 !== h[a] ? h[a] : b
			})
		},
		Highscores: {
			insert: function(d) {
				Gamehub.Score.submit(d.score)
			},
			showScoreboard: function(d) {
				Gamehub.ShowScoreboard();
				d && setTimeout(d, 100)
			}
		},
		Settings: {
			get: function(d) {
				switch (d) {
				case "currentGameInfo":
					return {
						splashScreen: Gamehub.Settings.splashScreen,
						rotationLockSreen: {
							portrait: Gamehub.Settings.rotationLockScreen.portrait,
							landscape: Gamehub.Settings.rotationLockScreen.landscape
						}
					};
				default:
					return {}
				}
			}
		}
	});
	FZ.SpilAPI = {
		SubmitScore: function(d) {
			FZ.SpilAPI.checkSpilAPI();
			SpilGames.Highscores.insert({
				score: d
			})
		},
		ShowHighscore: function() {
			FZ.SpilAPI.checkSpilAPI();
			!FZ.SpilAPI.___noSpilGamesAPI && FZ.GameBase && FZ.GameBase.pauseGame();
			SpilGames.Highscores.showScoreboard(function() {
				FZ.GameBase && FZ.GameBase.resumeGame()
			})
		},
		GetSplashScreenURL: function() {
			FZ.SpilAPI.checkSpilAPI();
			return FZ.SpilAPI.___noSpilGamesAPI ? "" : 
相关推荐
Apifox11 分钟前
如何在 Apifox 中通过 Runner 运行包含云端数据库连接配置的测试场景
前端·后端·ci/cd
树上有只程序猿39 分钟前
后端思维之高并发处理方案
前端
庸俗今天不摸鱼1 小时前
【万字总结】前端全方位性能优化指南(十)——自适应优化系统、遗传算法调参、Service Worker智能降级方案
前端·性能优化·webassembly
黄毛火烧雪下1 小时前
React Context API 用于在组件树中共享全局状态
前端·javascript·react.js
Apifox2 小时前
如何在 Apifox 中通过 CLI 运行包含云端数据库连接配置的测试场景
前端·后端·程序员
一张假钞2 小时前
Firefox默认在新标签页打开收藏栏链接
前端·firefox
高达可以过山车不行2 小时前
Firefox账号同步书签不一致(火狐浏览器书签同步不一致)
前端·firefox
m0_593758102 小时前
firefox 136.0.4版本离线安装MarkDown插件
前端·firefox
掘金一周2 小时前
金石焕新程 >> 瓜分万元现金大奖征文活动即将回归 | 掘金一周 4.3
前端·人工智能·后端
三翼鸟数字化技术团队2 小时前
Vue自定义指令最佳实践教程
前端·vue.js