Cocos Creator 2D摄像机 [Lv.1] 小视图
Posted VermillionTear
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Cocos Creator 2D摄像机 [Lv.1] 小视图相关的知识,希望对你有一定的参考价值。
摘要
本系列文章主要实操2D摄像机
,在官方Demo的基础上,做了适当的修改,并增加了新的内容。
文中对相关知识点进行适当展开,不做深入研究。
以实际操作做为出发点,帮助读者快速实现并且掌握2D摄像机
。
环境
- Cocos Creator 2.4.4
资源
准备工作
- 一张小姐姐的图片。
- 一张心形的图片。
- 创建Empty工程。
正式开始
对工程做一些修改
资源管理器
层级管理器
- 对节点的层级稍稍做了规范化,保证UI与代码分开,代码均挂载在
Controller
下对应的节点上。 - 创建
MiniMapController.js
脚本,并且挂载在MiniMapController
节点上。
之后节点相关的设置请参考工程中的设置,文中不再赘述。
场景编辑器
如何互动
小姐姐又来啦~
这回我们要来做一个类似于小地图的功能,在一个小的视图里,显示小姐姐的指定部位。
而这个功能就是通过2D摄像机
实现的。
上摄像机
创建一个2D摄像机
,
rect
属性,决定摄像机绘制在屏幕上哪个位置,值为(0 ~ 1),x
和y
为左下角的点。
所以如下设置,摄像机所照到的图像,就会绘制在屏幕的右上角。
看实际效果,
这么简单的设置,就有种已经要完成的感觉?
no, no, no,接下来我们要让它更加灵活一些。
缩放(看清黑头和脂肪粒)
缩放是通过控制摄像机的视窗大小(orthoSize
属性)而实现的,而默认创建出来的摄像机,会自动将视窗大小调整为整个屏幕的大小。所以如果想要完全自由地控制摄像机,则需要将alignWithScreen
属性设置为false
。
视窗的大小 * 2,就是摄像机能看到的高度。由于Canvas
默认的高度是640
,所以这里将orthoSize
设置为320
,让摄像机默认能看到整个屏幕。当然,你也可以设置其他的值,作为初始的视窗大小。
在MiniMapController.js
中实现功能。
let _canvasWidth = 0 // 场景宽
let _canvasHeight = 0 // 场景高
cc.Class({
extends: cc.Component,
properties: {
camera: cc.Camera, // 摄像机。
},
onLoad () {
// 初始化。
_canvasWidth = cc.Canvas.instance.node.width
_canvasHeight = cc.Canvas.instance.node.height
// 鼠标滚轮事件。通过鼠标滚轮,控制放大和缩小。
this.node.on(cc.Node.EventType.MOUSE_WHEEL, this.onMouseWheel, this)
},
// 鼠标滚轮事件响应函数。
onMouseWheel: function (event) {
let scrollY = event.getScrollY() // 滚动值,向上滚为1,向下滚为-1。
let orthoSize = this.camera.orthoSize
// orthoSize 的值越大,摄像机的视野就越大,所以画面就会变小,反之画面就会变大。
// 而我这里实际想要的功能是,滚轮向上滚,画面变大,所以这里减去滚动值。
// 1 个单位作为基本变化量,有些太慢了,所以这里用 5 个单位作为基本变化量。
orthoSize -= scrollY * 5
this.camera.orthoSize = orthoSize // 设置摄像机的视窗大小。
},
})
将节点挂载到脚本对应变量上。
由于鼠标事件需要依附于Node
节点上才能触发,所以我们需要将MiniMapController
节点设置为场景的大小(确保覆盖了整个场景),才能真正的触发鼠标事件。
运行起来,看看效果,
哇~ 原来小姐姐没有黑头,也没有脂肪粒,皮肤光滑且富有弹性~
动起来
缩放是做到了,但是如果我们想单独看看小姐姐那明亮的双眸,或是那bulingbuling的双唇……
在MiniMapController.js
中实现功能。
...
cc.Class({
...
onLoad () {
...
// 触摸移动事件。当在屏幕上滑动时,控制摄像机的移动。
this.node.on(cc.Node.EventType.TOUCH_MOVE,this.onTouchMove,this)
},
...
onTouchMove: function (event) {
// 这里获得的是,在屏幕坐标系下的坐标(不是this.node中的坐标)。
let pos = new cc.Vec2(event.getLocationX(), event.getLocationY())
// 转换为 camera 父节点中的坐标(camera的坐标实际上就是在其父节点坐标系下的坐标)。
pos = this.camera.node.parent.convertToNodeSpaceAR(pos)
// 重定位 camera 的位置。
this.camera.node.setPosition(pos.x, pos.y)
},
})
运行起来,看看效果,
哇~ 小姐姐bulingbuling的双唇。
辅助的边框
上面已经将基本的功能都实现了,但是看起来还是感觉有些别扭。照相机照到哪里,在原图上根本看不到,只能通过小视图中的图像判断。
所以接下来添加一些辅助的边框,帮助我们标注小视图以及摄像机照到的区域。
创建一个空节点,
并给其添加Graphics
组件,该组件可以像H5 Canvas
那样在屏幕上画图。
在MiniMapController.js
中实现功能。
...
cc.Class({
...
properties: {
...
brush: cc.Graphics, // 笔刷,用于在屏幕上画图。
},
...
update (dt) {
// 摄像机的位置以及视窗大小会变化,所以每一帧都绘制,绘制前先清空之前绘制的。
this.brush.clear()
// 绘制小视图的边界。
let cameraDisplayRect = this.calCameraDisplayRect() // 计算出小视图的边界(rect)。
this.brush.rect(cameraDisplayRect.x, cameraDisplayRect.y, cameraDisplayRect.width, cameraDisplayRect.height) // 绘制矩形。
this.brush.strokeColor = cc.Color.YELLOW // 设置画笔颜色。
this.brush.stroke() // 实际绘制。
// 绘制摄像机的视窗边界。
let cameraOrthoRect = this.calCameraOrthoRect() // 计算出视窗的边界(rect)。
this.brush.rect(cameraOrthoRect.x, cameraOrthoRect.y, cameraOrthoRect.width, cameraOrthoRect.height) // 绘制矩形。
this.brush.strokeColor = cc.Color.BLUE // 设置画笔颜色。
this.brush.stroke() // 实际绘制。
},
...
calCameraDisplayRect: function () {
let cameraRect = this.camera.rect // 摄像机绘制在屏幕上的位置。
// 摄像机的锚点。
let cameraAnchor = cc.Vec2(this.camera.node.anchorX, this.camera.node.anchorX)
// 绘制的矩形以左下角为原点,而摄像机的锚点在视窗的正中心。
// 根据 camera.rect 设置的比例,计算出实际在屏幕中的位置,以及宽高。
return new cc.Rect((cameraRect.x - cameraAnchor.x) * _canvasWidth,
(cameraRect.y - cameraAnchor.y) * _canvasHeight,
cameraRect.width * _canvasWidth,
cameraRect.height * _canvasHeight)
},
calCameraOrthoRect: function () {
let cameraPosition = this.camera.node.getPosition() // 摄像机的位置。
let orthoHeight = this.camera.orthoSize // 摄像机视窗的高度。
// 摄像机视窗的宽高比与场景的宽高比相同,所以通过场景的宽高比,计算出视窗的宽度。
let orthoWidth = orthoHeight * (_canvasWidth / _canvasHeight)
// 绘制的矩形以左下角为原点,而摄像机的锚点在视窗的正中心。
// 视窗的高度 * 2 = 摄像机能看到的高度;视窗的宽度 * 2 = 摄像机能看到的宽度。
return new cc.Rect(cameraPosition.x - orthoWidth,
cameraPosition.y - orthoHeight,
orthoWidth * 2,
orthoHeight * 2)
},
})
将节点挂载到脚本对应变量上。
运行起来,看看效果,
有了辅助的边框,看起来就更加直观了。
得有边界
拖动,缩放,拖动,缩放……
照相机的视窗有时会飞出屏幕外,小姐姐的靓照也就飞出了小视图外,这可不行,得有个边界。
在MiniMapController.js
中实现功能。
...
cc.Class({
...
onMouseWheel: function (event) {
...
orthoSize = this.limitOrthoSize(orthoSize) // 限定摄像机视窗在边界内。
...
// 摄像机不动,但视窗变大时有可能也会大到屏幕外,所以重新计算摄像机视窗的位置。
let pos = this.limitPos(this.camera.node.getPosition())
this.camera.node.setPosition(pos.x, pos.y)
},
onTouchMove: function (event) {
...
pos = this.limitPos(pos) // 限定为边界内的坐标。
...
},
...
limitOrthoSize: function (orthoSize) {
let val = orthoSize
// 摄像机视窗的size,也就是视窗的高度,是摄像机可以看到的高度的一半。
// 所以最大就限定其为场景高度的的一半。
let maxOrthoSize = _canvasHeight / 2
// orthoSize 不可为 0 ;orthoSize 小于 0 时,图像是倒过来的。
// 所以,1 <= orthoSize <= 场景高度的 / 2
val = Math.max(1, Math.min(val, maxOrthoSize))
return val
},
limitPos: function (pos) {
let val = pos
let orthoHeight = this.camera.orthoSize // 摄像机视窗的高度。
// 摄像机视窗的宽高比与场景的宽高比相同,所以通过场景的宽高比,计算出视窗的宽度。
let orthoWidth = orthoHeight * (_canvasWidth / _canvasHeight)
let halfCanvasWidth = _canvasWidth / 2
let halfCanvasHeight = _canvasHeight / 2
// 摄像机的锚点在正中心。
if (pos.x - orthoWidth < -1 * halfCanvasWidth) { // 超出左边界。
val.x = (-1 * halfCanvasWidth) + orthoWidth
} else if (pos.x + orthoWidth > halfCanvasWidth) { // 超出右边界。
val.x = halfCanvasWidth - orthoWidth
}
if (pos.y - orthoHeight < -1 * halfCanvasHeight) { // 超出下边界。
val.y = (-1 * halfCanvasHeight) + orthoHeight
} else if (pos.y + orthoHeight > halfCanvasHeight) { // 超出上边界。
val.y = halfCanvasHeight - orthoHeight
}
return val
},
});
运行起来,看看效果,
摄像机的视窗不会飞出屏幕,小姐姐也不会飞出小视图了。
用分组解决个bug
当摄像机移动到屏幕右上角时,会发现小视图中多出来的黄线,
当摄像机的视窗最小(camera.orthoSize = 1
)时,会发现小视图中一片蓝,
这些问题都是由于,摄像机照到了笔刷,在小视图中也将笔刷显示了出来。而笔刷绘制的图像在小姐姐之上,所以造成了上述问题。
解决这个问题很简单,我们需要分组,将笔刷单独放到一个组中,然后告诉摄像机,笔刷所在的组你假装没看到就好了。
在项目 -> 项目设置... -> 分组管理
中添加分组,保存,
这时就能在每个节点的Group
属性的下拉菜单中,看到新增加的brush
组。
我们将brush
节点的Group
设置为brush
,
然后将camera
节点的cullingMask
属性设置为只勾选default
,
cullingMask
决定摄像机用来渲染场景的哪些部分,我们未勾选brush
,那么所在brush
分组中的笔刷就不会被渲染出来。
运行起来,看看效果,
两个问题都消失了。
划重点
- 默认创建出来的摄像机,会自动将视窗大小调整为整个屏幕的大小。
alignWithScreen
rect
属性,决定摄像机绘制在屏幕上哪个位置,值为(0 ~ 1),x和y为左下角的点。- 摄像机的视窗大小
orthoSize
,视窗的大小 * 2,就是摄像机能看到的高度。 - 分组。
以上是关于Cocos Creator 2D摄像机 [Lv.1] 小视图的主要内容,如果未能解决你的问题,请参考以下文章
Cocos Creator 2D摄像机 [Lv.1] 小视图
Cocos Creator 2D摄像机 [Lv.1] 小视图
Cocos Creator 2D摄像机 [Lv.1] 小视图