#cocos creator 3D
warning
- 报错:
"project:///assets/main.js
,将https中的export注视掉重试一遍
知识点
- scrollview组件添加item图片时,要在scrollview–view–属性检查器中设置:cc.MaskComponent–Inverted选中。
- 预览的时候要选中框去掉
- 动态替换图片:
cc.loader.load(itemInfo.picUrl, function (err, texture) {
if (err) {
cc.error(err.messager || err);
return;
}
const spriteFrame = new cc.SpriteFrame();
spriteFrame.texture = texture._texture;
that.jianImg.getComponent(cc.SpriteComponent).spriteFrame = spriteFrame
}.bind(this));
- scrollview组件的子item添加点击事件,要在item上添加button组件,否则检测不到点击。
- 分包加载---------------------注意必须要等分包加载完成后再打开新的scene。
- 1.将文件夹放在resourse文件中
- 2.配置文件夹为“子包”
- 3.在需要分包加载的前一个scene中,提前加载分包。代码:
cc.loader.downloader.loadSubpackage('resMapPackage', function (err) {
if (err) {
return console.error(err);
}
that.fen2 = 1;
console.log('load subpackage ----resMapPackage---- successfully.');
});
EditBox
编辑器输入框 3D篮球
import {_decorator, Component, Node, EditBoxComponent} from "cc";
@ccclass("editBox")
export class editBox extends Component {
@property({type: EditBoxComponent, tooltip: 'editBox'})
private editBox: EditBoxComponent = null;
start() {
this.tipText.getComponent(cc.LabelComponent).string = '';
if (window.Global.mobile) {
this.editBox.getComponent(cc.EditBoxComponent).string = window.Global.mobile;
}
}
// 用户开始输入数据时
editBoxBegan(e) {
console.log(e);
}
// 用户正在输入数据
editBoxTextChange(text, editbox, customEventData) {
console.log(1111111111);
console.log(text.string);
// this.editBox.getComponent(cc.LabelComponent).string = text;
this.phoneNum = text.string;
}
}
加音效
import {
AudioClip
} from "cc";
export class main extends Component {
musicChuqiao() {
const path = `res_map/music/chuqiao`;
loader.loadRes(path, AudioClip, (err: any, clip: AudioClip) => {
if (err) {
console.warn(err);
return;
}
clip.setLoop(false);
clip.playOneShot(1);
});
}
}
001 初识creator3D
- 光、摄像机
- 坐标系:
- X轴: 红色
- Y轴: 绿色
- Z轴: 蓝色
- 3D组件 预览
- 游戏发布简介
- 3D坐标系
- 右手坐标系、左手坐标系
- 物体:
- 前方: -z
- 右边: +x
- 上面: +y
- 创建3D物体
- plane: 平面:10*10
基础
export class GameMgr extends Component {
@property({ type: NodePos, tooltip: '箭' })
NodePos_arrow: NodePos = null;
}
快捷键
- 双击目录–定位到物体
- 右键旋转
- ALT+鼠标左键 旋转物体
- atrl+shift+f–》点击摄像机节点,调成编辑器摄像机视角
- Ctrl+D 复制
002 creator3D如何显示3D物体_Mesh_shader_材质
- 准备:
- (1)做3D建模(3DMax,Zbrush,Maya),模型原点,模型坐标系。
- (2)放入3D世界中(位置、缩放、旋转)
- (3)摄像机、正方向
- 形状改变、坐标变幻
GPU绘制物体标准流程:–> 渲染管道流水线 --> pass
- 绘制流程:
- 顶点初始化–顶点shader–Tellellation曲面化–集合shader–裁剪,投影–三角形遍历–片元着色shader–输出2D图像
- 【1】顶点初始化:CPU读取3D模型得顶点数据传到显存,给GPU使用
- 点—>线—>面(三角形)—>体.顶点(位置(模型的坐标系),纹理贴图(uv坐标), 法线的向量,…)
- 【2】顶点shader:shader我们给GPU写好的一段程序,将你写好的程序装载到GPU里面;
- stepl: 根据模型坐标—>世界变换矩阵(平移矩阵,旋转矩阵,缩放矩阵)–>CPU(游戏引擎根据节点)
- 每个顶点模型× 世界变换矩阵—>世界坐标; 北京+ 三里屯+1.5(模型坐标)
- step2: 我们的游戏引擎,根据摄像机的位置,旋转—>世界坐标系,变换到以摄像机为原点坐标系;
- 游戏引擎根据摄像机的节点位置,旋转—>世界坐标系,摄像机坐标系—>变换矩阵;
- 世界坐标变幻矩阵* 摄像机矩阵*模型坐标—>模型坐标—>观蔡者为中心坐标系下;
- step3: 你可以们顶点shader代码里面自己修改模型坐标, 改变模型形状(可选)
- cocos creator,unity,都会自己写好一些标准的常用的3D shader,我们就用可以了;除非你自己要定制一一些持殊的效果;
- 【3】曲面化,【4】集合shader:显卡的标准流程—>3D物体更平滑;
- 【5】裁剪, 投影
- 背对摄像机的三角形我们都会被裁掉(cull正面,背面, 不裁剪,默认摄像机背对的面裁减掉)
- 投影: 关键的一个动作: 3D–>2D
- 如何计算投影
- (1)椎体投影(透视投影)【3D用的比较多】
- x墙/x = y墙/y = z墙/z ===> x投影=xz墙/z,y投影 = yz墙/z
- (2)正交投影【2D用的比较多】
- 【6】三角形遍历:3D网格–》2D三角形
- 【7】片元着色shader:每个三角形进行着色:着色Shader–>代码自己写,引擎已经写好了
2.creator3D网络、材质,Shader;
- (1)Creator3D组件:例如cc.ModelConponent–>复制显示3D物体
- Mesh:初始化好我们要绘制的模型的网络–》ModelComponent相关–》mesh网络数据–》GPU顶点初始化
- (2)装载shader,3D绘制算法不一样,绘制效果不一样–》装载算法—》shader代码在哪里
- ModelCoponent–>Matrials–>材质(配置文件,effect(指定的shader),渲染管道的参数)
builitin-standard
- 渲染管道就配置好了,我们的这个shader–>
set pass call
(性能优化很重要的一个点)
- (3) ModelCoponent相关–》世界变换矩阵,设想变幻矩阵—》传递给顶点shader
- (4)着色:ModelCoponent相关 读取材质相关的参数,将这些着色相关的纹理,颜色传递给着色shader进行着色
3.导入一个3D 模型, 并显示出来;
- ModelCoponent功能类是的,另外一个绘制3D物体的模型组件(蒙皮网格)
- SkinnedModelComponent
- creator 3D 内置常用的shader:unlit
003 creator3.D.组件化开发
- 1.新建一个脚本类,被编辑器识别—。自动创建完成
- new 组件类的实例到节点上
- 所有的组件类–》new一个组件类组件类实例–》到节点上, 组件类的实例–》节点上
- 【1】编辑器添加组件实例到节点
- new 组件类的实例—》 点击“添加组件”
- 【2】代码添加组件实例到节点
- 3.游戏引擎如何调用代码
- 规定:游戏引擎运行–》游戏场景–》每个场景–》每个节点–》节点上每个组件实例,拿到后可以调用组件实例成员方法
- 第一次运行,遍历每个组件实例,调用组建历史的
onLoad
方法–》都调用一遍 - 下一帧时:调用
.onStart
只调用一次 -
onLoad
–》.onStart
两个初始化入口
- update的时间差是不固定的,根据运行时间来判断
- 4.this,this.node,数据成员如何绑定到编辑器的
- 普通数据类型: 定义成员: // 权限 名称:类型 = 默认值
- cocos类型: @property(类型)
- 数据组: @property(类型)
// cc.Component --> 组件类的基类
// cc.Node ---> 节点类
// cc.Vec3 ---> 三维向量类
import { _decorator, Component, Node, Vec3 } from "cc";
// 装饰器:ccclass,property
// 装饰器是给编辑装载脚本代码的时候来读取的
// 装饰器:ccclass 是指定一个类是一个组件类
// 装饰器:property指定一个成员变量为属性成员,编辑器读到这个装饰器,会把这个数据成员,作为属性绑定到编辑器
const { ccclass, property } = _decorator;
// component导入进来的组件类的基类
// export 导出这个类 import {game_mgr} from "./game_mgr"
// 装饰器@开头的;
@ccclass("game_mgr") // 编辑器识别我们这个脚本后,会把他当成组件类
export class game_mgr extends Component {
// 权限 名称:类型 = 默认值
//普通的基本数据类型:boolean,number
@property
private is_debug: boolean = false;
@property
private speed: number = 200;
// 复杂数据类型
@property(Node)
private test_node: Node = null;
@property([Node])
private test_array: Array<Node> = [];
start () {
console.log("start")
}
update (deltaTime: number) {
var s = deltaTime * 5;
this.node.translate(cc.v3(0,0,-s))
}
}
004 三维向量
- 三维向量常用方法
var v:Vec3 = cc.v3(3,4,5);
var v1 = new Vec3(0,0,0);
var v3 = new Vec3(v);
- 【2】常用单位向量
UNIT_X: (1, 0, 0), UNIT_Y(0, 1, 0), UNIT_Y(0, 0, 1);ZERO: (0, 0, 0), ONE: (1, 1, 1), NEG_ONE (-1, -1, -1);
- 【3】常用向量方法
- 向量长度 Vec3.len
-
var v5 = Vec3.len(v4);
==>v4.length()
- 向量加减法: add,sub。
- 静态方法: 放在新的向量里面
v4.add(Vec3.UNIT_Y);
结果是v4 - 成员方法:将结构修改到实例对象
Vec3.add(v3,Vec3.ONE,Vec3.NEG_ONE)
结果在v3中
- 两个向量的距离:Vec3.distance
var v9 = Vec3.distance(v1,v4);
- 两个向量线性插值:
lerp
范围是(0,1)
V = A + T * (B-A) T(0, 1);
// 线性插值 V = A + T * (B-A) T(0, 1);
// v3 = v1 + 0.3 * (v4 - v1)
Vec3.lerp(v3, v1, v4, 0.3);
console.log(v3);
// v1 = v1 + 0.3 * (v4 - v1);
v1.lerp(v4, 0.3);
console.log(v1);
+ 两个向量点乘dot,原理,
- A(x1,y1,z1),B(x2,y2,z2)
- A*B = (x1*x2+y1*y2+z1*z2)
- A*B = |A|+|B|+cos(夹角)
+ 夹角:两个向量之间较小的角度【0,180】
+ 求夹角:|A|*|B|*cos(夹角) = (x1*x2+y1*y2+z1*z2)--->cos(夹角) = ((x1*x2+y1*y2+z1*z2)/(|A|*|B|))
// 点乘 (x1*x2 + y1 * y2 + z1 * z2)
console.log(Vec3.dot(v1, v4)); // 静态方法;
console.log(v1.dot(v4)); // 成员方法
+ 叉积(cross):法相向量
- 返回一个向量
// 叉积----》(法线向量)
console.log(Vec3.cross(v3, v1, v4)); // v3 = v1 x v4;
// v1.cross(v4); // v1 = v1 x v4;
// console.log(v1);
v4.cross(v1); // v4 = v4 x v1; // 相反的;
console.log(v4);
+ 两个向量单位化:normalize
// (x, y, z) ---> 单位向量, 方向相同, 向量长度的为一;
Vec3.normalize(v3, v4); // v3 = v4的单位向量;
v4.normalize(); // v4 = v4的单位向量;
console.log(v3, v4, v4.length());
- 【4】标量分解到对应向量
- dir:(x,y,z),len是dir长度,标量大小v,按照dir分解以后得到的向量:
(v*dir.x/len,v*dir.y/len,v*dir.z/len)
005 Node的平移与缩放
- 1: 本地坐标系:
- position: 获取本地坐标位置 只读不能用于修改坐标位置(直接修改节点poistion, 不会创建内存);
- setPosition: 修改物体本地坐标位置;
- getPosition: 获取物体的本地坐标位置; (新的内存,不是node 的postion)
- 2: 世界坐标系:
- worldPosition: 获取世界坐标位置(readonly);
- setWorldPosition: 设置世界坐标的位置;
- getWorldPosition: 获取世界坐标位置; 创建一个新的内存对象;
- 3: 平移:translate(位置增量,Local/World) 往前走100米
- Node.NodeSpace.Local/ Node.NodeSpace.World
update(dt: number) {
var speed: number = 5;
this.node.translate(cc.v3(0, 0, -speed * dt), Node.NodeSpace.LOCAL);
// this.node.translate(cc.v3(0, 0, -speed * dt), Node.NodeSpace.WORLD); 记录一下;有问题
var pos: Vec3 = this.node.worldPosition;
pos.z -= (speed *dt)
this.node.worldPosition = pos;
}
- 3D物体的缩放控制:
- 缩放是一个三维向量,你分别再x,y,z缩放多少
- 1: 本地缩放:
- scale: 获取本地坐标位置 只读不能用于修改坐标位置;
- setScale: 修改物体本地缩放;
- getScale: 获取物体的本地缩放; // 创建一个新的内存
- 2: 世界缩放:
- worldScale: 获取世界缩放;
- setWorldScale: 设置世界坐标的缩放;
- getWorldScale: 获取世界坐标缩放; // (新的内存)
// 缩放, 只读, get新new Vec3内存,set;
this.node.setScale(2, 2, 2);
var scale: Vec3 = this.node.scale; // 同一个内存;
scale = this.node.getScale(); // 新建一个内存;
scale = this.node.worldScale;
006 Node的_欧拉角_四元数_旋转
欧拉旋转:
- (1)
直观的旋转,任何3D物体,可以把物体旋转某个角度,分别绕x,y,z分别旋转,然后得到一个朝向
- (2)先后顺序很重要:
- unity: z-x-y顺序旋转
- 欧拉: y-z-x
- (3)欧拉旋转–》3维向量(x,y,z)—》绕x旋转多少度、y、z
- (4)优缺点:
- 优点: 简单,直观,非常好控制,
- 缺点:不方便参与矩阵计算(模型坐标,(平移旋转*缩放矩阵)), 万向节锁;
四元数 -Quat–引擎里面使用 Quat来表示四元数;
- 缺点:不能直观的表示旋转, 程序一般不直接使用, 引擎内部用四元素计算旋转;
- 优点:方便参与矩阵计算,没有万向节锁
- 四元数和欧拉旋转互换:
Quat(x,y,z)
.静态方法、成员方法
- 四元数—》欧拉角; toEuler(Vec2,四元数,z的取值范围) 成员方法:getEulerAngles(out: Vec3): Vec3;
- 欧拉角—》四元数:fromEluer(四元数对象,x,y,z);给定一个欧拉角,返回一个可以表示旋转的四元数对象
- 成员方法/getEulerAngles
- 【4】3D物体旋转控制:
- 四元数控制旋转:
- rotation: 获取本地旋转,返回对象是四元数;
- worldRotation:世界旋转,返回对象是一个四元数
- getRotation(是否new四元数对象):如果你是先new传入,name数据就会放到你new的这个对象里面没如果你不new,混熟回帮你new一个
- getWorldRotation()获取世界旋转,返回一个四元数对象
- setRotation();设置节点本地(相对父节点)旋转,有两个版本,四元数对象版本(quat),四元数分量(x,y,z,w)
- setWorldRotation():设置节点世界旋转(叠加附近的旋转角度)、
- 欧拉角控制旋转
-
eulerAngles
: 欧拉角;表示本地旋转 -
setRotationFromEuler
: 使用欧拉角来设置物体的本地旋转(x,y,z),绕x轴旋转多少度,绕y轴,z轴多少度。 -
setWorldRotationFromEuler
使用世界旋转(x,y,z) Y-Z-X
- 旋转方法:
- rotate:
- lookAt:方向调整:(x,y,z forward(-z方向))—》forward方向(-z)指向某个点;—》前方,对准某个点控制我们角色的朝向
- lookAt();-z指向哪里(调整物体的旋转)lookAt(目标位置,头顶的方向(默认是0,1,0))设置当前节点旋转为面向目标位置,默认前方为 -z 方向
-
this.node.lookAt(cc.v3(0,10,0));
设置node朝向y轴10方向
- 获取世界坐标系前方: 对于本地坐标(-z是前方)世界坐标(0,0,-1)—>forward—>获取世界前方的方向
- 四元数插值:
- 球面插值。
slerp
。一般使用,平滑过渡我们的旋转[0,1]—》t—>中间的某个状态—》详细的讲解 - 线性插值。
lerp:A+t*(B-A)
;
007 摄像机的使用
[1].摄像机的模式与成像的原理
- 1.在底层openGL的设置里没摄像机的概念–》根据摄像机节点—》视角—》‘世界坐标’–》摄像机坐标—》变幻矩阵
- 2。成像原理:3D游戏—》2D画面—》屏幕上—》 将3D物体–2D影像
- 透视成像:一般3D游戏成像使用方法。远小近大;
- 已知一个3D坐标(x,y,z)—》z投影
- y投影/y = z投影/z —>y投影 = yz投影/z; x投影 = x z投影/z
- 正交成像
- 2D中使用,特殊的3D可能需要
[2]摄像机常用组件
- 摄像机节点+摄像枳的组件实例组成:—》位置,旋转,缩放—》世界坐标—》摄像机坐标系下的一个变换矩阵
- 摄像机定义了成像模式和相关的参数. 一> 投影;
-
cc.CameraComponent
: ClearFlags
: 清理屏幕
-
dont_clear
不清空.原来有什么就是什么; -
depth_only
只清空深度 -
solid_color
清空颜色、深度与模板缓冲; -
skyBox
启用天空盒,只清空深度
-
color
: 清理屏幕的颜色; -
priority
: 相机的渲染优先级,值越小越优先渲染 -
depth
:清空为指定的深度 -
FOV
: 相机的视角大小, -
near
: 相机的近裁剪距离,应在可接受范围内尽量取最大 -
far
: 相机的远裁剪距离,应在可接受范围内尽量取最小 -
OrthoHeight
正交模式下的视角 -
Projection
相机投影模式。分为 透视投影(PERSPECTIVE) 和 正交投影(ORTHO) -
Rect
: 此相机最终渲染到屏幕上的视口位置和大小 -
Stencil
清空为指定的模板缓冲 -
TargetTexture
: 指定此相机的渲染输出目标贴图,默认为空,直接渲染到屏幕 -
Visibility
:可见性掩码,声明在当前相机中可见的节点层级集合。
[3]:第三人称摄像机与第一人称摄像机;
- 第三人称摄像机:摄像机跟着角色走,但是拍摄的角度不变—》王者荣耀
- 主角移动,摄像机移动,但不会因为主角的脸的朝向,改变摄像机的事业方向
- 第一人称:摄像机随着主角的朝向变化而变化—》CS\守望先锋。。。
008 3D模型与动画播放
- .fbx的流行格式
- material的贴图,调整大小:
+ 打开.mtl文件,在属性检查器中–Use texture – tilingOffset
+ x\y\z调整大小 1 - 0 值越小,放大倍数越大
+ w是调位置,往上或往下位移
导入和显示3D模型
- 导入后的有【fbx模型】+【贴图】
- 贴图类型要做成texture;fbx[Body,只读材质,动画文件,骨骼文件]
- 关联贴图:
- 1.新建文件夹(材料)【
material
】 - 2.
Effect
->选择builtin-unlit
(高效的3Dshader) - 3.下边选择框中勾选
[USE texture]
- 4.下边
MainTexture
中添加贴图 - 5.选中模型-body-
Materials
添加刚刚做好的贴图material
- 替换材质,渲染组件
模型动画的切割
- 动画切割及添加
- 选中资源当中的模型文件(.fbx)文件–>右边属性检查器中–》动画即可分割
显示3D物体组件
- 绘制3D物体组件:【Meshrander】普通网格–》cc.ModelComponent
- Mesh: 3D物体网格
- Material:材质
- 绘制"蒙皮网格":—》cc.SkinningModelComponent
- Mesh:3D物体网格
- Material:材质
4.动画组件的基本原理与代码播放动画
- 播放动画基本原理—> 动画组件,读取动画文件里面内容,每一帧来修改网格的Mesh顶点的位置—》shader
- 动画组件是非常消耗性能.
- 播放动画组件:
cc.SkeIetaIAnimationComponent
-
clips
: 是当前这个组件带了哪些动画剪辑(attack , clip , run, idle)
—>AnimationClip
-
DefauItCIip
默认的动画剪辑 -
Play on Load
:是否在装载的时候就开始播放,勾选上一一》播放默认的anim clip;
- 代码里面如何播放动画.
- stepl: 获取动画播放组件实例–》cc.SkeletalAnimationComponent
- step2: 动画组件的播放接口,播放你指定的动画,
- step3: 播放动画的时候注意下, 动画切换—》idle–》atatck;—> 动画过渡;
-
play
: 立即切换,播放我们的动画,如果没有给动画的名字—》默认的动画, -
clips
: 获取我们动画组件上面的,所有的动画剪辑—> cc.AnimationClip数组; -
defaultClip
: 默认的动画剪辑, -
crossFade
: 切换动画加上了平滑过渡一》自然; -
stop
:停止播放动画 -
pause
:暂停播放;
- 可以和2D一样写
import {
_decorator,
Component,
Node,
AnimationComponent, // 自己写的动画组件
SkeletalAnimationComponent // 美术给的3D物体自带的动画组件
} from "cc";
@property({type: Node, tooltip: '玩家'}) // 需要加动画的节点(自己写的动画)
public playerMove: Node = null;
private anim: SkeletalAnimationComponent = null; // 3D物体自带的组件
rePlayerAnimation(){ // 自己的方法
console.log('动画');
var animationComponent = this.playerMove.getComponent(AnimationComponent);
animationComponent.play('002_player_move'); // 播放动画状态 'idle'
var playerAni = this.playerMove.getChildByName('player').getComponent(SkeletalAnimationComponent);
playerAni.play('Take 001'); // 播放动画状态 'idle'
// 学习 教程方法:
this.anim = this.node.getComponent(AnimationComponent);
this.anim.play('001_flyjian');
var that = this;
// 当需要切换到跑的动画时
this.scheduleOnce(function(){
that.anim.crossFade('Die') // 在 0.3 秒内平滑地从走的动画切换为跑的动画
},5)
009 常用的Shader与天空盒
-
flip UV
翻转 - builitin-standard 标准
USE_ALBEDO_MAP
是否使用漫反射贴图?
- 勾选上,再放入贴图
-
USE_NORMAL_MAP
是否使用法线贴图?没增加三角形情况下增加更多细节
【1】Unlit Shader以及重要得参数;
- (1)
builitin-unlit
最高效的3D shader, 效果最少把一个3D模型最基本的显示出来—>unlinght不受光照影响;
- 只是把物体本来的样子显示出来; 贴图—>3D模型上,—>高效—》我们做微信小游戏Unlit;
- (2) 3D物体渲染队列:
- opaque(不透明物体渲染队列), transparent(透明物体渲染队列,透明的物体消耗会大一些)
- (3)Pass只有一个pass; (完整渲染流程)—> pass: 是否使用顶点颜色,
- a:是否使用顶点颜色,
- b: 是否使用纹理贴图: MainTexture: 指定贴图的资源;tilling offset
- c: 是否给她加环境颜色
- (4)纹理坐标,贴图的基本原理
【2】Stand Shader以及重要参数
- (1)是否使用顶点颜色:
USE VERTEX COLOR
- (2)是否使用法线贴图:3D的绘制技术,在不增加三角形面的情况下,能加入更多的细节;
- (3)3D物体的本来的贴图:
USE ALBEDO MAP
【3】天空盒
- (1)在真实的环境中, 我们的四面八方都是被天空包住的,用一个"盒子"来做天空;
- 摄像机绘制的时候, 纯色—>使用天空盒字
- (2)天空盒子是一个立方体, 前后上下6个面
- (3)使用天空盒
- [1].要配置摄像机的清理模式是天空盒,先绘制天空skyBox
- camera–>cc.CameraComponent组件–》ClearFlags–skyBox
- [2].设置天空盒资源
- 点击场景Scene—skyBox–勾选Enable
- [3]创建
cubemap
- 在资源管理器中–右键创建
cubemap
—导入资源
- [4]在scene中添加刚创建的
cubemap
010 Unity场景转creator3D场景搭建示例
011 打造3D路径编辑系统
导入SWS 路径编辑插件
录点:
- 【1】在unity 开发工具中—窗口(window)—simple Waypoint System—WayPointManager—会创建一个
Waypoint Manager
节点 - 【2】选中
Waypoint Manager
节点—》右边创建名称Enter Path Name
—》一般选标准—》Start Path - 【3】鼠标移动到目标位置,按p键(就会记录下一个路径点)—》接着点下一个路径点—》直到完成路径—》finishing Path
- 选路径点时千万不要点鼠标左键
导出路径数据
- 需要导入一个插件:
bycw_roaddata_export.unitypackage
- 使用
- 选中刚刚的waypointmanager节点
- bycw–> 打开一个窗口—》多语言版本的类型
- 在生成的路径那儿填入路径:
/../
就会生成一个Waypoint Manager.ts
文件
- 注意导出的路径文件需用单个单词命名,否则会报错
Waypoint Manager.ts
–》WaypointManager.ts
cocos/Unity路径点数据的坐标差异
- unity是左手坐标系
- 赛车x,y,z前方+z
- cocos 右手坐标系;x,y,z前方是-z.基于cocos开发游戏,前方主角朝向一定要是-z。
- 总结:路径:cocos,使用unity的路径数据,-x.根据场景来定
012 打造路径导航组件
示例:F:\cocos3D\009_test\assets\scenes\012routePoint
【1】获取路径数据
-
重点
: cocos中主角朝向一定要在-z方向。可以外包父节点模型转到-z方向。 - 导出的路径数据:
- 类的静态成员:
roads:[路径1,路径2,路径3,...路径数据[p1,p2,p3{x,y,z}...pend]]
【2】设置初始值
- speed:速度50
- 让赛车在路径上行走—>walk_on_road()
- 将赛车放在路径起点位置,录制路径点时下沉了-0.08,要在cocos中纠正。
【3】实现一个一个路径点行走
- unity路径点坐标和cocos路径点坐标不一样。
- unity.x == -cocos.x
this.vx = this.speed * dir.x / len;
this.vy = this.speed * dir.y / len;
this.vz = this.speed * dir.z / len;
- 上一次update没有到,下一次update超过
- 如何判断从src走到dst:
- 距离: 是很难判断的,两个点是否重合很难判断,每次更新"一段"距离—》不采用距离;
- 时间: 时司都没有了,那么这个时候说明我们走到了,
- 每次update, 根据速度,我更新一点点距离,假设没有行走,那么这个时候,update不要更新.
-
walk_to_next
–》lookAt—>朝向前方
【4】实现方向调整和摄像机的平滑过渡
路径点有噪点,路径点本身不是平滑,导致摄像机在一个很短是时间内来回晃动
- 不是一次性lookAt过来的—>当前的旋转—》目标需安装—》update,不断的插值
【5】高速物体的控制与移动
013 3D物理引擎、刚体、碰撞器、的使用
F:\cocos3D\009_test_physics\assets\scenes
#####【1】编辑物理场景,刚体,碰撞器,物理材质
- 物理:
- 动态物体:刚体(运动)+ 形状(碰撞器)
- 静态物体:形状。不能通过代码来修改物体位置
- 静态碰撞器:
-
BoxCollider矩形
:右键–》component
–》BoxCollider
-
SphereColliderComponent球形
:右键–》component
–》SphereCollider
- 动态物体:
刚体
-【计算物理运动,力,速度】
RigidBodyComponent刚体
:右键–》component
–》RigidBody
-
Mass
刚体质量 -
LinearDamping
线性运动的阻尼 -
AngularDamping
角速度阻尼 -
IsKinematic
不会受物体运动,但可以改变物体的位置 -
UseGravity
是否使用重力 -
FixedRotation
刚体是否固定旋转 -
LinearFactor
线性速度因子 -
AngularFacto
旋转速度因子
碰撞器BoxColliderComponent
Material
物理材质—》弹力、摩擦系数
- 右键新建
physic-material
-
Restitution
弹力 -
Friction
摩擦系数
-
IsTrigger
是否为触发器。只穿过物体,不改变物体运动。 -
Center
中心 -
Size
大小
【2】刚体组件实例的相关操作:刚体加力、速度
- 给这个物理节点添加代码。获取刚体组件实例
-
applyForce
加力
import { _decorator, Component, Node, RigidBodyComponent } from "cc";
const { ccclass, property } = _decorator;
@ccclass("physics")
export class physics extends Component {
start () {
this.body = this.node.getComponent(RigidBodyComponent);
// this.body.applyForce(cc.v3(2000,3,500));//加力
// this.body.setLinearVelocity(cc.v3(5,-3,4));//线性速度
this.body.setAngularVelocity(cc.v3(0,45,0));// 旋转速度
}
}
【3】二进制位运算
- 按位与
- 按位或
- 左移:1<<1;0000 0001 <<1 = 0000 0010 左移了一位,右边0补齐。没左移一位*2
- 右移:0000 0010>> 0000 0001 把右边的去掉,高位,用数字最高位补齐 除以2
- 非常棒的技巧:可以用一个整数来表示集合(类型的集合)
8bit的整数位: 0000 00000000 0001 0000 0010 0000 0100 0000 1000
1<<0 1<<1 1<<2 1<<3 1<<4 1<<5 1<<6 1<<7
- 做成几个类的类型集合:
[1,2,3] 0000 0001 | 0000 0010 | 0000 0100 = 0000 0111
判断,某种类型,是否在这个集合里面 value&(1<<类型)
【4】碰撞器与碰撞检测
BoxColliderComponent
,ICollisionEvent
,ITriggerEvent
当物理引擎检测到碰撞的时候,可以收到碰撞事件
- 【1】形状的碰撞,碰撞检测,是基于碰撞器,不是基于刚体
- 【2】碰撞发生后,会抛出事件,需要监听这些事情。
- 碰撞开始
onCollisionEnter
- 碰撞持续
onCollisionStay
- 碰撞离开
onCollisionExit
- 【3】要监听碰撞器抛出的这些事件
- 【4】获取碰撞信息
ICollisionEvent
-
type
:碰撞事件的类型 -
selfCollider
:碰撞中的自己的碰撞器。 -
otherCollider
:碰撞中的另一个碰撞器。 -
contacts
:碰撞中的所有碰撞点的信息。
- 特殊碰撞:只触发碰撞检测,不去改变物体的运动;—》(触发器,trigger,sensor)
- (1)做好一个trigger
- 【5】trigger或碰撞事件,三种状态,只使用其中一种就行
- 【6】碰撞配置,我们经常做游戏会遇到:敌人的子弹不会打到敌人。自己的子弹不会打自己
- 物体碰撞分group
- 要分好敌人、自己、敌人子弹、自己的子弹,类型:默认default,类型: 1<<0,1<<1,1<<2…32种类型
- 物体发生碰撞时,会有一个可碰撞的物理集合,32bit整数mask来表示,((1<<0)(1<<1)(1<<2)),0xffffffff—>-1
- 默认物体碰撞集合-1. 111111111111111111111111111111–>1;
- 发生碰撞: A(groupA,maskA),B(groupB,maskB)v:
- 发生碰撞条件:A的碰撞集合里有B(maskA & groupB 为真),B的碰撞集合里有A(maskB & groupA 为真),
setGroup/getCroup``setMask/getMask
- 碰撞分组监测:
Group, Mask:
- A, B两个物体是否发生碰撞,
(GroupA & MaskB) && (GroupB & MaskA)
setGroup/getCroup
setMask/getMask
PhysicsSystem:物理引擎全局设置
console.log(PhysicsSystem.instance)
- 【1】物理引擎代码模块–》项目设置–》Physics,用到物理引擎,需要勾选上
- cannon.js 标准物理引擎
- buildin.js 没有物理计算,只有碰撞检测。代码体积会小
- 【2】物理引擎全局对象,可以对物理引擎参数设置
- 1:
重力
:物理世界的重力值,默认为 (0, -10, 0) - 2:
enable
:是否开启物理系统,默认为 true - 3:
allowSleep
:是否允许物理系统自动休眠,默认为 true - 4:
maxSubStep
:物理每帧模拟的最大子步数,默认为 2 - 5:
deltaTime
:物理每步模拟消耗的时间,注意不是每帧,默认为 1 / 60 - 6:
gravity
: 物理世界的重力值,默认为 (0, -10, 0)
import {
_decorator,
Component,
Node,
RigidBodyComponent,
BoxColliderComponent,
ICollisionEvent,
ITriggerEvent,
PhysicsSystem,
} from "cc";
const {ccclass, property} = _decorator;
@ccclass("physics")
export class physics extends Component {
private body: RigidBodyComponent = null;
// private body: BoxColliderComponent = null;
onLoad() {
// this.body = this.node.getComponent(RigidBodyComponent);
// this.body.applyForce(cc.v3(2000,3,500));
}
start() {
this.body = this.node.getComponent(RigidBodyComponent);
// this.body.applyForce(cc.v3(2000,3,500));//加力
// this.body.setLinearVelocity(cc.v3(5,-3,4));//线性速度
// this.body.setAngularVelocity(cc.v3(0,45,0));// 旋转速度
// 碰撞
var collider = this.node.getComponent(BoxColliderComponent);
collider.on("onCollisionEnter", this.onCollisionEnter, this);
collider.on("onCollisionStay", this.onCollisionStay, this);
collider.on("onCollisionExit", this.onCollisionExit, this);
collider.on("onTriggerEnter", this.onTriggerEvent, this);
collider.on("onTriggerStay", this.onTriggerEvent, this);
collider.on("onTriggerExit", this.onTriggerEvent, this);
console.log(collider.getGroup(), collider.getMask())// 1 -1
collider.setMask((1 << 1) | (1 << 2)); // 设置碰撞关系
console.log(collider.getGroup(), collider.getMask())// 1 -1
// 0000 0010 0000 0100 --> 0000 0110
// cube:[1,mask(0000 0110)],
// group(0000 0001,mask -1)
console.log(PhysicsSystem.instance)
}
private onCollisionEnter(e: ICollisionEvent): void {
console.log('onCollisionEnter');
console.log(e)
}
private onCollisionStay(e: ICollisionEvent): void {
// console.log('onCollisionStay')
}
private onCollisionExit(e: ICollisionEvent): void {
console.log('onCollisionExit')
}
private onTriggerEvent(e: ITriggerEvent): void {
console.log('onTriggerEnter')
console.log(e);
console.log(e.type);
}
update(dt: number) {
}
}
014 常用3D_UI开发
- 可以2D/3D切换
- canvas
- [2]UI是独立于3D游戏场景的–》创建一个UI类型–》2D
- [3]UI Canvas --> UI画布—》Canvas—>设计分辨率:
- UITransformComponent:画布大小、锚点
- CanvasComponent:
- [4]widget
- 导入资源要改格式。选中src中的图片资源—》属性检查器–》
type:sprite-frame
- 图片九宫格拉伸–》将图片拖入节点中–》选择sliced—》到资源管理器中选中图片—》编辑–九宫格设置
015 事件响应_射线检测_3D拾取
-
DEVICEMOTION
重力感应
【1】系统全局事件监听
- 1.获取鼠标, 获取键盘,
- stepl: 全局事件对象的单例;
cc.systemEvent
- step2: 监听我们的事件类型通过API接口查看;
- step3: destory销毁事件
- step4: 全局系统事件支持的类型
- step5: 如何使事件对象
-
EventKeyboard
: —>keyCode
, 按键码 -
Touch, EventTouch
: 支持多点 - 位置是一个屏幕坐标
getLocation
;
import { _decorator, Component, Node, systemEvent, SystemEvent, Vec2, SystemEventType,EventTouch,Touch ,EventKeyboard} from "cc";
const { ccclass, property } = _decorator;
@ccclass("gameMgr")
export class gameMgr extends Component {
start () {
//鼠标事件
systemEvent.on(SystemEventType.TOUCH_START,this.onTouchStart,this);
//重力感应
// systemEvent.on(SystemEventType.DEVICEMOTION,this.DEVICEMOTION,this);
// 键盘事件
systemEvent.on(SystemEventType.KEY_DOWN,this.keyDown,this)
}
onTouchStart(touch: Touch,event: EventTouch){
console.log(touch);
console.log(event); // 包含touch
var pos:Vec2 = event.touch.getLocation();
console.log(pos);
}
keyDown(e:EventKeyboard){
switch (e.keyCode) {
case 32: console.log(123);// 空格
break;
}
console.log(e)
}
destory(){
super.destroy();// 调用component destory
console.log('注销事件');
systemEvent.off(SystemEventType.TOUCH_START,this.onTouchStart,this);
systemEvent.off(SystemEventType.KEY_DOWN,this.keyDown,this);
}
}
【2】UI节点时间监听–>和2D一样
- UI事件会挡住系统事件
【3】屏幕坐标与世界坐标的转换
- 摄像机坐标转换
- worldToScreen:世界坐标系—》屏幕坐标
var w_pos: Vec3 = this.camera.screenToWorld(cc.v3(pos.x, pos.y, 0))
- screenToWorld:屏幕坐标—》世界坐标系
【4】射线对象
- 2D坐标–》判断是3D物体
- 射线检测—》从某个点–》射线—》射线,这条射线碰撞到哪些物体
- 3D拾取:屏幕点击—》世界坐标,摄像机的世界坐标原点,(点击点-摄像机点),发射一条射线
- Camera组件:screenPointToRay—>
- 自己创建射线对象:枪的坐标—》枪.forward—>构建一个自己的射线对象
- 射线对象:原点(Vec3),方向(Vec3)
【5】射线检测与3D拾取
被点击的物体一定要加物理碰撞器(trigger)
- step1: 获取射线对象
- step2: 射线碰撞到了哪些物体(物理模块,射线检测基于物理碰撞器),有没点击到cube
- step3:使用物理引擎的接口来做射线检测
raycast
检测所有的碰撞盒,并记录所有被检测到的结果,通过 PhysicsSystem.instance.raycastResults 访问结果
-
worldRay
世界空间下的一条射线 -
mask
掩码,默认为 0xffffffff -
maxDistance
最大检测距离,默认为 10000000,目前请勿传入 Infinity 或 Number.MAX_VALUE -
queryTrigger
是否检测触发器 -
boolean
表示是否有检测到碰撞盒
-
raycastClosest
检测所有的碰撞盒,并记录与射线距离最短的检测结果,通过 PhysicsSystem.instance.raycastClosestResult 访问结果
geometry
几何体信息
1: systemEvent 全局事件单例;
2: 监听触摸: TOUCH_START/TOUCH_MOVE/TOUCH_END/TOUCH_CANCEL
鼠标事件: MOUSE_DOWN/MOUSE_MOVE/MOUSE_UP/
键盘: KEY_DOWN/KEY_UP
重力感应: DEVICEMOTION
3: UI 节点来监听事件。
1: 摄象机,触摸坐标转射线;
2: 射线检测与3D拾取;
016 Creator3D案例FPS控制《拇指射箭》
- 1.环境搭建
- 2.项目创建,导入素材,搭建第一人称场景
- 3.代码开发基本流程
- 4.拇指触摸控制
- 5.第一人称射箭瞄准
- 6.打包发布
017课 3D A* 寻路系统
- 1.3D地图
- 2.根据场景生成地图数据–哪些地方可以走,哪些不行。把地图分成对应区域块32*32,每一米为1块。[32X32] = [true,false]
- 地图烘焙工具
- 3.编写算法,起点–终点,寻出可达路径
- 4.导航组件–>从当前点,以固定速度移动到目标点。
寻路算法–》A*/A星/Astar
022 3D游戏摇杆与角色控制
公共组件已保存
100 UI组件之使用
101 progressBar 进度条
export class main extends Component {
// 进度条节点
@property({type: Node, tooltip: '进度条'})
public cProgressBar: Node = null;
test(){
var chaNodeComponent = this.cProgressBar.getComponent(cc.ProgressBarComponent);
chaNodeComponent.progress = juliNum/1000; //设置progressbar
console.log(chaNodeComponent);
}
}
102slider 滑动条
直接在组件中挂载 回调函数,在回调函数中动态设置值
SliderComponent
export class main extends Component {
@property({type: Node, tooltip: '控制飞剑起始飞行角度'})
public vSlider: Node = null;
sliderCallback(Slider,CustomEventData){
console.log(Slider._progress) // slider滑动条值
}
}
110粒子系统
ParticleSystemComponent
Cocos Creator之打包设置横竖屏
构建发布--设备方向
- Portrait —> 这个是竖屏展示;
- Upside Down --> 这个是手机竖屏,但是你的手机需要倒过来;
- Landscape Left --> 这个是横屏,屏幕在home键左边;(常用的)
- Landscape Right --> 这个也是横屏,屏幕在home右边。
技巧
- 【1】导入的资源–》prefab—>导入场景中后—》属性检查器中–》右上角还原为普通节点
- 【2】调整好的视角—》在编辑器中调好视角–》点击camera–》
ctrl + shift + F
- 【3】导入另一个js文件.在编辑器中拖入摇杆组件(携带js文件的组件)
import { UIJoyStick } from "./UIJoyStick";
@property(UIJoyStick)
private stick: UIJoyStick = null; // 引入js文件
- 【4】物体受重力落下,掉在平面上的组件配置:
- 物体需添加2个组件:
- 刚体:cc.RigidBodyComponent—》UseGravity重力
- 碰撞器:cc.BoxColliderComponent—》Friction:0.1 Restitution 0弹力
- 平面:cc.BoxColliderComponent—》不要添加材质
- 【5】角色在平面上移动,组件配置:
- 物体需添加2个组件:
- 刚体:cc.RigidBodyComponent—》UseGravity重力不勾选,
- 碰撞器:cc.BoxColliderComponent—》不要添加材质
- 平面:cc.BoxColliderComponent—》不要添加材质
- 【6】设置墙面,不要让物体穿过
- 只设置:碰撞器:cc.BoxColliderComponent—》不要添加材质
组件
- shader着色器
- billboard 广告牌
- blockInputEvents
- boxCollier
- CapsuleColliderComponent 胶囊碰撞组件
- skinnedModelComponent 蒙皮网格
- builitin-standard 标准
- builitin-unlity 用不用光照都行
import {
_decorator,
Component,
Node,
RigidBodyComponent, // 刚体 物理组件
BoxColliderComponent,// 碰撞组件
ICollisionEvent,
ITriggerEvent,
PhysicsSystem, // 物理系统
systemEvent, // 系统
SystemEvent,
Vec2, // 二维向量
Vec3, // 三维向量
CanvasComponent, // canvas组件用到
renderer //
} from "cc";
_decorator,
Component,
Node,
封装组件
- 3D摇杆:
F:\cocos3D\000_component\摇杆公共组件
Builtins 材质
无光照的 unlit、基于物理光照的 standard、skybox、粒子、sprite 等
- USE_BATCHING 是否启用动态合批?
- USE_SKINNING 是否启用顶点蒙皮? 对蒙皮模型必须启用。执行动画添加的材质要勾选上,否则不执行动画
- USE_VERTEX_COLOR 如果启用,顶点色会与漫反射项相乘
- USE_ALPHA_TEST 是否开启透明测试(镂空效果)?
方法命名
- 程序外部使用:
public walk_on_road():void {}
- 程序内部使用:
private walk_to_next():void {}
- 记得消除事件
destory(){
super.destroy();// 调用component destory
console.log('注销事件');
systemEvent.off(SystemEventType.TOUCH_START,this.onTouchStart,this);
}
-
UIJoyStick
摇杆、操纵杆
- 动画非常消耗性能
-
ShadowCastingMode
需要显示阴影的模型组件设置为 ON
warning 报错
- 如果有的看不见了,检查摄像机Visibility是否显示
- 报错:cannot find module ‘cc’
- 解决:将temp-declarations-cc.d.ts改为:
/// <reference path="D:\cocos3D\CocosCreator3D\resources\resources\3d\engine\bin\.declarations\cc.d.ts"/>
- 注意向量的异步执行: // var v6 = v4.add(Vec3.UNIT_Y);
- var v8 = v4.subtract(Vec3.UNIT_Y); // 注意向量的异步执行 - 只能有一个plane,否则角色找不到plane
- 如果物体下坠,但没有在平面上停下来,可能是物体外包着空node,没有设置size。
重点 重中之重
- 1.
3D游戏导入的资源,要把图片格式改为sprite-frame格式。否则不显示
TexturePackerUi 使用
- 1.将要打包的图集拖入工具内
- 2.在Texture中选择路径并输入文件名,上面也会出现相同的路径和名称
- 3.Publish即可
笔记 物体角度控制
- 最正确的控制旋转 实时控制具体角度、具体方向
var e_rot = this.xuanzhaunti.eulerAngles.clone(); // 角度
e_rot.x = sjiaodu; // 实际角度值 45度 30度
console.log(e_rot); // {x: -64.91512082108935, y: -60.59560000343657, z: 0} 里面为具体方向的角度
this.xuanzhaunti.eulerAngles = e_rot;
- 在多长时间内旋转多少的方法
// 欧拉角旋转方式 往前旋转的基数 飞剑往前飞的方向 朝向
/*var r: Quat = new Quat();
Quat.fromEuler(r, this.zSpeed * dt, 0, 0); // (0, w_speed * dt, 0)----> r;
this.xuanzhaunti.rotate(r);*/
- tweenUtil、tween
tweenUtil(this.NodePos_arrow)
.stop()
.to(5, { z: targetZ, x: targetX, y: targetY })
.to(1, {})
.call(() => {
this.gameOver();
})
.start()
- vmath 是已经废弃的 API,尽量使用 math:
import { Quat, math } from 'cc';
const q_tmp = new Quat();
const out_Q = math.Quat.rotateAround(q_tmp, this.node._quat, cc.v3(), Math.PI * 0.1);
this.node.setRotation(out_Q.x, out_Q.y, out_Q.z, out_Q.w);
- cc.v3(-1, 1, 0)时旋转变形,加上
cc.v3(-1, 1, 0).normalizeSelf()
就不变形了
var out_Q = cc.vmath.quat.rotateAround(q_tmp, this.node._quat, cc.v3(-1, 1, 0), Math.PI * 0.1);
this.node.setRotation(out_Q.x, out_Q.y, out_Q.z, out_Q.w);
let q_tmp = new Quat();
let v_tmp = new Vec3(0, 0, 1);
v_tmp.normalize();
let out_Q = Quat.rotateAround(q_tmp, this.zhizhen.rotation, cc.v3(0,0,1), Math.PI * 0.1);
this.zhizhen.setRotation(out_Q.x, out_Q.y, out_Q.z, out_Q.w);
- 四元素旋转:
var out_Q = math.Quat.rotateAround(q_tmp, this.xuanzhaunti.rotation, cc.v3(1, 0, 0), Math.PI * 0.1); //Math.PI * 0.1 * 180 / Math.PI = 18度
中cc.v3(1, 0, 0)
是绕X轴旋转,cc.v3(0, 1, 0)
是绕Y轴旋转,cc.v3(0, 0, 1)
是绕Z轴旋转,
旋转
onLoad(){
this.lab.on(Node.EventType.TOUCH_MOVE, this.callback, this);
}
callback(EventTouch){
let dif = EventTouch.getDelta();
let q_tmp = new Quat();
let v_tmp = new Vec3(-dif.y, dif.x, 0);
v_tmp.normalize();
let out_Q = Quat.rotateAround(q_tmp, this.testNode.rotation, v_tmp, Math.PI * 0.01);
this.testNode.setRotation(out_Q.x, out_Q.y, out_Q.z, out_Q.w);
}
四元数 欧拉角
/**
* @zh 根据欧拉角信息计算四元数,旋转顺序为 YZX
*/
static fromEuler<Out extends __internal.$cocos.$core.$math.$type_define.IQuatLike>(out: Out, x: number, y: number, z: number): Out;
/**
* @zh 根据四元数计算欧拉角,返回角度 x, y 在 [-180, 180] 区间内, z 默认在 [-90, 90] 区间内,旋转顺序为 YZX
* @param outerZ z 取值范围区间改为 [-180, -90] U [90, 180]
*/
static toEuler<Out extends __internal.$cocos.$core.$math.$type_define.IVec3Like>(out: Out, q: __internal.$cocos.$core.$math.$type_define.IQuatLike, outerZ?: boolean): Out;
/**
* @zh 将当前四元数转化为欧拉角(x-y-z)并赋值给出口向量。
* @param out 出口向量。
*/
getEulerAngles(out: Vec3): Vec3;
/**
* @zh 根据欧拉角信息计算四元数,旋转顺序为 YZX
*/
static fromEuler<Out extends __internal.$cocos.$core.$math.$type_define.IQuatLike>(out: Out, x: number, y: number, z: number): Out;
/**
* @zh 根据四元数计算欧拉角,返回角度 x, y 在 [-180, 180] 区间内, z 默认在 [-90, 90] 区间内,旋转顺序为 YZX
* @param outerZ z 取值范围区间改为 [-180, -90] U [90, 180]
*/
static toEuler<Out extends __internal.$cocos.$core.$math.$type_define.IVec3Like>(out: Out, q: __internal.$cocos.$core.$math.$type_define.IQuatLike, outerZ?: boolean): Out;
/**
* @zh
* 通过欧拉角设置世界旋转
* @param x - 目标欧拉角的 X 分量
* @param y - 目标欧拉角的 Y 分量
* @param z - 目标欧拉角的 Z 分量
*/
setWorldRotationFromEuler(x: number, y: number, z: number): void;
/**
* @zh
* 通过欧拉角设置本地旋转
* @param x - 目标欧拉角的 X 分量
* @param y - 目标欧拉角的 Y 分量
* @param z - 目标欧拉角的 Z 分量
*/
setRotationFromEuler(x: number, y: number, z: number): void;
/**
* @zh
* 设置本地旋转
* @param x 目标本地旋转的 X 分量
* @param y 目标本地旋转的 Y 分量
* @param z 目标本地旋转的 Z 分量
* @param w 目标本地旋转的 W 分量
*/
setRotation(x: number, y: number, z: number, w: number): void;
/**
* @zh
* 设置本地旋转
* @param rotation 目标本地旋转
*/
setRotation(rotation: Quat): void;
/**
* @zh 将当前四元数转化为欧拉角(x-y-z)并赋值给出口向量。
* @param out 出口向量。
*/
getEulerAngles(out: Vec3): Vec3;