前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >超级玛丽HTML5源代码学习------(四)

超级玛丽HTML5源代码学习------(四)

作者头像
wust小吴
发布于 2022-03-03 12:42:13
发布于 2022-03-03 12:42:13
1.6K00
代码可运行
举报
文章被收录于专栏:风吹杨柳风吹杨柳
运行总次数:0
代码可运行

首先我们需要知道

每一个游戏都是由:

A:获得用户输入

B:更新游戏状态

C:处理AI

D:播放音乐和音效

E:画面显示

这些行为组成。游戏主循环就是用来处理这个行为序列,在javascript中可以用setInterval方法来轮询。在超级玛丽中是这个循环

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	//主循环
	var mainLoop=setInterval(function(){

		//距上一次执行相隔的时间.(时间变化量), 目前可近似看作sleep.
		var deltaTime=sleep;
		
		// 更新Animation状态
		animation.update(deltaTime);
	
		//使用背景覆盖的方式 清空之前绘制的图片
		context.drawImage(ImgCache["bg"],0,0);
				
		//绘制Animation
		animation.draw(context, x,y);
		
	},sleep);

如何去做到让游戏角色进行移动呢?今天这里只学习让玩家在原地进行移动,也就是step3_1

实现人物移动的方法就是:将精灵图片的不同动作图片,在画布上同一位置交替显示,就形成了人物原地移动的动画。在画布的不同的位置显示动作图片,就形成了人物在画布上来回移动的动画。

首先实现炸弹人在画布上原地移动,显示移动动画;

了解精灵图片含义:所谓精灵图片就是包含多张小图片的一张大图片,使用它可以减少http请求,提升性能。

第一步:实现人物的显示

首先,要显示玩家角色。需要创建画布并获得上下文,加载缓存图像,调用StartDemo,然后是清空画布区域,使用drawImage来绘制图片。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// 页面初始化函数
function init(){
	
	// 创建canvas,并初始化 (我们也可以直接以标签形式写在页面中,然后通过id等方式取得canvas)
	canvas=document.createElement("canvas");
	canvas.width=600;
	canvas.height=400;
	document.body.appendChild(canvas);
		
	// 取得2d绘图上下文 
	context= canvas.getContext("2d");
	
	//加载图片,并存入全局变量 ImgCache, 
	// 加载完成后,调用startDemo
	ImgCache=loadImage( [ 
			{ 	id : "player",
				url : "../res/player.png"
			},
			{ 	id : "bg",
				url : "../res/bg.png"
			}
		], 
		startDemo );

}

第二步:游戏的帧数 FPS=30

每秒所运行的帧数。游戏主循环每33.3(1000/30)ms轮询一次

FPS决定游戏画面更新的频率,决定主循环的快慢。

主循环中的间隔时间sleep与FPS有一个换算公式:

间隔时间 = 就近最大取整(1000 / FPS),不同于四舍五入,也叫向下取整

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	// 一些简单的初始化, 
	var FPS=30;
	var sleep=Math.floor(1000/FPS);
	
	//初始坐标
	var x=0, y=284;

第三步:使用帧动画

一些基本要理解的知识:

动画是通过绘制一组帧图片来实现的。具体实现时有这些关键问题:

  • 一组帧应该以怎样的顺序来绘制?
  • 如何控制每一帧绘制的时间?
  • 在画布的什么位置绘制帧?
  • 如何控制绘制的帧的内容、图片大小?

策略: 帧动画控制类Animation

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// Animation类.动画类
// cfg为Object类型的参数集, 其属性会覆盖Animation原型中定义的同名属性.
function Animation(cfg){
	for (var attr in cfg ){
		this[attr]=cfg[attr];
	}
}

