目录:
Part1 摄像头固定的3D效果
Part2 尝试移动摄像头
Part3 边缘裁剪
在Scratch中实现的3D效果,我个人分成两类,
一个是以克隆体为主的3D,另一个是画笔类3D。
下面首先介绍画笔相关的教程,克隆体相关的会在之后补充。
Part1 摄像头固定的3D效果
首先,我们知道sc中有xy坐标。
现在让我们在sc中引入一个新坐标——z坐标。z轴垂直于电脑屏幕,从屏幕外指向屏幕里。(如下图)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/0292af8c-f3d8-4336-ab00-4f9e1926a523.png)
z坐标表示纵深,就是这个角色在屏幕内的深度。
z坐标越大,表示角色离屏幕所在平面越远,因为近大远小,z越大,物体看起来会越小;当z为0,物体刚好在屏幕面内;当z为负数表示角色跑到了屏幕外面,看不到。
为了方便你理解z坐标的含义,现在我们来看通过增减z坐标能够实现什么效果↓
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/69574bbc-a1fc-4423-abfa-405bda43e57e.gif)
可以看到,z坐标增加时,小猫远离屏幕,小猫变小;z坐标减小时,小猫靠近屏幕,小猫变大
下面第一个重头戏来了!!
接下来将向你展示实现3D的的代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/249510fe-c0ec-4c93-8207-dbf814e6c9b0.png)
当当当当!
是的!你没有看错!代码只有一行!!!
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/660bfb77-4f44-40bc-9702-513a2d122a3d.png)
使用这个代码可以让角色移动到对应的坐标
其中变量“#3D常数”设为350(也可以是其他的值,不同的值效果不同,比如在拂柳·奥波多普·伍柒零大佬的河边之战中,这个值被设为200,当这个值很小的时候可以实现广角镜头效果)
(接下来告诉你为什么是这么写,这一段不重要,听不懂也没关系,可以直接跳过)
————————————下面这一段可以跳过———————————————
(以下是我个人理解,非常不专业,请不要完全相信)
这个#3D常数(前面的#号是我的变量命名习惯,表示这个变量是常数)是什么?
在初中我们学过凸透镜成像原理,这个常数是像距——成像到凸透镜的距离。
以人眼为例,像距就是视网膜到晶状体的距离,这个距离是个定值,当然,如果像距是固定的,焦距就要随物距改变,所以晶状体会具有伸缩调焦的功能。
已知一个物体的长度和这个物体到凸透镜的距离,我们就能算出这个物体的成像的长度(屏幕上显示的长度)。
根据凸透镜成像原理和相似三角形,有如下关系:
实际长度:显示长度=物距(物体到凸透镜距离):像距(成像到凸透镜长度)
把这个式子变形一下,就是:
显示长度=实际长度*(像距/物距)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/18da7d77-07d0-4552-a1e0-80263efebb3b.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/c79e96cc-5d4f-413d-acb3-c0c9ce60dbe9.png)
因此在代码中,我们看到:
显示y=实际y*(像距/z)
显示x=实际x*(像距/z)
显示大小=实际大小*(像距/z)
(你发现多了一行调大小的代码?当然,如果只使用画笔,大小可以不用调整;如果要使用角色,角色大小也要调整)
同时,上面的式子也可以解释为什么“近大远小”:
显示大小与z成反比例关系,z越大,显示大小越小,即物体离屏幕越远,物体看起来就越小
————————————接下来继续————————————
那么这个代码具体可以怎么用呢?
首先,如果让你在sc中用画笔绘制一个正方形,边长为100,左下角坐标为(0,0),你应该知道怎么做吧?
就像这样:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/b3078cbb-cae8-4873-a8ad-131b4c73983e.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/572cd475-b076-48cb-b10a-d6e9af5ead70.png)
那么现在举一反三,我们来尝试用刚才的代码在三维空间中画一个正方形:边长为100,“放”在“地面”上(“地面”y坐标假设设为-150),正方形左下角坐标(-150,-150,300),你知道怎么画吗?
可以这样写:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/5979c48d-eb2d-4c0f-9b8e-daa02bc8fa32.png)
运行效果:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/ddca3f8b-ac81-479c-a6d2-814eb4aa2c22.png)
怎么样?是不是很像某个正方体的底面?
那么现在,我们以这个正方形为底面,绘制出一个完整的正方体…
首先我们来尝试画正方体的左侧面,类似于刚才底面的画法,你应该明白怎么画吧?
像这样:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/bc415e5f-8232-4261-aca3-c74c7f74d765.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/457b6bc3-30ad-4188-94ec-c61e1cccd26d.png)
其他面的代码同理。接着我们把其他面依次画完…
(Tips:可以直接画边,不用每个面都写一个绘制代码)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/506f71d4-965a-4900-8b9c-a65e8cfefa6a.png)
怎么样?是不是有内味了!好了,到这里,你已经掌握了实现3D的基本内容了
怎样,是不是意外的简单?
如果你听懂了,尝试自己画一个正方体。
————————————练习时间———————————————
(接下来是运用刚才的知识可以实现的几个案例练习,如果你听懂了,可以尝试自己做一下)
案例1:让正方体动起来!
预期效果:按wasd可上下左右移动正方体,↑↓键可前后移动正方体
具体过程:我们用三个变量:左下x,左下y,左下z来储存正方体左下角的坐标,然后编写程序,按对应的按键就增减正方体对应的坐标(例如按↑键增加z坐标,↓键减少z坐标)
实现结果↓
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/9af74882-69be-44a8-aef3-fcfff8d418fb.gif)
参考代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/aab4ee94-60a4-428f-bf1f-c7e2b698253f.png)
案例2:画个圆吧!
预期效果:画个铺在“地上”的圆(“地面”y:-150(当然你也可以自己设置)),半径100,圆心(-40,-150,500)
Tips:首先我们先尝试在sc自带的坐标系中尝试画圆(注意,需要用到三角函数!)
(即使在二维平面画出一个圆,代码其实也不简单↓,因此需要各位在阅读此教程之前需要比较扎实的基础)
(其实也可以不用三角函数,用勾股定理也可以)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/4ba5636c-f002-4301-920d-60e875fc6c4d.png)
我们对上面的代码稍作修改:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/ca57e9bf-a762-4a8e-839f-c6ee5bd4fd29.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/b9205b37-04a2-4e3e-bf89-3bea7901a8e4.png)
(平放在“地上”的圆看起来像个椭圆)
案例3:画个马路!(可以用来做公路跑酷游戏)
代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/e78aa3c7-5d94-4727-bef1-80eead53b57b.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/7d91b025-f46e-4103-9360-f9cb3deae5b0.png)
Part2 尝试移动摄像头
首先什么是摄像头?
摄像头是指当前视野的位置,移动摄像头就是移动视野。用xyz三个坐标储存摄像头的位置。在上面的教程中,其实相当于摄像头的x、y、z的值均为0的视野。
当摄像头向右移动,摄像头的x增加,视野往右移动,反之,往左移动时,摄像头的x减小;
同理,上下移动就是增加和减小摄像头的y坐标;前后移动就是增加和减少摄像头的z坐标。
实现摄像头移动效果的代码其实非常简单:
首先新建三个变量,命名为摄像头x,摄像头y,摄像头z
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/7d8df266-24fd-4e5e-b410-9666b1ae5cee.png)
然后对之前的代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/dd6a0743-cfd0-4f9c-8dce-1a8fbb12cf89.png)
中的“x”,”y”,”z”进行下面的替换
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/c2860901-9ae0-4f3a-bf0f-dad6e906ee98.png)
改为:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/615aad10-19ed-4b7d-9d3a-0a37a5d014f0.png)
然后,通过修改“摄像头x”“摄像头y”“摄像头z”就可以实现摄像头(即视野)的移动了。例如增减摄像头的x来向右和向左移动视野。
为什么这么做可以实现摄像头的移动呢?
如果你有制作“大地图”游戏的基础的话,上面的内容会很好理解。
例如,在MBZZW漫步者之王的“隔离区”作品中,实现的摄像头移动效果:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/04a442bc-12e9-487d-9f5c-ab69201d21ec.gif)
用的就是类似下面的代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/e27b3f25-128e-4e9a-8033-da75c464a966.png)
比如,一个角色在地图上的坐标是(100,100),摄像头的坐标是(60,60),这时,角色实际在屏幕上显示的坐标为(40,40),即用角色的实际地图坐标减去摄像头的坐标,得到角色相对于摄像头的位置。
因此,我们进行下面的替换,得到的就是角色相对摄像头的坐标,即角色显示的坐标。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/517edb0a-113a-44af-9b3c-b504591ab3ba.png)
现在,我们来写移动摄像头的代码吧!
(其中绘制正方体的代码是之前写过的代码)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/7c467b6d-0f04-4845-afa0-d831e7267ce3.png)
我们来看其中的这段新代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/f3a18e94-8f65-42ae-bb03-0cd8f37f55a9.png)
注意到摄像头的y初始为100,这是因为,游戏中的角色有一定的高度,这里的就是角色的视角到地面的高度。
绘制的立方体的y坐标为0,即把立方体放在地面上。
上面的代码很简单,就像移动一个角色一样,你应该很容易理解。
接下来我们来尝试加个跳跃效果:
如果你知道如何在2D的游戏中实现重力和跳跃效果,下面的代码将会非常好理解。
首先新建一个变量叫yv
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/27e92311-bf4f-48e4-a573-8f6007256947.png)
其中v是速度的意思。yv就是y方向的速度,就是纵向速度。
下面的代码实现了重力和跳跃效果。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/99fb3cc7-fe29-40d8-9d52-b286e41492f3.png)
yv是纵向速度,因此在每次循环中,摄像头的y都增加了yv,当yv为正值,角色将向上移动,当yv为负值,角色将向下移动。
因为受到重力的影响,yv每次循环都会减少一定的值。当角色跳起(按下空格),将角色的yv设为10,即设置一个向上的速度,此后角色以该速度上移,并且随着时间的增加,上移的速度减小(yv减小),最终yv减少到0,角色不再上移,达到最高点。之后,yv还在减少,减少到负数,这时,角色开始下落。
下面的代码是角色落地后的代码。因为角色的高度是100,当角色落到地面上时,角色的y是0,但是摄像头固定在“头”上,高度是100。所以当摄像头y<100时,才判断为落地。之后将摄像头y设为100,即移到地面。落到地面后,没有纵向速度,将yv设为0。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/54f35998-660c-4ca8-89ec-a0ad7f51470e.png)
于是,我们实现了移动,以及跳跃的效果。按WASD,摄像头就能前后左右移动;按下空格键,就可以跳跃。
Part3 边缘裁剪
(前排提醒:这一部分略难,我写的也比较凌乱,如果看不懂的话,可以跳过具体写代码的过程,只要知道最后的自定义模块怎么用就行了。)
不知道你在运行之前的代码,移动正方体时是否遇到这样的问题:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/442af7a8-a75b-45ce-bd9e-98b6905aa8d5.gif)
可以看到,当正方体移动到边缘时,发生了变形。
这是怎么回事呢?
我们知道,Scratch的舞台是有范围的,x坐标范围是-240~240,y坐标的范围是-180~180,当scratch角色移动到边缘时,会受到舞台限制。
例如运行这个代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/877bbb6e-f9bd-4425-98ab-2afe442ae10e.png)
得到的结果是:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/772a14ee-0b33-45d5-a177-73c315a8331c.png)
因为受到舞台限制,角色没有移动到(1000,1000)而是移到了(290,218)
(不同角色由于造型的大小不同,可能得到的结果不同。造型大的角色受到的约束会更小;当使用空造型,得到的结果则是240,180)
因此,当我们运行下面这段代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/44d50a32-125e-491c-8029-b12a345fa960.png)
我们希望得到的是下图中绿色的线(一条45°倾斜的线),可是实际运行的结果确实红色的线。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/beb9c45a-8615-4a73-8a4a-840bb11c65b1.png)
因此,我们需要对绘制的线段进行裁剪(裁剪的意思就是把跨越屏幕边缘的线段裁剪为只剩下屏幕内的线段):
具体步骤为:
当线段两端在屏幕内,直接画出;
当线段两端都在屏幕外,不用画出;
而当线段两端有一端在屏幕外,一段在屏幕内,就求出这个线段和屏幕边缘的交点,然后最后实际画出的线段就是从屏幕内的端点到交点的线段。(例如上面绘制的线段是(0,0)到(1000,1000),则实际画出的是(0,0),(180,180),即和屏幕上方边缘的交点)。
如果未经裁剪的绘制线段的写法是这样:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/37dbd279-b37d-4453-8641-507713f89453.png)
则经过裁剪的绘制线段的代码是这样:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/3723f314-7809-41d2-aac9-caff94987f20.png)
这段代码看不懂具体的过程没有关系,只要知道如何使用就行了。上面的代码用于绘制一条线段,并且当线段跨过屏幕边缘时,也能正确绘制。
(上面的代码取自国外一个大佬的3D教程中的代码。我自己也写了一个裁剪,但是写的太复杂了……上面的写法应该是算比较简单的写法了。
(建议直接使用上面的代码,不要自己写;当然如果你想挑战一下自己,也可以尝试自己写一个裁剪的代码)
运行下面的代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/deb6fda1-afea-4cd5-8efe-7823c78cf3cb.png)
可以看到绘制出来的线段是正确的。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/8bf5066b-02b3-4997-a377-5e84394cc53a.png)
现在,我们再把之前绘制立方体的代码进行修改:
首先写一条绘制3D线段的代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/37551772-ab8c-4d8f-9c74-2c42208520c0.png)
前面我们分析过了,当线段的端点跑到屏幕外时,上面代码的画法是有问题的。因此我们需要用到刚刚写的这个代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/431572c3-5291-4d7e-aaef-3d2f6cd5bfdf.png)
修改之后:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/dd92db0a-62d5-4fbe-b98d-adc25772f6fb.png)
补充说明:
(三维空间中一个点在Scratch舞台上绘制时的二维坐标,称为这个点的投影)
例如下面的两个黑圈中就是点(x,y,z)对应的投影的(x,y)坐标(在舞台上实际绘制的坐标)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/147a3db9-a39c-45d2-8a99-5486e931cf02.png)
同样,下面的起点x,起点y是点(x1,y1,z1)对应的投影坐标
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/e76c786f-9710-4a17-8bc9-788ed9e12aab.png)
然后把之前绘制立方体的代码换成依次绘制每条边的代码。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/2b6fcfb4-bd94-473f-8baa-9ac08f5380b0.png)
这样当立方体移动到边缘时,就不会变形了。
但是!
现在还有一个问题:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/357be759-8dc8-4335-bb6f-f49e300e0d26.gif)
当立方体靠近屏幕时,也会变形。这是因为,立方体的边和屏幕所在平面产生了交点,正方体有一部分跑到了屏幕外面。
前面我们进行的是x和y方向的裁剪。接下来,我们还需要进行z方向的裁剪。
具体步骤:
如果两端点都在屏幕内(两端点的z都大于摄像头z),则使用我们之前写的画线段的代码直接画出);
如果两端点都在屏幕后面(两端点的z都小于摄像头z),则不用画;
如果两端点一端在屏幕内,一端在屏幕外,则这条线段和屏幕产生了交点,实际画出的线段为从屏幕内的端点到交点的线段。
具体的代码:
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/b49212de-8669-43f1-ad89-d58117616b8c.png)
接下来要做到,就是求交点的坐标。
使用下面的代码求线段和平面z的交点
(其中线段的端点坐标填相对摄像头的坐标,平面的z为相对摄像头)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/b8dc31b5-fc8d-4a96-8b01-744d0756a710.png)
上面的代码大致的原理是相似三角形,不理解没关系,会用就行了。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/725c4041-9c13-4fae-bfdf-98d8e1c79a57.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/b51ad171-2500-4a57-8676-c93b14544e85.png)
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/d5d1e902-6b7f-4a81-bf9e-bf4f25ec0e57.png)
完成上面的代码后,现在当正方体和摄像头平面有交点时也不会变形。
现在,使用下面的这个代码绘制3D线段,无论何种情况,画出的线段都不会变形了。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/93ebf77e-d8be-464d-aa0d-70ab6ebb1ddc.png)
学完以上的内容,你已经掌握了画笔3D的理论知识的一半了!即除了旋转摄像头,你已经掌握了其他关于画笔3D的大部分内容!
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/2c1cb26b-23fb-4562-855d-38043cfe481f.png)
不过估计看到这里你还是一脸懵逼(我自己看我前面写的也觉得写的乱七八糟的)。如果你听不懂具体实现的过程,之后我会发布相关的代码,你只要知道如何使用这些代码就行了。后面也会有关于具体制作游戏的教程(大概)
总结:
Part1:核心代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/48d785c1-36dc-4d4a-b98c-05be15f2e30f.png)
Part2:核心代码
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/085e2c65-0f69-4af6-a9da-8f0df763843a.png)
Part3:核心代码
下面这段代码用于Scratch中绘制线段,并且当线段跨越舞台边缘时,对进行X和Y的裁剪,只绘制舞台内的线段,从而正确绘制。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/5b85a343-86d8-4a67-8c95-533723e81298.png)
下面这段代码用于绘制3D的线段。并且带有裁剪功能(当线段的一部分在摄像头后面时,进行Z的裁剪,只绘制摄像头前的线段,从而正确绘制)。
![](https://m.xiguacity.cn/post/6107c5323e593a0c25f850f8/96f13516-3f51-4968-b43f-6960494e63c4.png)
(这两个代码的具体代码可以在前面找到。之后教程中的相关代码也会发布,可以直接下载)
暂无评论内容