多维空间视错实现《笼中窥梦》,可渲染纹理和自定义着色器结合实现视觉方盒

《笼中窥梦》的盒子视觉空间如何在Creator3中实现?

B站视频:

本文是视频的文字版

前言概述

Hello大家好,我是Nowpaper,一爸学游戏,越来越有趣

去年一款惊奇的独立游戏,掀起了一轮视觉高潮,这款游戏就是《笼中窥梦》,它美术堪称一绝,使用视错设计,表现力非凡,不得不感叹,游戏还能还能这么玩?,《笼中窥梦》有很多值得,考究的技术细节点,那么今天,我们将使用CocosCreator3来实现一下,这个游戏的方盒视错功能,一窥其技术实现思路。

本项目使用的是 :CocosCreator 3.5.0

动画7

关于《笼中窥梦》的技术实现灵感,来自于正在制作的,另外一个技术视频,那是探讨如何在Creator3中,实现瞄准镜和额外屏幕技术

偶然发现其中的部分,只要结合之前的传送门技术实现的方法,就能够完成《笼中窥梦》的效果,先完成了这个方案,第一时间分享给大家,所以,还请大家多多支持一下

有关链接:

用RenderTexture实现炫酷的传送门

CocosStore:传送门实现

场景准备,实现分析

《笼中窥梦》中的盒子,各个面显示了完全不同场景,通过旋转摄像机找到合适的位置,组合达成过关条件,因此我们需要解决的是,盒子的各个面显示不同的画面,正常来说,我们将使用5个摄像机,渲染不同的画面到方盒的5个面上,这里使用Render To Texture,可以很容易的完成,为了达成五个面有五个不同的样子,就得需要使用一些素材搭建了几个不同场景,素材来自于官方商店资源《幽灵射手》和一些演示场景,需要注意的是,这里将场景按节点分割,方便管理

image

最基本的需要一个基础场景,用了一些素材作了一个室内场景,中间摆放一个盒子,并且建立对应各方向的面片,然而如果五个表面都制作,那么场景搭建将会异常的复杂,为了降低复杂度,先做出两个表面,对应的,也得做出来2个场景用来当谜题,这些场景搭建并不复杂,但是如果真的,要实现完整的关卡,这就得需要精细设计了,本文章主要是为了实现技术效果,就不作那么细致了,这些演示都将会打包放到商店当中,商店链接如下:


https://store.cocos.com/app/detail/3791

在项目设置中,新增6个Layer,来标记渲染分组,因为对应的摄像机,只需要渲染指定的渲染层即可,不用全部都渲染出来,现在为它们每个组的根节点,设置对应的Layer,以方便将来摄像机的设置,将基本场景的根节点设置成为Base,而其他的两个场景根节点,分别设置为Layer1和2,那么准备工作就完成了

image

摄像机的控制代码

现在我们需要先实现一个摄像机的渲染控制代码,让摄像机围绕着一个物体进行转,代码相对来说比较简单,通过监听TouchMove事件处理旋转,具体的请参看论坛中的一些大佬的分享


import { _decorator, Component, Node,  input, Input, EventTouch, Vec3, v3, Quat, math, quat } from 'cc';

const { ccclass, property } = _decorator;

@ccclass('CameraControl')

export class CameraControl extends Component {

    @property(Node)

    target: Node = null;

    public yMinLimit = -90;//相机向下最大角度

    public yMaxLimit = 0;//相机向上最大角度

    private targetX = 0;

    private targetY = 0;

    private xSpeed = 25;

    private ySpeed = 12;

    private disance: Vec3 = v3();

    start() {

        let angles = this.node.eulerAngles;

        this.targetX = angles.y;

        this.targetY = angles.x;

        input.on(Input.EventType.TOUCH_MOVE, this.onTouchMove, this);

        Vec3.subtract(this.disance, this.node.worldPosition, this.target.worldPosition);

        this.disance = v3(0,0,this.disance.length());

    }

    private onTouchMove(touch: EventTouch) {

        this.targetX -= touch.getDeltaX() * this.xSpeed * 0.02;

        this.targetY -= touch.getDeltaY() * this.ySpeed * 0.02;

        this.targetY = this.ClampAngle(this.targetY, this.yMinLimit, this.yMaxLimit);

       

    }

    private _quat = quat();

    private _vec3 = v3();

    update (deltaTime: number) {

        Quat.fromEuler(this._quat, this.targetY, this.targetX, 0);

        Vec3.transformQuat(this._vec3, this.disance, this._quat);

        Vec3.add(this._vec3, this.target.worldPosition, this._vec3);

        this.node.worldPosition = this._vec3.clone();

        this.node.worldRotation = this._quat.clone();

    }

    ClampAngle(angle, min, max) {

        if (angle < -360) angle += 360;

        if (angle > 360) angle -= 360;

        return math.clamp(angle, min, max);

    }

}

回到Creator中,为主摄像机添加脚本,并且指定目标,测试旋转效果

新建一个摄像机,命名为Camera 1,然后复制主摄像机节点参数,粘贴给新建的摄像机,调整到合适的位置,用来拍摄第一个场景,设置这个摄像机的可见性掩码,只勾选Layer 1这个Layer层