Animation.prototype={
	constructor :Animation ,

	// Animation 包含的Frame, 类型:数组
	frames : null,
	// 包含的Frame数目
	frameCount : -1 ,
	// 所使用的图片id(在ImgCache中存放的Key), 字符串类型. 
	img : null,
	// 当前播放的 frame
	currentFrame : null ,
	// 当前播放的帧
	currentFrameIndex : -1 ,
	// 已经播放的时间
	currentFramePlayed : -1 ,
	
	// 初始化Animation
	init : function(){
		// 根据id取得Image对象
		this.img = ImgCache[this.img]||this.img;
		
		this.frames=this.frames||[];
		this.frameCount = this.frames.length;
		
		// 缺省从第0帧播放
		this.currentFrameIndex=0;
		this.currentFrame=this.frames[this.currentFrameIndex];
		this.currentFramePlayed=0;
	},
	
	
	// 更新Animation状态. deltaTime表示时间的变化量.
	update : function(deltaTime){
		//判断当前Frame是否已经播放完成, 
		if (this.currentFramePlayed>=this.currentFrame.duration){
			//播放下一帧
			
			if (this.currentFrameIndex >= this.frameCount-1){
				//当前是最后一帧,则播放第0帧
				this.currentFrameIndex=0;
			}else{
				//播放下一帧
				this.currentFrameIndex++;
			}
			//设置当前帧信息
			this.currentFrame=this.frames[ this.currentFrameIndex ];
			this.currentFramePlayed=0;
		
		}else{
			//增加当前帧的已播放时间.
			this.currentFramePlayed += deltaTime;
		}
	},
	
	//绘制Animation
	draw : function(gc,x,y){
		var f=this.currentFrame;
		gc.drawImage(this.img, f.x , f.y, f.w, f.h , x, y, f.w, f.h );
	}
};

Animation负责读取、配置、更新帧数据,控制帧数据的播放

读取:

创建一个Animation对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	// 创建一个Animation对象
	var animation = new Animation({
		img : "player" ,
		//该动画由3帧构成,对应图片中的第一行.
		frames : [
			{x : 0, y : 0, w : 50, h : 60, duration : 100},
			{x : 50, y : 0, w : 50, h : 60, duration : 100},
			{x : 100, y : 0, w : 50, h : 60, duration : 100}
		]
	} );
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function Animation(cfg){
	for (var attr in cfg ){
		this[attr]=cfg[attr];
	}
}

// Animation类.动画类 // cfg为Object类型的参数集, 其属性会覆盖Animation原型中定义的同名属性.

配置:

初始化Animation对象:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	// 初始化Animation
	animation.init();

初始化函数代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	// 初始化Animation
	init : function(){
		// 根据id取得Image对象
		this.img = ImgCache[this.img]||this.img;
		
		this.frames=this.frames||[];
		this.frameCount = this.frames.length;
		
		// 缺省从第0帧播放
		this.currentFrameIndex=0;
		this.currentFrame=this.frames[this.currentFrameIndex];
		this.currentFramePlayed=0;
	},

更新帧数据:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		// 更新Animation状态
		animation.update(deltaTime);

更新函数代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	// 更新Animation状态. deltaTime表示时间的变化量.
	update : function(deltaTime){
		//判断当前Frame是否已经播放完成, 
		if (this.currentFramePlayed>=this.currentFrame.duration){
			//播放下一帧
			
			if (this.currentFrameIndex >= this.frameCount-1){
				//当前是最后一帧,则播放第0帧
				this.currentFrameIndex=0;
			}else{
				//播放下一帧
				this.currentFrameIndex++;
			}
			//设置当前帧信息
			this.currentFrame=this.frames[ this.currentFrameIndex ];
			this.currentFramePlayed=0;
		
		}else{
			//增加当前帧的已播放时间.
			this.currentFramePlayed += deltaTime;
		}
	},

播放:

就是绘制帧动画:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		//绘制Animation
		animation.draw(context, x,y);
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	//绘制Animation
	draw : function(gc,x,y){
		var f=this.currentFrame;
		gc.drawImage(this.img, f.x , f.y, f.w, f.h , x, y, f.w, f.h );
	}

再来看帧动画播放需要掌握的那些知识点:

1.一组帧应该以怎样的顺序进行播放

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
		// 缺省从第0帧播放
		this.currentFrameIndex=0;

2.如何控制每一帧的绘制时间:

当 当前帧 播放没有完成的时候:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
			//增加当前帧的已播放时间.
			this.currentFramePlayed += deltaTime;

当 当前帧 播放完成的时候:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.currentFramePlayed=0;

3.在画布的什么位置开始绘制:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
	//绘制Animation
	draw : function(gc,x,y){
		var f=this.currentFrame;
		gc.drawImage(this.img, f.x , f.y, f.w, f.h , x, y, f.w, f.h );
	}

4. 如何控制绘制的帧的内容、图片大小:

帧内容:首先是一个数组 frames[],其次是当前播放的帧 currentFrame : null ,

初始化时控制操作:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
this.currentFrame=this.frames[this.currentFrameIndex];

currentFrameIndex : -1 ,可以看作是一个索引

更新的时候:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
			//设置当前帧信息
			this.currentFrame=this.frames[ this.currentFrameIndex ];

