技术具有"继承性、延展性"
修正为:
技术具有"延续性,延展性"
本篇目的:
- 为什么不能使用DOM内置的事件分发系统
- 暂时先选择鼠标事件
- 实现一个简单的鼠标事件分发和处理框架
- demo演示与验证
由于动画,数学,碰撞等demo演示,需要进行事件交互。
目前还没有事件分发系统,因此今天我们来实现一个简单的事件分发系统以及事件处理的流程
为什么不能使用DOM内置的冒泡事件系统
很简单,因为DOM事件系统仅能分发到canvas元素。
而我们的2D精灵系统是直接通过canvas2D绘制出来的,并没有并入到DOM文档树中,因此DOM 事件分发到canvas后,就结束了。
所以我们要在事件分发到canvas后,继续进行分发给每个精灵,让他们有机会接受到事件并进行处理。这就是今天的任务!!
暂时先选择鼠标事件
原因:
在手机端,竖屏显示范围太小了,查了一些资料,发现h5目前没有一个通用的进入页面直接横屏的功能,需要研究一下变通的实现方式。
如果一旦实现手机端自动横屏效果,我会将mouse事件更改为touch事件,也就是几句代码的事情
touch/mouse事件最大区别是move事件。只要鼠标移动就会产生mousemove事件。而touchmove事件必须按下移动才产生。后面我一些例子,建立在mousemove基础上
关键原因就是我现在还没实现h5页面自动横屏效果。导致手机演示不是很爽。
实现一个简单的鼠标事件分发和处理系统
- 需要一个函数,将窗口客户区坐标转换到canvas2D坐标表示,该函数就加在BLFRender2D中去吧:
ToCanvasCoord(x, y) {
var bbox = this.context.canvas.getBoundingClientRect();
return {
x: x - bbox.left * (this.context.canvas.width / bbox.width),
y: y - bbox.top * (this.context.canvas.height / bbox.height)
};
}
原因和如何使用,等会demo会演示和解释
- BLFSprite基类中增加鼠标事件处理方法:
onMouseDown(x, y) {
console.log("deal mouseDown event");
return false;
}
onMouseUp(x, y) {
console.log("deal mouseUp event");
return false;
}
onMouseMove(x, y) {
console.log("deal mouseMove event");
return false;
}
关于返回值true/false,请看下面的代码注释
- BLFSpriteManager中增加事件分发函数:
dispatchMouseDownEvent(x, y) {
//超级简单,用于演示用的事件分发体系
//事件分发是核心之一
//目前比较流行的有:dom3 level3事件系统
// ios responder 职责链事件系统
// android中那个复杂无比,效率底下的事件分发系统(会被骂吗?哈哈)
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精灵事件处理完成(true),就中断事件分发
if (this.sprites[i].onMouseDown(x, y))
return;
}
}
dispatchMouseUpEvent(x, y) {
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精灵事件处理完成(true),就中断事件分发
if (this.sprites[i].onMouseUp(x, y))
return;
}
}
dispatchMouseMoveEvent(x, y) {
for (let i = this.sprites.length - 1; i >= 0; i--) {
//如果i指向的精灵事件处理完成(true),就中断事件分发
if (this.sprites[i].onMouseMove(x, y))
return;
}
}
- 如果循环中当前i指向的精灵事件处理完成(true),就中断事件分发,退出函数
- 事件分发循环是从后到前方式(let i = this.sprites.length - 1; i >= 0; i--),这是因为当两个精灵重叠时,肯定是上面的精灵进行事件处理,而不是被遮挡住的精灵(先前景,后背景)
- 而绘制时,肯定是先背景,后前景(昨天孩子写生油画,老师讲解也强调如此,经典的画家算法)
- 最后,在BLFEngine2D的构造函数中将DOM 事件转发到各个精灵上:
canvas.addEventListener("mousedown", (e) => {
//先将客户区的点转换为相对canvas坐标系的点表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
console.log("e.clientX = " + e.clientX + " e.clientY = " + e.clientY);
console.log("canvasX = " + pt.x + " canvasY = " + pt.y);
this.sprMgr.dispatchMouseDownEvent(pt.x, pt.y);
}, false);
canvas.addEventListener("mouseup", (e) => {
//先将客户区的点转换为相对canvas坐标系的点表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
this.sprMgr.dispatchMouseUpEvent(pt.x, pt.y);
}, false);
canvas.addEventListener("mousemove", (e) => {
//先将客户区的点转换为相对canvas坐标系的点表示
let pt = this.render.ToCanvasCoord(e.clientX, e.clientY);
this.sprMgr.dispatchMouseMoveEvent(pt.x, pt.y);
}, false);
关键的一步是将客户区的点转换为相对canvas坐标系的点表示。可能的情况是你的canvs画布的原点和客户区的原点没有重合时,如果不进行坐标变换,会出现非常大的问题
关于DOM3 level3 冒泡事件,我个人是非常喜欢的一种事件分发体系。其实使用中有很多诀窍。本系列中,我会专门抽一章来聊一聊冒泡事件。实际上,我从webkit中抽取了很多超级有用的代码,包括冒泡事件系统(webkit我个人感觉应该是超过100万行代码的庞大c++程序)
demo演示与验证:
以前我们的demo都是canvs画布与客户区原点对齐的
现在我们改变一下:将canvas右移100个像素
- 使用绝对定位,left设置为100px,css一定要用单位哦
添加画布,使用canvas样式:
客户区: 649 392
canvas: 549 384
红色框部分左右差100 px
蓝色框部分上下差8 px
问题: 为什么客户区和canvas上下差8px?(有兴趣可以留言回答)
本篇结束,下一篇我们进入鼠标hitTest方面的内容
附:
昨天晚上听了一堂视听课,关于mysql MyISAM/InnoDB 索引底层实现(B+树)。收获是巨大的。只有了解了原理,才能有效的使用!。
其实我个人一直很努力的学习各种树结构,它太重要了!!
quake3中实现的自适应哈夫曼树(用于网络传输数据最小化)
quake3 BSP树(整个quake引擎之所以如此高效,就是因为使用了binary space partitioning tree,空间二叉分割树)
分割空间,加快渲染,与碰撞检测的quadtree(二维分割,四叉树,广泛用于地形渲染和碰撞检测),octree(三维分割,八叉树)
kd树(四叉/八叉都是kd的特殊形式)
用于ui/2d/3d中组成场景用的通用树结构
用于加快室内场景管理,动态光影计算的portal树
各种加快碰撞检测的包围体层次树
还有就是数据结构中各种经典的树结构:二叉树,红黑树,还有昨天的b树/b+树......
树是非常非常非常重要的数据结构,如果想深入了解图形,数据库,游戏引擎等,那么各种树的数据结构一定要了解,并且知道用在哪些方面
设计模式在UI系统开发中的应用(导读)这篇文章中,提供了一个通用树结构相关图,很值得研究
在闲聊c++系列中,我的文章以基础知识为主。别看现在外面的新技术层出不穷,但本质都是很基础的知识。
一个新技术不可能是凭空出来的,技术都是具有:
继承性 : 从上到下
延展性 : 从左到右
突然发现,好有哲理哦!!!
修正为:
一个新技术不可能是凭空出来的,技术都是具有:
延续性 : 从上到下
延展性 : 从左到右
这样比较押韵!!