政安晨【示例演绎虚拟世界开发】(三):TypeScript编程语言——实现游戏脚本开发

TypeScript是一种开源的编程语言,由微软开发和维护。它是JavaScript的一个超集,意味着任何合法的JavaScript代码也是合法的TypeScript代码。TypeScript通过添加静态类型检查和一些新特性来增强JavaScript的功能。

它在JavaScript的基础上添加了类型系统,使得TypeScript具备了静态语言的特点。

TypeScript具有以下特点:

  1. 静态类型检查:TypeScript引入了静态类型检查,可以在代码编译阶段发现潜在的错误,提供更好的代码可靠性和可维护性。

  2. 类和接口:TypeScript支持类和接口的定义,使代码结构更加清晰和可扩展。

  3. 泛型:TypeScript支持泛型,使代码可以适用于多种数据类型,提高代码的复用性。

  4. 模块化:TypeScript支持模块化的开发方式,可以将代码分割成多个模块,提高代码的可维护性。

  5. 兼容性:TypeScript可以兼容现有的JavaScript代码,可以直接使用现有的JavaScript库和框架。

  6. 工具支持:TypeScript具有完善的工具链,包括代码编辑器、调试器和构建工具等,提供更好的开发体验。

总而言之,TypeScript可以提供更好的代码可靠性和可维护性,使JavaScript开发更加高效和舒适。它广泛应用于大型项目的开发,也被许多开发者用于小规模项目的开发。


变量的声明

在TypeScript中,可以使用关键字let来声明一个变量,并通过在变量名之后添加冒号“:”来指定变量的类型(let变量名:类型=值):

let hp: number = 100; //基础血量

上面的代码通过let关键字定义了一个名为hp的数值类型变量,并将它的值设置为100。

代码中的“//”表示单行注释,“//”后面的文字是注释的内容。TypeScript中的基础类型,除了上面使用到的数值类型(number),还有字符串类型(string)和布尔类型(boolean),如下所示:

let skill_name: string = '技能名'; // 技能名字
let is_cd: boolean = false; // 技能冷却状态

在定义变量时也可以不进行显式的类型指定,此时的变量就会将初始定义时赋值的变量类型作为默认类型,如下所示:

let skill_name = '技能名'; // string
let is_cd = false; // boolean

这里需要注意的是,在指定了变量类型之后,如果对不同类型的值进行赋值,将会报错。

在阅读的过程中,您可以安装cocos creator,通过console.log输出语句来对代码进行测试。将start函数中的代码块进行如下修改,再次预览运行,查看输出结果。

 start() {
        
        //zachen
        console.info('Hello world');
        let hp: number = 100; // 基础血量
        let skill_name: string = '烈焰斩'; // 技能名字
        let is_cd: boolean = false; // 技能冷却状态
        console.log(hp);
        console.log (skill_name);
        console.log(is_cd);

    }

条件语句

使用条件语句可以基于不同的条件(true或false)执行对应的游戏逻辑,如下图所示:

(1)if语句。只有当指定条件为true时,if语句内的代码块才会被执行。

在执行上面的代码时,我们会发现只输出了一次【使用必杀技】,并没有输出【再次使用必杀技】。这是因为在第一次执行if判断的时候,mp满足了超过5点的条件,在第一个if语句块的代码被执行完成后mp被清空,在执行第二个if语句块时因为mp不足,所以if语句块内的代码块并没有被执行。

(2)if…else语句。if语句后面可以跟一个可选的else语句,else语句在布尔表达式为false时执行。

在执行上面的代码时,当前的mp不满足超过5点的条件,此时会输出【法力不足,使用普通攻击】。

(3)if…else if…else语句。在else之后可以跟一个新的判断分支,当使用该语句时会从多个代码块中选择一个来执行。

在执行上面的代码时,因为当前的mp不满足超过5点的条件,所以会继续执行下一个if语句,当mp满足使用烈焰斩的条件时,会输出【使用烈焰斩】。

switch语句

使用switch语句可以基于多个不同的条件执行对应的游戏逻辑。switch语句会将变量依次对比各个case的值,当匹配到对应的case时,会执行对应的case语句的代码块。当所有的case均匹配不到时,将会执行default代码块中的内容。

在执行上面的代码时,因为job的值匹配到了第三个case中的“法师”,所以程序运行后输出了【火球术】。