最后提供源代码:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<meta http-equiv="Pragma" content="no-cache" />
<meta http-equiv="Expires" content="-1" />
<meta http-equiv="Cache-Control" content="no-cache" />


<title>My first Game</title>

<style type="text/css">
body {
	border:none 0px;
	margin:0px;
	padding:10px;
	font-size : 16px;
	background-color : #f3f3f3;
}

canvas {
	border : 1px solid blue; 
}
</style>


<script type="text/javascript">

// 加载图片
function loadImage(srcList,callback){
	var imgs={};
	var totalCount=srcList.length;
	var loadedCount=0;
	for (var i=0;i<totalCount;i++){
		var img=srcList[i];
		var image=imgs[img.id]=new Image();		
		image.src=img.url;
		image.οnlοad=function(event){
			loadedCount++;
		}		
	}
	if (typeof callback=="function"){
		var Me=this;
		function check(){
			if (loadedCount>=totalCount){
				callback.apply(Me,arguments);
			}else{		
				setTimeout(check,100);
			}	
		}
		check();
	}
	return imgs;
}

//定义全局对象
var ImgCache=null;
var canvas=null;
var context=null;

// 页面初始化函数
function init(){
	
	// 创建canvas,并初始化 (我们也可以直接以标签形式写在页面中,然后通过id等方式取得canvas)
	canvas=document.createElement("canvas");
	canvas.width=600;
	canvas.height=400;
	document.body.appendChild(canvas);
		
	// 取得2d绘图上下文 
	context= canvas.getContext("2d");
	
	//加载图片,并存入全局变量 ImgCache, 
	// 加载完成后,调用startDemo
	ImgCache=loadImage( [ 
			{ 	id : "player",
				url : "../res/player.png"
			},
			{ 	id : "bg",
				url : "../res/bg.png"
			}
		], 
		startDemo );

}


// Animation类.动画类
// cfg为Object类型的参数集, 其属性会覆盖Animation原型中定义的同名属性.
function Animation(cfg){
	for (var attr in cfg ){
		this[attr]=cfg[attr];
	}
}

Animation.prototype={
	constructor :Animation ,

	// Animation 包含的Frame, 类型:数组
	frames : null,
	// 包含的Frame数目
	frameCount : -1 ,
	// 所使用的图片id(在ImgCache中存放的Key), 字符串类型. 
	img : null,
	// 当前播放的 frame
	currentFrame : null ,
	// 当前播放的帧
	currentFrameIndex : -1 ,
	// 已经播放的时间
	currentFramePlayed : -1 ,
	
	// 初始化Animation
	init : function(){
		// 根据id取得Image对象
		this.img = ImgCache[this.img]||this.img;
		
		this.frames=this.frames||[];
		this.frameCount = this.frames.length;
		
		// 缺省从第0帧播放
		this.currentFrameIndex=0;
		this.currentFrame=this.frames[this.currentFrameIndex];
		this.currentFramePlayed=0;
	},
	
	
	// 更新Animation状态. deltaTime表示时间的变化量.
	update : function(deltaTime){
		//判断当前Frame是否已经播放完成, 
		if (this.currentFramePlayed>=this.currentFrame.duration){
			//播放下一帧
			
			if (this.currentFrameIndex >= this.frameCount-1){
				//当前是最后一帧,则播放第0帧
				this.currentFrameIndex=0;
			}else{
				//播放下一帧
				this.currentFrameIndex++;
			}
			//设置当前帧信息
			this.currentFrame=this.frames[ this.currentFrameIndex ];
			this.currentFramePlayed=0;
		
		}else{
			//增加当前帧的已播放时间.
			this.currentFramePlayed += deltaTime;
		}
	},
	
	//绘制Animation
	draw : function(gc,x,y){
		var f=this.currentFrame;
		gc.drawImage(this.img, f.x , f.y, f.w, f.h , x, y, f.w, f.h );
	}
};



