Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
2400字整理Python编码规范,肝了一晚上~
对任何一门语言来说,学习编码规范都是第一要务,它制定了“游戏规则”,约束了我们的行动,我们只有在这个规则内编码才能被正确执行。想要写好Python代码,了解Python相关编码规范也是必要的。
程序员树先生
2023/02/22
1.1K0
2400字整理Python编码规范,肝了一晚上~
一篇文章教你快速了解并使用Python基础语法
首先必须说明的是,Python语言在任何场景都严格区分大小写!也就是说A和a代表的意义完全不同
汤贤
2020/05/18
5210
一篇文章教你快速了解并使用Python基础语法
Python全网最全基础课程笔记(一)——基础入门
Python是一种高级的、解释型、动态类型的编程语言,由Guido van Rossum(吉多·范罗苏姆)于1989年首次发布。Python以其简洁性、易读性和可扩展性而广受欢迎,被广泛应用于各个领域。以下是对Python基本概念、重点部分及常用领域的详细解析,以及针对新手的学习建议。
小白的大数据之旅
2024/11/20
6400
Python全网最全基础课程笔记(一)——基础入门
初识Python(注释、代码缩进、编码规范、标识符、变量)
在Python中使用"#“作为单行注释的符号,从符号”#“开始直到换行为止,”#"后面所有的内容都作为注释内容,同时注释内容会被Python编译器忽略 单行注释可以放在要注释代码的前一行,也可放在要注释代码的右侧
hacker707
2023/04/06
8880
初识Python(注释、代码缩进、编码规范、标识符、变量)
复习Python第一天
由于已经安装了Python,所以就不打算重新去安装环境了,直接开始复习,不会的可以直接去这一篇操作
sjw1998
2019/09/28
5640
Java基础入门篇(二)——Java注释、关键字和标识符
前面几篇文章用Java带大家一起了解了几个游戏小项目,感兴趣的小伙伴可以点击文章观摩下,手把手教你用Java打造一款简单故事书(上篇)、手把手教你用Java打造一款简单故事书(下篇)、手把手教你用Java打造一款简单考试系统(上篇)、手把手教你用Java打造一款简单考试系统(下篇)接下来的几篇文章是关于Java基础的,希望对大家的学习有帮助,欢迎大家在讨论区留言。
Java进阶者
2021/01/22
5680
2022年最新Python大数据之Python基础【一】
文章目录 Python 1、Python概述 2、Python解释器和pycharmIDE工具 3、Python中的注释 4、变量 5、标识符的命名规范 6、变量的使用 7、Python中的数据类型 8、Python中的bug和调试 9、字符串的格式化及输出 Python Python基础语法:标识符,关键字,变量,判断循环 。。。。 容器类型(数据类型中的高级类型) 函数 文件处理 面向对象 包和模块 异常处理 1、Python概述 创始人:吉多·范罗苏姆 龟叔 为什么要学习Python:大势所趋,简单易
Maynor
2022/08/15
6540
《Java从入门到失业》第三章:基础语法及基本程序结构(3.2-3.5):标识符、关键字、注释、变量及常量
       上面我们知道我们自定义一个类,需要一个类名。在Java中,还有很多需要命名的组成部分,例如方法名,变量名等。标识符的命名需要遵循Java的规范,总结如下:
用户7801119
2020/09/27
4130
01. Kotlin 标识符、关键字和注释
标识符就是变量、常量、函数、属性、类、接口和扩展等由程序员指定的名字。构成标识符的字符均有一定的规范,Kotlin 语言中标识符的命名规则如下:
acc8226
2023/02/02
4700
【Python从入门到精通】(三)Python的编码规范,标识符知多少?
您好,我是码农飞哥,感谢您阅读本文,欢迎一键三连哦。这是Pyhon系列文章的第三篇,本文主要介绍Python程序的编码规范。 干货满满,建议收藏,需要用到时常看看。小伙伴们如有问题及需要,欢迎踊跃留言哦~ ~ ~。
码农飞哥
2021/11/02
7030
【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字
​ 一个大型的工程,是由多名工程师协同开发的,如果每个人都按照自己的方式随意取名,比如:person、PERSON、Person、_person,将会使程序非常混乱。如果大家在取名时能够遵守一定的约束(即规范),那多人写除的代码仿佛一个人写的。
屿小夏
2024/01/22
1450
【Java探索之旅】我与Java的初相识(完):注释,标识符,关键字
从零开始的JavaSE:初识JavaSE & 基础语法
欢迎来到咸鱼干的博客!今天我们将一起开始探索JavaSE,从零开始,逐步建立对Java编程语言的理解。
一条晒干的咸鱼
2025/01/12
1140
从零开始的JavaSE:初识JavaSE & 基础语法
[Python零基础入门篇⓪⑤] - Python初学者需要牢记的几种编码规范
在 标准、规范、大行其道的今天,任何行业、任何事物、任何职业、任何机器...都有自己的一套标准、规范或者流程。在各种编程语言中同样也存在着一定的规范,那就是==编程规范==,虽然有的语言中体现的不是很直观,甚至即使不规范也不影响代码、脚本的执行与执行结果的输出。然而一个合理的编程规范在初学者学习编写代码、熟记编码规则对日后的编写规范是影响非巨大的!而已作为当下最流行的编程语言之一的 Python 当然也不例外。
哈哥撩编程
2024/06/16
1970
[Python零基础入门篇⓪⑤] - Python初学者需要牢记的几种编码规范
Python 语法介绍
Python 语句以 回车 结束,即Python 脚本中的每一行都是一条语句。下面的 Python 脚本三行代表三条不同的语句。
Taobaoapi2014
2023/12/20
2180
Python基本语法与数字类型
在python3中,默认的情况下,源码文件的编码为UTF-8,所有的字符串都是Unicode字符串。而python2中则是ASCII编码,使用python2的话需要设置编码为UTF-8,这一点要区分。python3相对于python2区别比较大,并且两者不兼容。
端碗吹水
2020/09/23
8480
Python基本语法与数字类型
Java初识总结(java程序结构组成、代码运行、注释、关键字、标识符)
在一个源文件中,只能有一个public修饰的类,源文件名字必须和public修饰的类的名字相同。
用户11162265
2024/08/05
1010
Java初识总结(java程序结构组成、代码运行、注释、关键字、标识符)
Java 基础教学:基础语法 - 注释、标识符与关键字
Java是一种广泛使用的编程语言,它的语法规则和结构为编程提供了清晰的框架。为了编写出易于理解和维护的代码,必须掌握Java的基本语法元素,包括注释、标识符和关键字。本文档将详细介绍这些概念,并提供示例以帮助初学者了解和应用。
世间万物皆对象
2024/10/22
1810
Python新手快速入门教程-基础语法
交互式编程不需要创建脚本文件,是通过 Python 解释器的交互模式进来编写代码。
一墨编程学习
2018/12/11
1.1K0
Python新手快速入门教程-基础语法
菜鸟学Python——初识Python
很多初学Python的同学经常问我这样的问题:学Python应该看什么书啊?我会非常自信的把之前整理的Python教程扔给他,后来收到很多反馈:你的排版太烂了,你遗漏了好多知识点,能不能加一点练习题?
PM小王
2019/06/28
1.3K0
菜鸟学Python——初识Python
JavaNote[001] - 注释、标识符、关键字、变量
Java学习的基础知识,因为之前学习过了就2倍速快速过了一下,下面是一些简单的笔记?,顺手就记录下来了。 1 注释 注释不会出现在字节码中,也就是说Java编译器编译的时候会忽略我们的注释内容,这样子
Sam Gor
2020/05/28
5570
推荐阅读
相关推荐
2400字整理Python编码规范,肝了一晚上~
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验