这里需要注意的是,当case的值匹配到变量后,与该case关联的代码块会被执行,因此在每个case执行结束后,还需要使用break来阻止程序自动执行下一个case的代码块。

循环基础

在编写代码的过程中,我们可能会遇到需要多次执行相同代码块的情况。假设我们需要实现一个5连击技能,每次攻击都会造成3点伤害,并在每一击之后都输出敌人当前的剩余血量。在不使用循环的情况下,我们需要把两行代码连续、重复地编写5次,如下所示。

虽然我们可以通过复制、粘贴的方式简化重复编写的过程,但是这种方式并不利于对代码的维护。比较推荐的方式是合理地使用for循环。for循环可以将重复的代码块移到循环逻辑中,从而简化代码,语法如下所示。

其中会首先执行init,且只会执行一次。init常用于初始化循环变量。condition是循环条件,在每次执行代码块之前都会进行一次判断,当条件为true时会执行循环中的代码块,为false时则停止执行循环。在每次执行完成循环中的代码块后,会执行一次increment语句。

现在我们尝试用for循环改写最初的代码,如下所示:

在上面的代码中,“let i:number=0”表示循环语句声明了变量i,并将其初始化为0。

“i<5”是循环的条件,只有在变量i的值小于5的情况下才会执行循环,否则将退出循环。

“i++”会在每次循环执行完成后对i的值进行+1,以此来保证循环可以达到退出条件。

除了for循环,我们也可以使用while循环。

while循环会一直执行循环语句的代码块,直到条件为false时,才会结束循环。

我们尝试将for循环改写为while循环,如下所示。

数组

假设现在有一个需求,需要将游戏中所有的职业存储起来,在不使用数组的情况下,我们需要定义多个变量来存储所有的职业。这里我们定义变量job_num来存储当前的职业的数量,并以“job_职业编号”的格式定义多个职业的变量名,如下所示:

目前只有3个职业,通过定义多个变量的方式来存储职业似乎没有什么问题,但是当游戏需要进行扩展时,添加新职业的操作就会变得特别烦琐。

假设此时添加了2个新职业:召唤师和圣骑士,代码如下所示:

仔细观察上面的代码,你有没有发现什么问题?相信细心的你已经发现了,在添加了新的职业后,我们忘记将job_num变量的值从3修改成5了,这将会导致游戏在运行的过程中出现不可预知的bug:

定义多个变量来存储一系列的职业的方式显然是低效且容易出问题的。此时可以选择定义一个名为jobs的数组,并用其将所有的职业进行存储。定义数组的方式和定义变量的方式类似(let数组名:类型[]=[值1,值2,值3...])。修改为数组之后,代码如下所示。

数组中的每个元素都对应一个编号,我们把这个编号称为下标。下标从0开始依次递增,通过jobs[下标]的方式可以获取对应的变量值。此外,我们也可以通过jobs.length获取当前数组中的元素数量。通过使用数组我们可以很好地管理需要存储的一系列变量,当需要继续添加新的职业时,只需要向数组中插入新的值即可。

值得一提的是,我们也可以通过for/of循环语句方便地遍历数组中的对象,代码如下所示。

对象

与数组类似,对象的作用之一也是更方便地组织和存储多个变量。对象是包含一组键-值对的实例(let对象名={键1:值1,键2:值2…}),对象的值可以是变量、函数、数组、对象等。

函数

如果说变量的作用是存储数据,那么函数就可以被理解为用于存储代码逻辑的特殊变量。我们可以把多行执行语句存储到一个函数中,在需要使用对应的语句时,只要调用相应的函数即可。

通过关键字function来定义一个函数,并使用花括号来包含函数的代码块,语法如下。

当函数有返回值时,需要在声明函数的时候指定返回值的类型,如下所示。

在函数定义的时候,也可以指定需要传递的参数,如下所示。

类用于定义事物的抽象特点。从代码组织的角度观察会发现,类和对象“长得非常像”,类同样描述了所创建的对象的共同的属性和方法。TypeScript类的定义方式如下。

观察之前在Cocos Creator中自动生成的脚本会发现,我们之前都是在Game类中编写逻辑代码的。这里需要注意的是,在资源管理器中创建的脚本,它的类名默认与脚本名保持一致。假设你创建了一个名为Hero的脚本,那么Cocos Creator就会默认生成一个Hero类,如下所示。

