本帖最后由 脑的研发记录 于 2023-11-19 13:23 编辑
“数据结构课作业笔记”#008-数组-方块喷泉-循环队列预兆
所用编辑器版本0.27.0.0
代码随编辑器更新而略有变化
目录总览:
零.开发背景与意外收获
壹.第一个循环数组
贰.所需语法
叁.应用说明
肆.相关参考链接 (返回主站)
零.开发背景与意外收获
开发背景
想着用数组搓出循环队列,但是不好形容中间循环概念是怎样无中生有的。而且写帖子的时候,总想着在引入新概念的时候,能讲故事的就讲点故事。不让概念先入为主,就像是产生需求的时候,穷举方法解决需求的过程中,顺便产生了一个新的经验,刚好这个经验可以描述成其他样子,又在穷举经验的过程中验证了这个新的经验可以解决更大问题,就强调这个经验,形成了一个所谓的新概念,这个新概念也就是如今见到的教科书上的知识。如何用需求来引领学习,把需求换一种描述方式,在各种描述中,自然而然地意识到自己可以把自己的需求通过描述来转化成知识。这也是在帖子:“....笔记”#002....”的“水字数的道理“中,提到的:“从直觉与穷举开始,重新感受数据结构,给知识一个不需要理解的面貌——这可以是自然而然产生的事情”这个想法的最新理解和最新的阐述。而究竟是怎样自然而然,这就是我在尝试解释和以此试水写一些有意思的教材的探索目的、方向依据、以及基本的参考标准。
意外收获
答应是要更新帖子,然后好几天也没想到怎么过渡到新的知识,又有其他考试作业积压,一想就是一堆事,不想就难以决策先做哪个事,帖子更新,积压一个月的作业,备考小测,好像每天都有一堆办不完的事情。既有短期又有长期,既有感觉没有意义又必须做,又有感觉很有意义但是需要长久跟进也不知道成不成。人然后就困厄起来了。在这个困厄的情况下,只是根据以前的经验,知道摆烂就会更加困厄,努力应对就会精力磨损,还可能会被突然的活动影响,分不出精力应对意外事情。然后选择了一个不努力,也不躺平的选择,看看新编辑器有啥优化,看看之前的代码更新成啥样了。于是,更新完编辑器,备份完代码,不一键替换API,直接新建工程,手敲原来代码,看看能不能跑起来。
然后,
第一次代码,手敲代码,尝试动态生成方块,然后报错。原因是动态生成代码的函数改版了。根据鼠标悬停提示也不知道怎么改。
第二次代码,查API动态生成物体的代码,找函数。寄了。不会用。没看着案例代码。
第三次代码,穷举到想起来自己求助的帖子,里面有个注释的历史代码,还是从别人的帖子里复制粘贴来的。看格式差不多,这下应该能用了?复制粘贴,跑起来。能动态生成一个方块。可,然后再把动态生成的数据存进数组里。
第四次代码,发现setCollision接口废弃,觉得就这样提交,代码撑不过几个编辑器版本更新。又想起来之前getplayerID废弃接口和getuserID的替换排行榜的事情,就觉得替换接口应该问题不大。去查API碰撞。然后看不懂代码,其他的说明也只有数字代表的意义,没有函数。就回看代码。
第五次代码,变量提示错误,鼠标悬停,提示自动修正,才想起来可以鼠标悬停,看看代码有啥提示,就在废弃代码上悬停,看说明,说是请在Model里使用。有个关键词Model,直接搜,Model是个函数最好,目录看了半天,一个一个子目录看,最后还是在看着了,离着之前看不懂的代码差了7行子标题。
第六次开发,复制粘贴直接跑。Model样例成功,一看效果,原来是方块模拟,这不直接就是心心念念的方块倒下的物理效果的实现。大喜过望。
第七次开发,队列,塞代码,跑。不生成,原来是代码变量写错了,换变量,成了。生成次数有限,旧的方块传送到起点,改循环变量的大小,超过10就重置,从头开始。
第八次开发,加入计时器,跑代码方块生成,改计时间隔,减慢生成速度。跑,完事。
第一个方块喷泉,迟早会有人写出来代码,但是方块喷泉代码产生的时间提前到哪里,这是人的努力的力量。
科研好像就是穷举各种方法,穷举到一定程度,就能产生,但是怎样压缩穷举步骤,或者提前穷举完,这就是人的努力的力量。
所以理想的自然而然,就是产出品直接能当教程使用,也能直接应用到游戏开发,保持“首发”,较为完整地记录“从无到有”,帖子本身就是“自然而然”的真实写照。
9:00-10:46开发完代码
10:46-11:34故事回溯完毕
11:34-13:32帖子完成
壹.第一个循环数组
不多说,上代码,复制粘贴直接跑
最终成果
class ooh {
n: Model;
id: string;
}
@Component
export default class ModelExample extends Script {
//当脚本被实例后,会在第一帧更新前调用此函数
protected build: Array<ooh> = new Array(10);
// 100改小成50,控制距离
// protected i: number = -1;
protected j: number = 0;
protected k: number = 0;
/** 当脚本被实例后,会在第一帧更新前调用此函数 */
protected async onStart(): Promise<void> {
AssetUtil.asyncDownloadAsset("197386");
for (var j = 0; j < this.build.length; j++) {
this.build[j] = new ooh();
}
if (SystemUtil.isClient()) {
// InputUtil.onKeyDown(Keys.F1, () => {
// F1键 通知服务器执行事件
// mw.Event.dispatchToServer("Model");
// });
let timer = setInterval(()=>{
mw.Event.dispatchToServer("Model");
},100)
}
if (SystemUtil.isServer()) {
mw.Event.addClientListener("Model", () => {
if (this.j < 10) {
let box = GameObject.spawn("197386", {
transform: new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1)),
replicates: true
}) as Model;
this.build[this.j].n = box;
this.build[this.j].n.massEnabled = true;
this.build[this.j].n.mass = 200;
this.build[this.j].n.gravityEnabled = true;
this.build[this.j].n.friction = 0.1;
this.build[this.j].n.restitution = 1;
this.build[this.j].n.physicsEnabled = true;
}
this.j++;
if (this.j > 10) {
// this.build[this.k].n.physicsEnabled = false;
// this.build[this.k].n.setCollision(PropertyStatus.Off, true);
// this.build[this.k].n.setVisibility(PropertyStatus.Off, true);
// this.build[this.k].n.localTransform.position.x = 500;
// this.build[this.k].n.localTransform.position.y = 0;
// this.build[this.k].n.localTransform.position.z = 100;
this.build[this.k].n.localTransform=new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1));
this.k++;
this.k=this.k%10;
}
// let box = GameObject.spawn("197386", {
// transform: new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1)),
// replicates: true
// }) as Model;
// // 控制质量
// box.massEnabled = true;
// // 设置质量
// box.mass = 200;
// // 使用质量
// box.gravityEnabled = true;
// // 设置摩擦力
// box.friction = 0.1;
// // 设置弹力
// box.restitution = 1;
// // 开启物理模拟
// box.physicsEnabled = true;
});
}
}
}
实现了一堆方块在一个点不断产生。玩家可以和方块产生碰撞的效果。
代码拆解
数组定义:先有的案例代码,然后再适配的数组Modle类型,可以和上一篇帖子的最终成果比较“数据结构课作业笔记”#007-数组-从冲击层到按钮生成阶梯-排队队列 口袋方舟论坛|面向全年龄的UGC互动内容平台与交流社区 (ark.online)
class ooh {
n: Model;
id: string;
}
// @Component
// export default class ModelExample extends Script {
//当脚本被实例后,会在第一帧更新前调用此函数
protected build: Array<ooh> = new Array(10);
// 100改小成50,控制距离
// protected i: number = -1;
protected j: number = 0;
protected k: number = 0;
按时发送消息:
第一行代码是经过一些修饰,就是加入了一些其他说明,但是具体作用不明,因为没出BUG,其他理由就是学了不能马上用,用还需要更多新概念。
第二行是预先加载方块数据,不用在空场景里拖进方块才能跑代码。
第三,四,五行这是初始化。
第七行是判断客户端,因为代码默认在服务器和玩家的手机同时生成,在服务器生成的代码,第七行的systemUtil.isClient()就会返回false,这个if语句里面的代码就都不跑。如果是客户端,就执行里面的计时器,计时器里面的代码功能是发送消息,向服务器发送名为“Model”的消息。每100毫秒发送一次。
protected async onStart(): Promise<void> {
AssetUtil.asyncDownloadAsset("197386");
for (var j = 0; j < this.build.length; j++) {
this.build[j] = new ooh();
}
if (SystemUtil.isClient()) {
// InputUtil.onKeyDown(Keys.F1, () => {
// F1键 通知服务器执行事件
// mw.Event.dispatchToServer("Model");
// });
let timer = setInterval(()=>{
mw.Event.dispatchToServer("Model");
},100)
}
第三部分,如果在服务器里,动态产生方块
对比之前的“数据结构课作业笔记”#007-数组-从冲击层到按钮生成阶梯-排队队列 口袋方舟论坛|面向全年龄的UGC互动内容平台与交流社区 (ark.online)的最终成果代码
可以发现多了isServer()函数,和isClient功能类似。服务器里的这个isServer函数返回值是true;
第二行是接受客户端发送的名称为“Model”的消息。然后执行预设好的“Model”事件名称后边的事情。
如果小于10个,就先初始化,动态生成物体,设置物体位置,设置物体旋转,设置物体大小。
然后后面的as Model是指转化成Model类型。之前的类型可能不是Model类型,或者有其他方式,但是还没探索出来。因为这是编辑器里的第一个方块喷泉代码。
if (SystemUtil.isServer()) {
mw.Event.addClientListener("Model", () => {
if (this.j < 10) {
let box = GameObject.spawn("197386", {
transform: new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1)),
replicates: true
}) as Model;
this.build[this.j].n = box;
this.build[this.j].n.massEnabled = true;
this.build[this.j].n.mass = 200;
this.build[this.j].n.gravityEnabled = true;
this.build[this.j].n.friction = 0.1;
this.build[this.j].n.restitution = 1;
this.build[this.j].n.physicsEnabled = true;
}
this.j++;
if (this.j > 10) {
// this.build[this.k].n.physicsEnabled = false;
// this.build[this.k].n.setCollision(PropertyStatus.Off, true);
// this.build[this.k].n.setVisibility(PropertyStatus.Off, true);
// this.build[this.k].n.localTransform.position.x = 500;
// this.build[this.k].n.localTransform.position.y = 0;
// this.build[this.k].n.localTransform.position.z = 100;
this.build[this.k].n.localTransform=new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1));
this.k++;
this.k=this.k%10;
}
// let box = GameObject.spawn("197386", {
// transform: new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1)),
// replicates: true
// }) as Model;
// // 控制质量
// box.massEnabled = true;
// // 设置质量
// box.mass = 200;
// // 使用质量
// box.gravityEnabled = true;
// // 设置摩擦力
// box.friction = 0.1;
// // 设置弹力
// box.restitution = 1;
// // 开启物理模拟
// box.physicsEnabled = true;
});
}
循环的功能实现
如果j大于10,k就开始增加。
因为k从零开始,
穷举0%10=0
1%10=1
2%10=2
3%10=3
4%10=4
5%10=5
6%10=6
7%10=7
8%10=8
9%10=9
到了10之后,10%10=0
于是k从零开始。实现了循环
作用其实就是
if(K>10){
k=0}
效果是第k个物体又回到了起点。
this.j++;
if (this.j > 10) {
// this.build[this.k].n.physicsEnabled = false;
// this.build[this.k].n.setCollision(PropertyStatus.Off, true);
// this.build[this.k].n.setVisibility(PropertyStatus.Off, true);
// this.build[this.k].n.localTransform.position.x = 500;
// this.build[this.k].n.localTransform.position.y = 0;
// this.build[this.k].n.localTransform.position.z = 100;
this.build[this.k].n.localTransform=new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1));
this.k++;
this.k=this.k%10;
}
循环的概念其实是希望场景里就生成一些物体,不要太多,然后持续有这些物体在运动,比如说这里就选择生成了10个方块。
十个方块生成了之后,就把最先生成的方块放回原来位置。这个和喷泉一样。最先喷出的水最先被吸入水泵继续喷出一样。
这个是修改物体的位置,相当于重新初始化了。
从绿色代码里面的尝试试出来的,注释的代码都是当时开发的遗迹。
this.build[this.k].n.localTransform=new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1));
参数说明,可以通过改true false来控制物体的功能是否使用这些功能,
数字大小可以控制喷泉的范围,通过控制摩擦来控制喷泉范围,控制方块质量控制喷泉高度,角色推方块难易度。
// let box = GameObject.spawn("197386", {
// transform: new Transform(new Vector(500, 0, 100), new Rotation(0, 0, 0), new Vector(1, 1, 1)),
// replicates: true
// }) as Model;
// // 控制质量
// box.massEnabled = true;
// // 设置质量
// box.mass = 200;
// // 使用质量
// box.gravityEnabled = true;
// // 设置摩擦力
// box.friction = 0.1;
// // 设置弹力
// box.restitution = 1;
// // 开启物理模拟
// box.physicsEnabled = true;
贰.所需语法
Model | API (ark.online)
可看可不看,但是里面讲的用法权威。对应代码第二部分的方块初始化与参数设定。
叁.应用说明
物理模拟,场景喷泉。
技能释放,带物理阻挡效果的粒子动画,
攻击到目标时释放一堆方块实现掩埋效果。
高塔倒塌的壮观场景,
陷阱生成,
陷落动画。
怪兽生成时建筑倒塌的物理模拟,结合CG脚本k帧可以拍穿越倒塌废墟的运镜电影。
场景实时交互。
肆.相关参考链接 (返回主站)
普通大学生“数据结构”课作业笔记#000-目录-逻辑结构与存储结构 口袋方舟论坛|面向全年龄的UGC互动内容平台与交流社区 (ark.online)
|