欢迎光临散文网 会员登陆 & 注册

自制小球淘汰赛教程(二)传送门、闪队小球以及它们背后的原理

2023-07-26 16:56 作者:灰安教主  | 我要投稿

一、传送门和碰撞代码基础格式

小球淘汰赛里面的传送门是怎么实现的呢?

首先,画一个你想用来当传送门的东西,比如我随便画个红色长方形。

右键传送门,打开script脚本选单,找到onCollide.

oncollide的意思是:这个东西每被碰撞一次,就执行一次右边的代码。

右边的代码默认是(e)=>{ },你可以把它理解成代码格式,这是空代码,什么效果都没有。

今后所有这类(e)=>{ },要书写代码时,千万别把(e)=>{ }删掉!自己的代码写在大括号里面。

那么,先看一个传送门代码的实例:

一个传送门代码


如果你会英文,知道英文单词的意思,应该一眼就能看明白。

英文字母大小写无所谓,不影响实际效果。你可以全部大写,全部小写,或者大小写混杂都没问题。

(e)=>{}和e.是代码格式,先忽略掉。

onCollide(在碰撞时)other(别的)pos(位置)=(等号,是赋值符号)[60,100](一个具体的位置坐标)

意思就是,当它被碰撞时,撞到它的东西,位置坐标就变成[60,100]。

是不是很好理解?

所有onCollide代码都可以套用这个格式。

other可以改成this,this表示这个东西本身,other表示撞到它的东西。

比如,你写e.this.pos = [60,100],意思就是当它被碰撞时,这个东西本身的位置坐标变成[60,100]。

e.this.可以省略,直接写pos=[60,100]默认就是e.this.。e.other.不能省略。

那么,总结一下oncollide代码的基本格式:

等号左边:写想要变的属性的名字,至于名字是啥,去看教程第一章讲的,script脚本选单里面那些英文单词就是属性名字。

等号右边:写你想要的数值。可以不写具体数值,但要注意,不管写什么,格式都保持一致!比如,坐标pos是二项数组,等号右边就必须全部是二项数组,不能写成单个整数。

下面看几个淘汰赛常用的onCollide代码实例:

(这里做展示,我把所有的(e)= > {  }格式省略掉了,你自己在algodoo里面写代码时千万别把(e)= > {  }删掉)

①e.other.vel = [5,5]

②e.this.color = e.other.color

③angle = angle + 1

④text = e.other.materialname

⑤color = color -[0,0,0,0.25]


只要看得懂这些英文单词,你应该就大概知道这些代码会是什么效果了。

①other(别的)vel(瞬时速度)=(等号,是赋值符号)[5,5](一个具体的瞬时速度)

就是会给小球特定速度的障碍物,用来当做通关路径比较固定的关卡地板。

②this(这个)color(颜色)=(等号,是赋值符号)other(别的)color(颜色)

被撞之后,它的颜色变成撞它的东西的颜色,这就是能被染色的障碍物。

③(没有e.xxxx.前缀,默认是e.this)angle(角度)=(等号,是赋值符号)(没有e.xxxx.前缀,默认是e.this)angle(角度)+1

意思就是,被撞一次,这个东西的角度值就加一。