在默认生成的代码中,被注释掉的dummy和serializableDummy是类的成员属性,start和update是类的成员函数。

脚本组件基础

我们已经成功地在Cocos Creator中创建并运行了脚本,也学习了TypeScript的基础语法,现在让我们回过头来学习脚本组件的基础知识。

组件类

所有继承自Component的类都被称为组件类,其对象被称为组件。我们可以将组件挂载到场景中的节点上,用于控制节点的行为。需要注意的是,如果没有使用@ccclass将组件类声明成cc类,则无法将组件添加到节点上。

cc类

将装饰器ccclass应用在类上时,此类称为cc类。cc类注入了额外的信息以控制Cocos Creator编辑器对该类的序列化和场景编辑器对该类的展示等。因此,未声明ccclass的组件类无法作为组件被添加到节点上。

装饰器ccclass的参数name指定了cc类的名称,cc类名是独一无二的,这意味着同类名在不同目录下也是不被允许的。当需要获取相应的cc类时,可以通过cc类名来查找。

属性装饰器

属性装饰器property可以被应用在cc类的属性或访问器上,并用于控制Cocos Creator编辑器中cc类属性的序列化,以及该属性在属性检查器上的显示等。

这里需要注意的是,属性装饰器property的选项type会指定属性的cc类,若未指定,则Cocos Creator将从属性的默认值中推导其类型,完整的可选择参数可以参考Cocos Creator的官方文档。

我们可以将Game脚本进行修改,分别定义job变量和hp变量,同时在start函数中通过“this.变量名”的方式访问并输出成员变量的值,代码如下所示。

以普通方式声明的属性不能在编辑器中被访问,只有使用了属性装饰器property修饰的属性才能在编辑器中被访问。因此,在Node节点的属性检查器中,虽然我们可以查看并编辑在脚本中定义的【hp】属性,却看不到同时定义的【job】属性,如下图所示。

在编辑器中尝试将【hp】的值修改为【50】,再次进行预览运行,我们会发现输出结果已经变成了【50】,如下图所示。

与其他节点及组件交互

在游戏开发的过程中,脚本通常需要与多个节点进行交互。假设现在有一个需求,需要将Label节点的string属性进行动态调整,使默认的【Hello World】文本在游戏运行后变为【Game Start】。此时我们就需要让Game脚本与Label节点进行交互,代码修改如下所示。

在上面的代码中,我们定义了label变量并将其默认值设置为null,同时将它的type声明为Label组件。这里需要注意的是,为了能在脚本中正常使用Label类,还需要在脚本的头部对该类进行导入。

在通常情况下,使用VS Code编写代码时,编辑器会对代码进行实时检测,当发现我们使用了未导入的内置组件类时,该类将会被VS Code编辑器自动导入。如果编辑器未能正确检测到类的引用,那么也可以手动将用到的类进行导入,如下图所示。

与此同时,我们还需要在属性检查器中将Label节点与Game脚本进行绑定,否则在预览运行时会报错。回到Cocos Creator编辑器,将层级管理器中的Label节点拖动到Game脚本组件中的Label属性上,从而完成对组件的绑定,如下图所示。

完成拖动绑定后预览运行,浏览器中显示的文字将会从【Hello World】变成【Game Start】。

 脚本的生命周期

何为生命周期?从字面上可以理解成事物从出生到死亡的过程,而对应到脚本中指的就是从创建到销毁的整个过程。在Cocos Creator中,每个脚本组件都有自己的生命周期。引擎为脚本组件提供了生命周期的回调函数,我们只需要在cc类中定义对应的函数即可。当执行到相应的周期时,就会调用该函数。

何为生命周期?从字面上可以理解成事物从出生到死亡的过程,而对应到脚本中指的就是从创建到销毁的整个过程。

在Cocos Creator中,每个脚本组件都有自己的生命周期。引擎为脚本组件提供了生命周期的回调函数,我们只需要在cc类中定义对应的函数即可。当执行到相应的周期时,就会调用该函数。

脚本组件的生命周期回调函数包括:onLoad、onEnable、start、update、lateUpdate、onDisable、onDestroy。脚本组件的生命周期如下图所示。

1.onLoad

onLoad回调函数会在脚本组件的初始化阶段被调用,比如所在的场景被载入或者所在的节点被激活。在onLoad阶段,可以获取场景中的其他节点,以及与节点关联的资源数据。onLoad总会在调用start方法前被执行,可以用于设置脚本的初始化顺序。通常我们会在onLoad阶段做一些与初始化相关的操作。

