首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >超级玛丽HTML5源代码学习------(四)

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

作者头像
wust小吴
发布于 2022-03-03 12:42:13
发布于 2022-03-03 12:42:13
1.7K00
代码可运行
举报
文章被收录于专栏:风吹杨柳风吹杨柳
运行总次数: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 删除。

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

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
flask框架(二)配套代码
1、cookie.py """ - 解释: 用来保持服务器和浏览器交互的状态的, 由服务器设置,存储在浏览器 - 作用: 用来做广告推送 - cookie的设置和获取 - 设置cookie: response.set_cookie(key,value,max_age) - max_age: 表示cookie在浏览器的存储时间,单位是秒 - 获取cookie: request.cookies.get("key") """ from flask import Flask, make_res
小闫同学啊
2019/07/18
1.4K0
Flask模板和静态文件(一)
lask是一款基于Python的Web框架,它支持使用模板和静态文件来构建Web应用程序。模板和静态文件可以帮助我们轻松地组织和管理Web应用程序中的视图和资源。
堕落飞鸟
2023/05/05
1.3K1
Flask学习笔记-Flask模板集成Bootstrap 顶
Flask模板集成Bootstrap。一般情况下Flask都是搭配Jinja2模板引擎来实现视图展现,不过现在Bootstrap比较流行,内置的样式也比较好看,有利于提高开发效率,本篇文章就是讲解在Flask如何集成Bootstrap框架。
bdcn
2018/09/12
2.2K0
Flask学习笔记-Flask模板集成Bootstrap
                                                    顶
慕课网Flask高级编程实战-7.静态文件、模板、消息闪现与Jinja2
Flask访问静态文件非常简单,只需要在项目根目录建立static文件夹。将静态资源文件放入static下即可。访问的时候访问http://ip:port/static/fileName即可。
Meet相识
2018/09/12
9950
慕课网Flask高级编程实战-7.静态文件、模板、消息闪现与Jinja2
Flask入门很轻松(三)—— 模板
转载请在文章开头附上原文链接地址:https://www.cnblogs.com/Sunzz/p/10959471.html
py3study
2020/01/15
2.2K0
Flask(9)- 蓝图的基本使用
程序中包含 4 个视图函数,根据页面路径,Flask 将请求转发给对应的视图函数,从浏览器发送过来的请求的处理过程如下图所示
小菠萝测试笔记
2021/07/16
9990
Flask(9)- 蓝图的基本使用
Flask学习与项目实战3:简单入手模板及高阶使用
声明:本学习系列笔记是来源B站 知了传课 up主的教学视频的个人学习笔记,原up主教学视频地址:https://www.bilibili.com/video/BV17r4y1y7jJ?p=10。
程序员洲洲
2024/06/07
1720
Flask学习与项目实战3:简单入手模板及高阶使用
Flask 学习篇二:学习Flask过程中的记录
Flask学习笔记: GitHub上面的Flask实践项目 https://github.com/SilentCC/FlaskWeb 1.Application and Request Context(上下文) 在Flask 中,一般一个view function(视图函数)会处理一个请求 Flask 中提供request context.保证全局只有一个线程的request,而不会同时出现两个request. Application and Request Context 一共有四种
ShenduCC
2018/04/27
1.8K0
Flask 静态文件、模板文件设置
在Django项目中,如果需要访问静态文件,默认则是使用 /static 的前缀来进行访问。那么对于Flask来说,也是一样的。
Devops海洋的渔夫
2019/10/28
5.8K0
Flask 静态文件、模板文件设置
flask框架2_flask框架介绍
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/179055.html原文链接:https://javaforall.cn
全栈程序员站长
2022/09/27
8070
flask框架2_flask框架介绍
Python Web - Flask笔记2
导入config.py后app.config.from_object(config)
YingJoy_
2018/08/02
2K0
Flask Jinja2 模板中的变量和过滤器
通常,返回的 Jinja2 模板文件并不是一个静态的页面,而是同时有静态部分和动态部分。
Python碎片公众号
2021/02/26
3.2K0
Flask Jinja2 模板中的变量和过滤器
Flask 框架:运用Ajax实现数据交互
使用Ajax技术网页应用能够快速地将增量更新呈现在用户界面上,而不需要重载刷新整个页面,这使得程序能够更快地回应用户的操作,如下笔记将简单介绍使用AJAX如何实现前后端数据通信。
王 瑞
2022/12/28
1.3K0
Python Flask 学习笔记 —— 二(路由,视图函数,jinjia2语法)
客户端(Web 游览器)发送网络请求到 Web 服务器,Web 服务器再把请求转发给 Flask 程序实例。程序实例需要知道每个 URL 请求运行哪些代码。所以保存了一个 URL 到 Python 函数的映射关系。处理 URL 和函数之间的关系的程序叫做 路由
Gorit
2021/12/08
1.8K0
Python Flask 学习笔记 —— 二(路由,视图函数,jinjia2语法)
Flask
1.Flask实例配置 app.config.form_object("setting.FlaskSetting") app.DEBUG = True 开启Debug模式,该完代码不用手动重启 app.SECRET_KEY = "xxxxx" 开启session必备参数
py3study
2020/01/19
1.9K0
Flask
Flask 模板 - 变量、过滤器
在大型应用中,把业务逻辑和表现内容放在一起,会增加代码的复杂度和维护成本。这次的模板内容主要的作用即是承担视图函数的另一个作用,即返回响应内容。
Devops海洋的渔夫
2019/12/19
1.3K0
Flask 快速入门
Flask是一个Python编写的Web 微框架,让我们可以使用Python语言快速实现一个网站或Web服务。本文参考自Flask官方文档,大部分代码引用自官方文档。 安装Flask 首先我们来安装F
乐百川
2018/01/09
1.6K0
Flask 快速入门
Flask快速入门,知识整理
一、Flask介绍(轻量级的框架,非常快速的就能把程序搭建起来)   Flask是一个基于Python开发并且依赖jinja2模板和Werkzeug WSGI服务的一个微型框架,对于Werkzeug本质是Socket服务端,其用于接收http请求并对请求进行预处理,然后触发Flask框架,开发人员基于Flask框架提供的功能对请求进行相应的处理,并返回给用户,如果要返回给用户复杂的内容时,需要借助jinja2模板来实现对模板的处理,即:将模板和数据进行渲染,将渲染后的字符串返回给用户浏览器。 “微”(mic
用户1214487
2018/01/24
2.1K0
Flask快速入门,知识整理
使用Flask构建个人简历网站
本文将介绍如何使用Flask框架来构建一个简单的个人简历网站。我们将重点讲解Flask中的路由处理、模板渲染以及静态文件的管理,并通过具体的代码示例来展示这些功能在实际开发中的应用。
大盘鸡拌面
2024/05/13
4430
Flask(初步入门 二)
安装 $ pip install flask werkzeug:处理application jinja2:渲染html flask:组装大师 初始化application from flask im
zx钟
2020/06/19
3700
相关推荐
flask框架(二)配套代码
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档