④(没有e.xxxx.前缀,默认是e.this)text(文字)=(等号,是赋值符号other(别的)materialname(物体名字)

意思就是,被撞一次,它显示的文字就变成对方的名字。这就是过关区上方显示名字的文本框。

⑤color(颜色)=(等号,是赋值符号)color(颜色)-[0,0,0,0.25]

color是个四项数组,意思就是,每被撞一次,它的color值的第四项就减少0.25。color第四项是透明度,也就是被撞一次就变得更透明一些。

.

.

.

如果你要使每次碰撞执行多个效果,比如既传送又改变速度,就用分号隔开,像这样写:

(e)=>{

  e.other.pos = [60,100];

  e.other.vel = [5,5]

}

以上就是oncollide代码的最基本的格式。


二、其他(e)=>{  }



我们可以看到,除了oncollide,其他还有好些地方默认写的(e)=>{},代码书写方法跟oncollide是一样的,只是触发条件不同。

e.other是oncollide专有的,其他地方没有e.other.,但是都有e.this.(当然e.this.可以省略不写)。

oncollide是碰撞时才执行代码,那么说下其他地方代码的触发条件。

【poststep】当场景在运行时,这里的代码就会一直执行。

【update】只要你打开了algodoo,不管你有没有按空格开始运行,这里的代码始终在执行。

【onClick】这个东西被鼠标左键点击了,才执行代码。

【onDie】这个东西以任何方式死了(消失了),就执行代码。

【onHitByLaser】这个东西被激光照到了,就执行代码。这里可以写e.laser.,让照到它的激光笔来执行代码,跟oncollide的e.other.原理相同。

【onKey】我没用过,不做介绍。

【onSpawn】这个东西出现在场景的一瞬间,执行代码。(刚打开场景也算onspawn,可用来记录自定义函数。)


三、条件判断和逻辑判断

在做传送门时,有时候可能会有这样的困扰,直接写e.other.pos = [x,y]的话,只要碰到它的东西就都会传送。但是,如果我只想让小球传送,其他东西碰到不传送,该怎么办呢?

这时候就要用到条件判断了。

条件判断和逻辑判断符号:

> 大于

< 小于

== 等于(条件判断中的等于是两个等号,只有一个等号表示赋值)

>= 大于等于

<= 小于等于

!= 不等于

&& 与

|| 或

!非

条件判断的格式:

条件 ? {符合条件执行的代码}:{不符合条件执行的代码}

当然,还是得写在(e)=>{  }的大括号里面,这个格式始终不能省略。

我们看个例子,写在oncollide里面的:

e.other.radius == 0.25 ? {

  e.other.pos= [60,100]

}:{}

对照上面的条件判断符号,就知道它的意思了

这是传送门的碰撞代码,但是加了个判断条件:

对方的半径是不是等于0.25?如果符号这个条件,就执行e.other.pos= [60,100],也就是传送;如果不符合条件,不符合条件代码是空的,也就是无事发生。

这样,这个传送门就“只传送半径为0.25的东西”,只要不符合这个条件,都不会被传送门传走。什么方块障碍物啊,乱七八糟的多边形啊,你都没有半径这项属性,别想着碰我传送。


其他条件判断和逻辑判断符号使用示例:

①在poststep里写

(e)=>{

e.this.colorHSVA(3)<=0? {

    e.this.timetolive = 0

}:{}

}

ColorHSVA(3)是什么意思呢?这种格式表示取数组中的一个数字。我们知道colorHSVA是四项数组,假设某个东西的colorHSVA是[180,0.5,1,0.25],那么colorHSVA(0)表示第一个数180,colorHSVA(1)是第二个数0.5,colorHSVA(2)是第三个数1,colorHSVA(3)是第四个数0.25。

对,数组的编号是0,1,2,3……的顺序,也就是说,你要取数组中的第x个数字,就得写数组(x-1)。

回到这个判断语句,poststep是运行后时刻执行代码,这东西的colorHSVA第四项是不是小于等于0?如果是,那这东西的存活倒计时就变成0;如果不是,就无事发生。

配合oncollide里写colorHSVA = colorHSVA - [0,0,0,0.2],就做出了“撞一次就变透明一点的方块,完全透明就消失”的障碍物,也就是淘汰赛中的“集体打工关卡”。

②在oncollide里写:

e.other.colorHSVA(0) >=165 && e.other.colorHSVA(0)<=195 ? {

  e.other.pos = [60,100]

}:{e.other.pos = [60,90]}

对照上面的符号表,意思就是,碰到它的东西colorHSV第一项(也就是色相)是否大于等于165,并且同时满足色相小于等于195?(这个条件就是筛选出色相在165~195的东西,也就是青队)如果满足条件(是青队的),就传送到坐标[60,100];如果不满足条件(不是青队的),就传送到坐标 [60,90]。

总结一下,条件判断作用就是分类筛选,只让符合条件的对象执行代码。


四、常用数学表达式

前面我们可以看到,oncollide代码里面,等号右边不一定要写具体的数值,比如angle = angle + 1。

那么,既然能写加号,其他数学符号能不能用呢?

当然可以用。

如果你数学成绩很差,就用最简单的加减乘除吧;如果数学还不错,可以用取余、三角函数、对数、根号、勾股定理等更多数学表达。


①基础运算:

+ 加号

- 减号

* 乘号

/ 除号

()括号  四则运算当然是先乘除后加减,如果想要先加减,请使用括号提高优先级。

% 取余(也可以写成mod)  示例:angle % 2  就是角度值除以2的余数。

幂运算  示例:vel ^ 2  就是速度的平方

(多项数组每项都会执行运算,比如速度是[3,6],那么vel ^ 2就相当于[3 ^ 2 ,6^2]也就是[9,36])

用于布尔变量转换,也就是true和false互换。比如我在oncollide里写e.other.heterocollide = ! e.other.heterocollide,heterocollide是无自身碰撞,意思就是被撞一次,无自身碰撞如果是true就变成false,如果是false就变成true。


②特殊数和随机数

math.pi 圆周率,algodoo取的值是3.1415927

math.e 自然常数,algodoo取的值是2.7182817

rand.uniform01 取一个0~1之间的随机数(每个数概率相同)

Rand.direction2D 在[0,0]为圆心、半径1的圆上,随机取一个坐标点(每个坐标概率相同)

Rand.boolean 随机生成布尔值,即随机选true或false

Rand.normal 取一个-6~6之间的随机数(一维正态分布形式)

Rand.normal2D 取一个每项都在-6~6之间的随机二项数组(二维正态分布形式)

比如,我想让碰到的小球随机传送到四个顶点分别为[0,0],[0,8],[8,0],[8,8]的正方形区域内随机坐标,那就可以在oncollide里写e.other.pos= [8*rand.uniform01 ,8*rand.uniform01].


③实用进阶数学运算

有math.前缀不能省略!正弦和余弦虽然去掉math.也有效,但加上math.可以略微减轻卡顿。

math.sin (x) 正弦

math.cos (x) 余弦

math.tan (x) 正切

math.toInt (x) 取整(去尾法)


④更多数学运算(淘汰赛中很少用,想整花活的可以看一看)

math.sum (  ) 求和(括号里必须是一个数组)

math.sqrt (x) 开方

math.vec.len ([a,b]) 求一个二项数组对应的坐标点到[0,0]的长度,类似勾股定理,比如math.vec.len([3,4])等于5

math.log10 (x) 以10为底的对数

math.asin (x) 反正弦

math.acos (x) 反余弦

math.atan (x) 反正切

math.toFloat (x) 转换成浮点值(即有小数形式)

math.toString (x) 转换成纯文本

math.comp.eq(a,b) 比较两个值是否相同,如果相同,输出true;如果不同,输出false

其他比较函数同理:

math.comp.g(a,b) a是否大于b

math.comp.ge(a,b) a是否大于等于b

math.comp.l(a,b) a是否小于b

math.comp.le(a,b)a是否小于等于b

math.comp.ne(a,b)a是否不等于b

还有些函数我都没怎么用过,就不列出来了。


五、闪队代码,以及利用sim.time、system.time或sim.tick实现动态函数

sim.time和system.time都是自带的计时代码。

sim.time:表示这个场景启动后累计运行的秒数,初始为0,当你按下空格开始运行的时候,sim.time就持续计时;暂停运行时,sim.time也暂停增加.

system.time:类似于sim.time,但它是打开algodoo的时候就开始计时了,你暂停模拟的时候它照样在持续计时。

sim.tick:跟sim.time原理一样,只不过sim.tick始终是sim.time的60倍。

所有在持续变化的数值,都可以利用这三个动态数字实现。

个人习惯用sim.time,后面都用sim.time做例子,有时候用sim.tick。

你应该知道基础的函数吧,比如y=2x这种。



把x换成sim.time,y换成你想要动态变化的值,再把这段代码放在poststep或update里,就形成了动态函数。

比如在poststep里写:

(e)=>{density = 2 * sim.time}

这个东西的密度就按照y=2x函数的图像变化(从x=0开始),也就是运行1秒的时候密度是2,运行2秒的时候密度是4,运行114.514秒的时候密度是229.028.


这样一来,闪队颜色代码就可以实现了。

首先搞清楚这个颜色是怎么闪的。

比如黑白闪就是黑-暗影-灰-银-白-银-灰-暗影-黑-……无色循环往复变化,用colorHSVA表示的话,就是H等于0不变,S等于0不变,V在0和1之间循环往复,A等于1不变。

彩虹则是红-橙-黄-黄绿-酸橙-……色相0-360循环变化,用colorHSVA表示的话,就是H从0逐渐增加到360,然后又变回0再逐渐增加到360,如此循环,SVA都是1不变。

那么再找到按照这个规律变化的函数,于是我们找到,在0和1之间循环往复的正弦函数y=sin(x)/2 + 0.5,以及符合彩虹变化规律的取余函数y = x mod 360.

这样,把x换成sim.time,y换成algodoo里面对应的属性,然后个别数学符号换成algodoo的书写形式,就得到闪队代码了。

黑白闪:

colorHSVA = [0, 0, math.sin(sim.time ) / 2 + 0.5, 1]

彩虹:

colorHSVA = [sim.time % 360, 1, 1, 1]

写好之后测试一下,感觉闪得太快了或太慢了?给sim.time做个乘法或除法就行。

比如:

黑白闪colorHSVA = [0, 0, math.sin(sim.time * 6 ) / 2 + 0.5, 1]

彩虹colorHSVA = [270*sim.time % 360, 1, 1, 1]

至于乘多少或除以多少,自己看情况调整频率即可。

下面列出我自己使用的一些闪队代码,都可以写在poststep里或者update里。始终记住(e)=>{}的格式必须要有!

彩虹: colorHSVA = [270 * sim.time % 360, 1, 1, 1]

暗彩虹:colorHSVA = [270 * sim.time % 360, 1, 0.5, 1]

浅彩虹: colorHSVA = [270 * sim.time % 360, 0.5, 1, 1]

黑白闪: colorHSVA = [0, 0, math.sin(sim.time * 6) / 2 + 0.5, 1]

彩虹闪:colorHSVA = [270 * sim.time % 360, math.sin(sim.time * 6) * 0.5 + 0.5, math.cos(sim.time * 6) * 0.5 + 0.5, 1]

红黑闪:colorHSVA = [0, 1, math.sin(sim.time * 6) / 2 + 0.5, 1](其他黑闪,把色相的0改成对应数字就行)

青白闪: colorHSVA = [180, math.sin(sim.time * 6) / 2 + 0.5, 1, 1](其他白闪,把色相的180改成对应数字就行)

灰暗闪:colorHSVA = [0, 0, math.sin(sim.time * 8) / 5 + 0.4, 1]

随机色:

sim.tick % 24 == 0 ? {

        sim.tick % 96 == 0 ? {

            colorHSVA = [360 * rand.uniform01, 1, 1, 1]

        } : {

            colorHSVA = [360 * rand.uniform01, 0.7 * rand.uniform01 + 0.3, 0.7 * rand.uniform01 + 0.3, 1]

        }

} : {}

渐变红:

math.sin(sim.time * 3) / 2 >= 0 ? {

        colorHSVA = [0, 1, 1 - math.sin(sim.time * 3) / 2, 1]

    } : {

        colorHSVA = [0, 1 + math.sin(sim.time * 3) / 2, 1, 1]

}

(其他渐变单色,自己改色相就行)

更多闪色,知道它闪的规律,找到对应的函数就行了。


其他有规律变化的东西,都可以利用sim.time,system.time,sim.tick加上函数表达式来实现,发散思维,别被定式限制了。

自制小球淘汰赛教程(二)传送门、闪队小球以及它们背后的原理的评论 (共 条)

分享到微博请遵守国家法律