2.onEnable

当组件的enabled属性从false变为true时,或者所在节点的active属性从false变为true时,都会激活onEnable回调函数。如果节点第一次被创建且enabled属性为true,则会在onLoad之后、start之前调用onEnable回调函数。

3.start

start回调函数会在第一次激活组件之前,也就是第一次执行update之前被触发。start通常用于初始化一些中间状态的数据,这些数据可能会在update时发生改变,并且被频繁地进行enable和disable操作。

4.update

update回调函数会在游戏每一帧渲染之前被触发。游戏开发的一个关键点是在每一帧渲染前更新物体的行为、状态和方位。这些更新操作通常都被放在update回调函数中。

5.lateUpdate

lateUpdate回调函数会在游戏每一帧渲染之后被触发。update会在所有的动画更新之前被执行,但如果我们要在动效(如动画、粒子、物理等)更新之后进行额外的操作,或者希望在执行完成所有组件的update之后进行其他操作,就需要用到lateUpdate回调函数。

6.onDisable

当组件的enabled属性从true变为false时,或者所在节点的active属性从true变为false时,会激活onDisable回调函数。

7.onDestroy

当组件或者所在节点调用了destroy函数时,回调函数onDestroy也会被调用,并在当前帧结束时统一回收组件。

结论

现在,咱们了解了TypeScript的基础知识,也掌握了Cocos Creator脚本组件的创建与使用。

同时,我们还在项目中创建了第一个脚本组件,学习了如何让脚本组件与其他组件进行交互,并通过脚本组件对默认的Label文本进行了修改。最后我们还学到了脚本组件的生命周期的基础知识。


学好脚本编程语言是构建AI虚拟世界的条件之一,小伙伴们让我们加油!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/421612.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

if语句用法

if语句是单条件分支语句 定义:根据一个条件来控制程序执行流程(如图3.2)。 语法格式: if(表达式){ 若干语句 } ★注意★: ① 表达式的值必须是boolean 型; ② 不能用0代表false;用1代表 true&am…

Linux 之压缩与解压相关命令的基础用法

目录 1、zip 与 unzip 2、gzip 命令 3、tar 命令 1、zip 与 unzip 在桌面新建一个文件和文件夹用于测试 在 test 目录下有一个 1.txt 文件 我们使用 zip 命令对其压缩 用法: zip 自定义压缩包名 被压缩文件路径位置 zip myon.zip 1.txt 因为我们这里就是在 …

『运维备忘录』之 RegEx 正则表达式实例汇总

运维人员不仅要熟悉操作系统、服务器、网络等知识,甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作,持续给大家更新运维工作所需要接触到的知识点,希望大…

抽象类与抽象方法

文章目录 抽象类抽象类的特点 抽象方法抽象方法的特点 模板设计模式模板设计模式能解决的问题示例 #抽象类与抽象方法 抽象类 用abstract关键字来修饰一个类时,这个类就叫抽象类。 public abstract 类名{... }抽象类的特点 1)抽象类不能被实例化。 2&…

javaScript 深浅拷贝

javaScript深浅拷贝 浅拷贝 自己创建一个新的对象,来接受你要重新复制或引用的对象值。如果对象属性是基本的数据类型,复制的就是基本类型的值给新对象,但如果属性是引用数据类型,复制的就是内存中的地址,如果其中一个…

pip降级在pycharm中

PyCharm依赖于"–build-dir"参数安装第三方库,但该参数在最新的23.0版pip中已删除 解决办法就是降级pip,PyCharm中选择File,找到编译器,点击pip,勾选对应版本即可 或者在cmd中执行运行python -m pip install…

swift 长按桌面图标弹出快捷选项

文章目录 一、3D Touch二、主屏交互1. 静态添加2. 动态添加三、监听主屏交互按钮的点击事件四、预览和跳转1. 注册3D touch2. 实现协议3. 在目标控制器复写previewActionItems4. 使用UIContextMenuConfiguration一、3D Touch 3D Touch通过屏幕下方的压力感应器来感知不同的压力…

蓝桥杯Java B组历年真题(2013年-2019年)

