[开发者心得] “数据结构课作业笔记”#008-数组-方块喷泉-循环队列预兆

[复制链接]
584 |3
脑的研发记录 发表于 2023-11-19 13:23:57 | 显示全部楼层 |阅读模式
本帖最后由 脑的研发记录 于 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)




回复

使用道具 举报

复读机读复读机 发表于 2023-11-19 19:28:09 | 显示全部楼层
可以看看这篇027升级API变动https://docs.ark.online/ReleaseN ... 88%97%E8%A1%A8.html
查查之前的API被改成什么了
回复

使用道具 举报

复读机读复读机 发表于 2023-11-19 19:29:24 | 显示全部楼层
复读机读复读机 发表于 2023-11-19 19:28
可以看看这篇027升级API变动https://docs.ark.online/ReleaseN ... 88%97%E8%A1%A8.html
查查之前 ...

欢迎进入027时代
回复

使用道具 举报

脑的研发记录楼主 发表于 2023-11-19 22:25:03 | 显示全部楼层

粒子操控2.0,启动
回复

使用道具 举报

热门版块
快速回复 返回顶部 返回列表