然后再实现一个摄像机同步的代码,用来处理面摄像机和主摄像机的同步,实现同步只需要在开始的时候,计算两个摄像机的偏移值,同步位置和旋转时候修正即可


import { _decorator, Component, Node, Vec3, v3 } from 'cc';

const { ccclass, property } = _decorator;

// 同步摄像机脚本,事实上如果监听主摄像机坐标、旋转差值会更加合理

@ccclass('SyncCamera')

export class SyncCamera extends Component {

    @property(Node)

    mainCamera: Node = null;

    offset: Vec3 = v3();

    _vec3 = v3();

    start() {

        Vec3.subtract(this.offset, this.node.position, this.mainCamera.position);

    }

    update(deltaTime: number) {

        Vec3.add(this._vec3,this.mainCamera.position,this.offset);

        this.node.position = this._vec3.clone();

        this.node.rotation = this.mainCamera.rotation;

    }

}

先实现一个面

现在我们先实现一个面看看效果,新建一个材质,选择着色器为内置builtin-unlit,勾选Use Texture,新建一个可渲染纹理,设置宽高为512x512,把刚刚新建的可渲染纹理,拖到上面完成引用,在场景中选择surface 1的面片,将它材质替换,就可以看到摄像机画面,渲染到表面1上,现在我们运行一下看看效果,由于有摄像机同步脚本,当主摄像机调整的时候辅摄像机也会跟着变动

用同样的方式建立第二个表面的渲染画面

但是我们发现有个不对劲的问题,这个画面看起来非常的平,根本就不像是透视过去的画面,这是因为表面,直接将拍摄到的渲染画面显示,这样肯定是没有透视的

image
image

这个时候就得需要一些特殊的处理,在我的之前有关传送门的视频中,也没有解决的很完美,后来在Cocos的Panda大佬的帮助下,通过修改着色器Shader,达成了完美的传送门效果,有兴趣的可以到CocosStore中浏览,本视频中也将使用到这个着色器文件,或者参考 youtube 大佬,Sebastian Lague的有关视频,他对于透视计算Shader和原理,讲解的非常详细,本文中的实现只是他的简化版本

核心代码如下:


float flip = cc_cameraPos.w == 0.0 ? -1.0 : 1.0;

v_screenPos = pos * 0.5;

v_screenPos.xy = vec2(v_screenPos.x, v_screenPos.y * flip) + v_screenPos.w;

v_screenPos.zw = pos.zw;

将修改过后的着色器,添加到工程,然后选择surface的材质,修改Effect点击保存,运行就可以看到效果,现在透视基本上OK了

image

不过好像还有一些小细节可以调整,比如画质发生了变化,显示的内容更近了,这个需要自行对摄像机进行调整,但是为了更好的设计关卡,两个摄像机的有关参数应该保持一致,否则可能会出现奇怪视觉错误

视错谜题

经过参数的调整,可以看出已经非常不错了,那么我们也设计一个简单的谜题到其中

这里有一幅画,在第一个场景中放到地上,作一下参数调整,然后再往第二个场景中添加一个,此时需要一些空间视觉感,来调整对应的位置和角度,这个可能需要,反复对比摄像机呈现的画面,和最终运行结果才能调出满意的效果,现在运行一下看看效果,在一般情况下,我们透过两个表面,看到的并不能完全重合,经过拖动旋转可以让其完全的实现重合

动画8

结语

好了,剩下的就是关卡设计的问题了,您可以利用本篇中的技巧,使用CocosCreator,完成一个自己的笼中窥梦游戏,本技术实现本质上是,将RenderToTexture给用活了,只要稍微调整一下,你也能做出叹为观止的创意

我一直认为,技术工具都是为创意服务,人类的创意总是没有尽头,如何实现心中所想,除了对它的热爱,工具的熟练度和技术的沉淀,才是创意发挥的基础

今天这个文章就到这里了,我是Nowpaper,一个混迹游戏行业的老爸,如果您喜欢我的文章,不妨点个赞,您的支持是我更新的动力,那么我们下次再见

本人喜欢研究各种有趣的玩法,以下是往期制作,可以移步研究

游戏中射击的最酷实现,Creator3如何作出《守望先锋》同级的枪弹射击体验

时间倒放的有趣实现,在Creator中作物理回溯,开发《时空幻境》一样的倒退玩法

摄像机视角的有趣玩法,实现《饥荒》同款视觉表现,一毛一样

Raycast射线实现3D世界交互,如何实现立体界面UI

用RenderTexture实现Sprite版小地图和炫酷的传送门

好玩的编队代码,魔性队伍排列惊喜不断完全停不下来

手撸三个有关Bundle详细教程,大厅+子游戏模式从入门到进阶

Cocos3D《病毒传播模拟器》游戏版本1 开发日志和总结

案例开发 四图猜词 Part1~4 全集教程

30赞

前排围观.

amazing :+1:

火钳刘明!!!

杨老师的每一个作品都是经过精心设计,不仅有趣、有料,还非常开脑洞 :+1:

强势抱大腿!

强强强 :+1:

学习了。。。

膜拜大佬~

mark!

这波我吹爆

牛逼! :grinning:

哇擦 真的好强

颠覆我眼界

Amazing :exploding_head:

mark一下