一、2013年真题 1、世纪末的星期 使用日期类判断就行,这里使用LocalDate,也可以使用Calendar类 答案 2099 使用LocalDate import java.time.LocalDate; import java.time.format.DateTimeFormatter; // 1:无需package // 2: 类名必须Main, 不可修改p…

【AIGC】微笑的秘密花园:红玫瑰与少女的美好相遇

在这个迷人的画面中,我们目睹了一个迷人的时刻,女子则拥有一头柔顺亮丽的秀发,明亮的眼睛如同星河般璀璨,优雅而灵动,她的微笑如春日暖阳,温暖而又迷人。站在红玫瑰花瓣的惊人洪水中。 在一片湛蓝无云的晴…

YOLOv9有效提点|加入BAM、CloFormer、Reversible Column Networks、Lskblock等几十种注意力机制(二)

专栏介绍:YOLOv9改进系列 | 包含深度学习最新创新,主力高效涨点!!! 一、本文介绍 本文只有代码及注意力模块简介,YOLOv9中的添加教程:可以看这篇文章。 YOLOv9有效提点|加入SE、CBAM、ECA、SimA…

【机器学习300问】25、常见的模型评估指标有哪些?

模型除了从数据划分的角度来评估,我上一篇文章介绍了数据集划分的角度: 【机器学习300问】24、模型评估的常见方法有哪些?http://t.csdnimg.cn/LRyEt 还可以从一些指标的角度来评估,这篇文章就带大家从两个最经典的任务场景介绍…

天津公租房租金怎么算?附计算方式

天津公共租赁住房租金如何计算?附计算方法 天津市公共租赁住房租金租金标准建筑面积(100分-减分)。 公共租赁住房租金按照建筑面积计算。 应收租金以人民币计算,低于人民币的部分四舍五入。 具体内容见正文。 申请天津公共租赁住…

Go 与 Rust:导航编程语言景观

在当今构建软件时,开发者在编程语言上有着丰富的选择。两种脱颖而出的语言是 Go 和 Rust - 都很强大但却截然不同。本文将从各种因素比较这两种语言,以帮助您确定哪种更适合您的需求。 我们将权衡它们在并发、安全性、速度、互操作性等方面的方法。我们将…

软件系统开发流程规范

目的:规范系统开发流程,提高系统开发效率。 立项申请需求分析方案设计方案评审开发调整测试阶段系统培训试运行测试验收投入使用 所有文档过去进主页获取。

基于 STM32U5 片内温度传感器正确测算温度

目录预览 1、引言 2、问题 3、小结 01 引言 STM32 在内部都集成了一个温度传感器,STM32U5 也不例外。这个位于晶圆上的温度传感器虽然不太适合用来测量外部环境的温度,但是用于监控晶圆上的温度还是挺好的,以防止芯片过温运行。 02 问题…

MATLAB知识点:利用智能缩进整理代码

​讲解视频:可以在bilibili搜索《MATLAB教程新手入门篇——数学建模清风主讲》。​ MATLAB教程新手入门篇(数学建模清风主讲,适合零基础同学观看)_哔哩哔哩_bilibili 节选自​第4章:MATLAB程序流程控制 小技巧&#x…

LZO索引文件失效说明

在hive中创建lzo文件和索引时,进行查询时会出现问题.hive的默认输入格式是开启小文件合并的,会把索引也合并进来。所以要关闭hive小文件合并功能!

GIT概述及安装

文章目录 01.GIT概述内容小结 02.GIT相关概念(掌握)目标内容小结 03.GIT下载与安装目标内容 01.GIT概述 内容 Git是目前世界上最先进的分布式文件版本控制系统(没有之一) 版本控制 所谓的版本控制就是将一组文件的改动记录下来,形成版本历史…

2024年新提出的算法|LEA爱情进化算法(Love Evolution Algorithm)

Love Evolution Algorithm: a stimulus–value–role theory-inspired evolutionary algorithm for global optimization 爱情进化算法Love Evolution Algorithm,LEA,于2024年2月发表在中科院3区SCI期刊 The Journal of Supercomputing。 1、简介 本文提…

新 Logo 正式发布,Tubi 品牌全面升级!

作为新一代观众的首选流媒体平台,Tubi 持续扩大自身影响力,并于近日推出了富有活力的新品牌形象。 根据 Nielsen 的 The Gauge 报告,Tubi 在 2024 年 1 月的电视总观看份额提升至 1.5%,在年轻人和多元化观众群体中的吸引力持续上升…