// Demo的启动函数
function startDemo(){
	
	// 一些简单的初始化, 
	var FPS=30;
	var sleep=Math.floor(1000/FPS);
	
	//初始坐标
	var x=0, y=284;
	
	// 创建一个Animation对象
	var animation = new Animation({
		img : "player" ,
		//该动画由3帧构成,对应图片中的第一行.
		frames : [
			{x : 0, y : 0, w : 50, h : 60, duration : 100},
			{x : 50, y : 0, w : 50, h : 60, duration : 100},
			{x : 100, y : 0, w : 50, h : 60, duration : 100}
		]
	} );
	// 初始化Animation
	animation.init();
	
	//主循环
	var mainLoop=setInterval(function(){

		//距上一次执行相隔的时间.(时间变化量), 目前可近似看作sleep.
		var deltaTime=sleep;
		
		// 更新Animation状态
		animation.update(deltaTime);
	
		//使用背景覆盖的方式 清空之前绘制的图片
		context.drawImage(ImgCache["bg"],0,0);
				
		//绘制Animation
		animation.draw(context, x,y);
		
	},sleep);

}





	
</script>

</head> 
<body οnlοad="init()"> 


<div align="center"><a href="http://www.linuxidc.com" target="_blank">www.Linuxidc.com</a></div>
</body>
</html>
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
从Chrome小恐龙游戏学习2D游戏制作
在chrome浏览器的断网页面,按空格键或者向上键会出现一个小恐龙跑酷小游戏,这个2D小游戏在设计上精致小巧,在代码上也只有三千多行,思路清晰严谨,很有学习价值
异名
2020/10/29
1.7K0
从Chrome小恐龙游戏学习2D游戏制作
超级玛丽HTML5源代码学习------(二)
首先放置源代码: <!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="-1" /> <meta http-equiv="Cache-Control" content="no-cache" />
wust小吴
2022/03/03
1.8K0
超级玛丽HTML5源代码学习------(二)
超级玛丽HTML5源代码学习-----(三)
定义和用法 setInterval() 方法可按照指定的周期(以毫秒计)来调用函数或计算表达式。 setInterval() 方法会不停地调用函数,直到 clearInterval() 被调用或窗口被关闭。由 setInterval() 返回的 ID 值可用作 clearInterval() 方法的参数。 语法 setInterval(code,millisec[,"lang"]) 参数 描述 code 必需。要调用的函数或要执行的代码串。 millisec 必须。周期性执行或调用 code 之间的时间间隔,以毫秒计。 返回值 一个可以传递给 Window.clearInterval() 从而取消对 code 的周期性执行的值。
wust小吴
2022/03/03
1.3K0
Canvas基础-粒子动画Part2
紧接上一篇文章 Canvas基础-粒子动画Part1 其实这篇早在一个星期之前就应该发了,无奈事情太多,而且我又跑去写微信公众号了。 粒子动起来 有了上一篇的基础,我们已经可以获得粒子,并将轮廓显示在Canvas上,如果看了之前我写的一些关于 Canvas动画啊,画图啊什么文章的话,其实应该已经很清楚如何去让这些粒子动起来。 这里我们重新定义一个draw2()方法,init()等还是和Part1一样,对图片进行取样,获取粒子的位置,保存在Dot对象里面,这里就省略了。 要让粒子动起来无非是不断的计算粒
Bob.Chen
2018/05/02
1.4K1
Canvas基础-粒子动画Part2
腾讯课堂 H5 直播间点赞动效实现
1. 前言 以前在看微信视频号直播的时候,经常点击右下角的点赞按钮。看着它的数字慢慢从一位数变成五位数,还是挺有氛围感的。特别是长按的时候,有个手机震动的反馈,很带感。 虽然之前很好奇这些飘动的点赞动效是怎么实现的,但没有特别去钻研。直到前阵子投入腾讯课堂 H5 直播间的需求,需要自己去实现一个这样的效果时,才开始摸索。 先看看最后的效果: 相比视频号的点赞动效,轨迹复杂了很多。可以看到课堂直播间的这一段点赞动效,大概分为这么三个阶段: 从无到有,在上升过程中放大成正常大小 上升过程中左右摇曳,且摇曳
用户1097444
2022/06/29
9480
腾讯课堂 H5 直播间点赞动效实现
超级玛丽HTML5源代码学习------(一)
<pre name="code" class="html"><!doctype html> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <meta http-equiv="Pragma" content="no-cache" /> <meta http-equiv="Expires" content="-1" /> <meta http-equiv="Cache-Control" co
wust小吴
2022/03/03
1.4K0
【不可思议的CANVAS】画一只会跟着鼠标走的小狗
这个例子来自于[CodePen],它是根据鼠标的位置设置两个眼球的transform: rotate属性做的效果。
coder_koala
2020/09/17
8250
HTML5 Canvas学习笔记
鸟:https://i.loli.net/2019/08/14/yRFjQEdoSpx9YDa.png
戴兜
2023/02/23
3960
【前端词典】实现 Canvas 下雪背景引发的性能思考
代码已上传至 github 【https://github.com/wanqihua/koa-canvas】
小生方勤
2019/06/01
9270
制作高大上的Canvas粒子动画
制作粒子动画效果要解决两个问题:一个是粒子动画轨迹,另外一个是粒子执行动画的时机。 首先来看下我们准备要做的粒子动画效果是怎么样的~ 是这样(粒子漂浮): 或者这样(粒子轨迹动画): 甚至是这样
练小习
2017/12/29
2.6K0
初识HTML5
客观地讲,没有不好的技术,只有没有用好的技术。JavaScript 的坎坷遭遇让我不禁想起了另一种被人们滥用的技术:Adobe公司研发的 Flash。
林清猫耳
2018/12/04
1.6K0
通过游戏学javascript系列第一节Canvas游戏开发基础
HTML5引入了canvas元素。canvas元素为我们提供了一块空白画布。我们可以使用此画布来绘制和绘制我们想要的任何东西。JavaScript为我们提供了动态制作动画并绘制到画布上所需的工具。它不仅提供绘图和动画系统,还可以处理用户交互。在本教程中,我们将使用纯JavaScript制作基本的HTML5 Canvas框架,该框架可用于制作真实的游戏。在本教程的结尾创建了一个非常简单的游戏,以演示HTML5 Canvas与JavaScript结合的优势。
huofo
2022/03/18
8170
通过游戏学javascript系列第一节Canvas游戏开发基础
ChatGPT教你APP性能评测分析
请打开智造喵GPT地址:https://chat.plexpt.com/i/511440
用户10443079
2023/04/25
1.2K0
ChatGPT教你APP性能评测分析
HTML5(九)——超强的 SVG 动画
SVG 动画有很多种实现方法,也有很大SVG动画库,现在我们就来介绍 svg动画实现方法都有哪些?
呆呆
2021/09/30
3.4K0
微信小程序 案例二 飞机大战
提供了一个通过JavaScript 和 HTML的canvas元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。
万少
2025/02/08
1500
微信小程序 案例二 飞机大战
HTML5 canvas 粒子特效显示图像/文字
本次实例将图片或文字分解成粒子。是先将图片或者文字画在canvas上,然后通过画布对象的getImageData获取到画布上的所有像素点,也就是imageData对象的data数组,存放着画布的所有像素的rgba值。
用户5997198
2019/08/09
6.2K0
HTML5 canvas 粒子特效显示图像/文字
SVGA源码解析
主要是decodeFromInputStream方法,读取解析来自URL的svga文件,并缓存成本地文件
雁字回时
2022/12/13
7690
HTML5(六)——Canvas 高级操作
angle 旋转弧度,如果想使用角度,可以把角度转成弧度,公式为:deg * Path.PI/180。
呆呆
2021/09/29
1.4K0
听说你也在开发年终盘点?送你一篇详尽的踩坑实战~
年终了,听说你也在开发年终盘点?也许你可以看看这篇腾讯 ABCmouse 圣诞年终盘点活动页的踩坑实战记录。 圣诞节的时候 ABCmouse 为用户精心准备了一份圣诞礼物,你也想看下吗?快来扫下这个神奇的二维码... 好吧,知道你可能不想扫码 '__' ,直接看下图吧(截取了其中一段) 当然了,这篇文章不是介绍整个开发过程(实际上本身开发周期很短,开发才三天,另外两天bugfix和视觉还原,时间非常赶)。这篇文章主要记录我在开发的过程的过程的一些经验总结和遇到的坑。 坑一:视频坑 这次的年终盘点在前
用户1097444
2022/06/29
7530
听说你也在开发年终盘点?送你一篇详尽的踩坑实战~
Canvas基础-粒子动画Part4
在之前的文章 Canvas基础-粒子动画Part2 和 Canvas基础-粒子动画Part3 中分别讲了用图片和文字做粒子动画,今天我们来把代码简单整理一下,封装成一个类,能同时支持用图片和文字做粒子动画,而且有更好的灵活性。 封装类 HTML结构和上一篇的一样,这里从外部引入一个js文件,我们的类就写这里面。 <body> <div class="input-wrap"> <input id="txt" type="text" name="" valu
Bob.Chen
2018/05/02
1.1K0
Canvas基础-粒子动画Part4
相关推荐
从Chrome小恐龙游戏学习2D游戏制作
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验