骑马与砍杀中文站论坛

 找回密码
 注册(Register!)

QQ登录

只需一步,快速开始

搜索
购买CDKEY 小黑盒加速器
查看: 1620|回复: 6

[功能与代码] 场景物模拟技能--混沌陨石(代码)

[复制链接]

212

主题

1033

回帖

1049

积分

子爵[版主]

Rank: 7Rank: 7Rank: 7

UID
2893127
第纳尔
14847
精华
0
互助
93
荣誉
21
贡献
325
魅力
1382
注册时间
2017-11-5
鲜花(431) 鸡蛋(0)
发表于 2023-1-4 17:52:50 | 显示全部楼层 |阅读模式
本帖最后由 vegetto 于 2023-1-4 18:00 编辑

前言:场景物作为具备3d空间运动控制,贴图大小动画等控制,具备其他所有系统近似等效的“主动和被动”功能,十分灵活,但是对整体综合性的运动等事件进程控制具有一定综合知识基础要求。所以说,把握利用好场景物,骑砍便是万能游戏引擎制作器(把握presention界面一定意义上也是),所以针对场景物的一些方方面面的控制,分享一些实例。

本贴分享一下dota的召唤师卡尔的技能之一,混沌陨石的制作。当然此功能简单点可以直接add missle,然而用场景物的好处是,运动轨迹控制更自由,体现陨石滚动,体现陨石碰撞对周围人物的实感挤压和对其他障碍物的判定更灵活(比如陨石被建筑阻碍的位置更可控,撞到是立即破坏还是暂留一段时间作为障碍是可控的),对整个运动过程提供伤害效果。


接下来是代码实例讲解:从我的魔兽争霸mod里https://bbs.mountblade.com.cn/thread-2094063-1-1.html节选,相关特效模型查看我的dotaeft.brf,但不许提取:
module_scene_props.PY添加如下一行
("chaostone", sokf_moveable, "chaostone", "chaostone", []),

以下添加到module_mission_templates.PY需要的场景里,比如lead charge 野战,或者直接全部脚本化后每个场景触发器都引用一遍:
条件推荐0.00000,0.00000,0.00000,

(set_fixed_point_multiplier, 1000),
(get_player_agent_no, ":var_0"),              
(agent_get_position, pos32, ":var_0"),
(scene_prop_get_num_instances, ":var_1", "spr_chaostone"),
(try_begin),                                        #代码块1-表示陨石场景物chaostone数量为0时刷一个出来备用
    (eq, ":var_1", 0),
    (copy_position, pos33, pos32),
    (position_move_z, pos33, -10000),
    (set_spawn_position, pos33),
    (spawn_scene_prop, "spr_chaostone"),
    (prop_instance_deform_in_cycle_loop, reg0, 0, 2540, 5000),           #陨石场景物自带滚动的顶点动画,动画帧数区间从0播放到2540(brf右侧的数据,此处为帧时刻,而不是左侧的关键帧序号,因为相连关键帧之间可以间隔不同的帧时间,但一般为了控制方便,宜设置间隔连续均匀)
    (scene_prop_set_slot, reg0, 200, -8),       #给这个场景物定性,比如propslot200 为-8代表特效物品,在其他触发器需要try for prop时方便集中控制
(try_end),                                          #代码块1-结束
(eq, ":var_1", 1),
(try_begin),
    (scene_prop_get_instance, ":var_19", "spr_chaostone", 0),
    (agent_get_slot, ":var_6", ":var_0", 318),                           #  玩家的agent-slot318号为陨石降落到消失这一事件过程的时间进程控制
    (copy_position, pos33, pos32),
    (position_move_y, pos33, 500),
    (position_move_z, pos33, 500),
    (position_set_z_to_ground_level, pos33),                     #为了下面控制运动的时候以地面为基准,避免降落时遁地,之所以要yz偏移500是因为陨石设置了碰撞体,如果在其碰撞体平面范围上找一点的地面投影点,投影会不断上移到碰撞体最高处认定为名义地面,然后导致陨石反而不断上升运动。
    (prop_instance_get_position, pos35, ":var_19"),
    (copy_position, pos36, pos35),
    (position_move_z, pos36, -100),                 
    (position_get_distance_to_ground_level, ":var_17", pos36),           #获取陨石下方100cm处的地面高度,下面运动判断时作为是否靠近地面则停止下降位移量转为前水平滚动位移的条件,为什么要下降100cm,也是为了不受到陨石碰撞体本身被认定为地面的影响以及考虑运动有延迟。
    (try_begin),
        (eq, ":var_6", 0),
        (scene_prop_set_visibility, ":var_19", 0),
        (position_move_z, pos33, -10000),
        (prop_instance_set_position, ":var_19", pos33),                #以上表示agentslot318号为0时,陨石下沉到玩家地下10000cm处,并且影身。下降这么多目的是为了不使用陨石时藏着并且人不受到其碰撞体阻碍,visibility设影身是为了防止编辑模式被人偷看,可以不写。
    (else_try),
        (is_between, ":var_6", 1, 400),
        (scene_prop_set_visibility, ":var_19", 1),
        (store_add, ":var_7", ":var_6", 1),
        (agent_set_slot, ":var_0", 318, ":var_7"),                     #当表示agentslot318号大于等于1,则自动随时间+1,则其取值1-400控制了陨石运动的整体进程。
        (try_begin),
            (agent_slot_eq, ":var_0", 329, 0),                        #当表示agentslot329是一个0-30循环的量,其代码此处不写,反正是用来控制伤害持续触发的基础间隔的,避免集中高频持续伤害。
            (try_for_agents, ":var_14"),                                #代码块2-表示基础伤害间隔触发一次对陨石周围1200范围的单位造成75点伤害
                (agent_is_alive, ":var_14"),
                (agent_is_human, ":var_14"),
                (agent_get_team, ":var_15", ":var_0"),
                (agent_get_team, ":var_16", ":var_14"),
                (neg|eq, ":var_15", ":var_16"),
                (prop_instance_get_position, pos37, ":var_19"),
                (agent_get_position, pos38, ":var_14"),
                (get_distance_between_positions, ":var_18", pos37, pos38),
                (neg|ge, ":var_18", 1200),
                (agent_deliver_damage_to_agent, ":var_0", ":var_14", 75),
            (try_end),                                                            #代码块2-结束
        (try_end),
        (try_begin),
            (is_between, ":var_6", 1, 10),
            (position_move_z, pos33, 3000),
            (prop_instance_set_position, ":var_19", pos33),        #以上表示当表示agentslot318号为1-10取值区间时,陨石从玩家头顶3000cm的高空凭空出现
        (else_try),
            (is_between, ":var_6", 10, 400), #代码块3-表示agentslot318号为10-400取值区间时,如果陨石的参考表面点距离地面的高度大于500,则给予一个越来越快的y位移量和恒定100的z下降位移量,当陨石的参考表面点距离地面的高度小于500,则直接按照紧贴地面运动并给予120的y方向前进位移量。
            (try_begin),
                (is_between, ":var_17", 500, 80000),
                (position_move_y, pos35, ":var_6"),
                (position_move_z, pos35, -100),
            (else_try),
                (position_set_z_to_ground_level, pos35),     
                (position_move_y, pos35, 120),
            (try_end),                                                    #代码块3-结束
            (prop_instance_animate_to_position, ":var_19", 35, 5),            #控制场景物向pos35匀速运动,因为pos35的位移改变是根据自身坐标向下一个瞬间做简单的xyz增量改变
            (try_begin),
                (position_move_z, pos36, 400),                                    
                (position_move_y, pos36, 1000),
                (cast_ray, ":var_20", 39, 36, 800),                           #cast ray是用来检测碰撞体防止陨石功能在有建筑物的场景里使用时穿墙的,pos36即由陨石中心向前预留1000cm的空间再检测碰撞,目的也是为了防止检测到自身陨石的碰撞以及为运动延迟留一点制动区间,
                (neg|eq, ":var_20", -1),                     
                (agent_set_slot, ":var_0", 318, 0),           
                (particle_system_burst, "psys_atk6", pos35, 1),   #以上表示:var_20便是上面检测到的碰撞体,-1则没有碰撞,我们需要假设有碰撞时及时终止陨石的运动,故判断其不等于-1时,强行让控制进程的slot318归0,并播放psys_atk6炸开的特效,当slot318归0后,根据上面的设定,陨石会影身并沉到地下
            (try_end),
        (try_end),
    (else_try),
        (ge, ":var_6", 400),                                                   
        (agent_set_slot, ":var_0", 318, 0),
        (particle_system_burst, "psys_atk6", pos35, 1),              #以上表示陨石如果超出slot318这个事件进程控制量的时间上限值,自动爆炸归0.陨石会影身并沉到地下
    (try_end),
(try_end),

然后我感觉很多人处理场景物运动时习惯用scene prop py里的触发器和mt组合控制,其实这样不利于思路的顺畅,以及在处理多段式运动时两个文件来回跳跃会比较乱。而且场景物运动本身对于骑砍来说是耗性能的东西,比如几百个一起采用animate的方式运动,最后一个参数填的时间越大,屏幕甚至会颤抖。所以控制运动特别是多个物体组合运动的时候,建议直接一个mt一气呵成。
然后场景物运动控制对op比较高频的使用就是set position ,animate to pos,而对于场景物运动自由但碰撞自己要另写不然可以穿墙的特性,又需要熟练使用op里的cast_ray判断场景物碰撞体障碍以及position_get_distance_to_ground_level,position_set_z_to_ground_level判断地面地形障碍碰撞(有时也可以简单判断场景物碰撞,因为ground_level地面基础面是考虑场景物碰撞面的)。

评分

参与人数 2第纳尔 +40 互助 +2 魅力 +25 收起 理由
幼稚园殺手 + 20 + 1 + 5 原创内容,值得鼓励!
Aomine Daiki + 20 + 1 + 20 文章不错,继续努力!

查看全部评分

26

主题

804

回帖

399

积分

骑士

民间工匠

Rank: 4Rank: 4

UID
1115705
第纳尔
4062
精华
0
互助
26
荣誉
2
贡献
0
魅力
30
注册时间
2012-12-13
鲜花(235) 鸡蛋(10)
发表于 2023-1-5 13:01:28 | 显示全部楼层
其实除了用cast_ray和ground_level,还可以用用prop_instance_intersects_with_prop_instance,不过这个操作需要检测的场景道具使用的碰撞是胶囊,而且需要检测频率比高

31

主题

210

回帖

187

积分

见习骑士

Rank: 3

UID
2462463
第纳尔
1587
精华
0
互助
23
荣誉
0
贡献
0
魅力
83
注册时间
2015-3-3
鲜花(58) 鸡蛋(0)
发表于 2023-3-1 16:23:42 | 显示全部楼层
本帖最后由 战争傀儡阿格兰 于 2023-3-1 16:27 编辑

请教下,cast_ray 似乎是没有模型的吗


cast_ray                               = 1900   # (cast_ray, <destination>, <hit_position_register>, <ray_position_register>, [<ray_length_fixed_point>]), #Casts a ray of length [<ray_length_fixed_point>] starting from <ray_position_register> and stores the closest hit position into <hit_position_register> (fails if no hits). If the body hit is a prop instance, its id will be stored into <destination>

212

主题

1033

回帖

1049

积分

子爵[版主]

Rank: 7Rank: 7Rank: 7

UID
2893127
第纳尔
14847
精华
0
互助
93
荣誉
21
贡献
325
魅力
1382
注册时间
2017-11-5
鲜花(431) 鸡蛋(0)
 楼主| 发表于 2023-3-1 16:31:11 | 显示全部楼层
本帖最后由 vegetto 于 2023-3-1 16:41 编辑
战争傀儡阿格兰 发表于 2023-3-1 16:23
请教下,cast_ray 似乎是没有模型的吗

重新组织语言,什么叫没有模型,判断碰撞,和模型外在样子无关,和模型的碰撞有关。碰撞可以是两个对象形体的判断也可以是一个对象形体的,可以是一个参考点对一个不规则面的碰撞判断,所以可以是有限数量坐标对坐标范围的判断。举例:对于一个尺寸对比另一个障碍物尺寸小很多的物体,考虑的更多是一个点的碰撞,比如一个炮弹打城墙,只需要考虑物体运动方向的最前沿一点不要穿入障碍物继续运动,根据碰撞阻止和调整运动。而对于两个尺寸差不多的物体,比如两辆车进行碰碰车摩擦运动,则需要考虑形体的尺寸,整个模型的外形各个方向点对模型坐标原点有不可忽略的尺度,要保证两个车各方向的尺度不要有大范围重合

31

主题

210

回帖

187

积分

见习骑士

Rank: 3

UID
2462463
第纳尔
1587
精华
0
互助
23
荣誉
0
贡献
0
魅力
83
注册时间
2015-3-3
鲜花(58) 鸡蛋(0)
发表于 2023-3-1 16:40:36 | 显示全部楼层
vegetto 发表于 2023-3-1 16:31
重新组织语言,什么叫没有模型,判断碰撞,和模型外在样子无关,和模型的碰撞有关。碰撞可以是两个对象形 ...

就是这个代码,无法设定模型,用cast_ray  的时候,在游戏里是看不见这个ray的吗

212

主题

1033

回帖

1049

积分

子爵[版主]

Rank: 7Rank: 7Rank: 7

UID
2893127
第纳尔
14847
精华
0
互助
93
荣誉
21
贡献
325
魅力
1382
注册时间
2017-11-5
鲜花(431) 鸡蛋(0)
 楼主| 发表于 2023-3-1 16:42:19 | 显示全部楼层
本帖最后由 vegetto 于 2023-3-1 17:11 编辑
战争傀儡阿格兰 发表于 2023-3-1 16:40
就是这个代码,无法设定模型,用cast_ray  的时候,在游戏里是看不见这个ray的吗

理解为红外线测距,红外线测距你也看不到红外线,就是从一个坐标发射,遇到障碍物反馈信息的一种手段。这种偏向get型操作,用于获取参数和判断值用于判断碰撞和获取碰撞物相关信息,而不是set型操作来让你设置哪个物体是不是障碍类场景物的,要和add missle区分开来不要混淆。但是可以结合addmissle去理解,相当于addmissle是发射有实际的物体但是侧重在产生发射的事件结果,castray是发射抽象看不见的“红外线”侧重在获取发射点发射方向上的场景物类碰撞对象和其点位,而由于有ti on missle hit这个trigger也可以获取击中障碍物的类别和位置的特性,所以。
“add missle + ti on missle hit获取trigger param 参数”可以等效作用于“cast ray”,而cast ray是1.161之后的操作,add missle在1.153之前就有了,骑砍ms经常会更新新操作=旧操作1+旧操作2等效的情况,所以这些都是灵活变通的方法多样的,在cast ray 没出现前判断碰撞的同样还有prop_instance_intersects_with_prop_instance  但是这种要特殊碰撞其实主要是来做船与船这种两个对象都不能忽视外在尺寸且外形不算特别凹凸不规则的。然后还有含in sight类操作判断坐标是否在视线内,然后特别对玩家视线和屏幕范围差不多就可以等效3d换算2d坐标是否在(0,0)-(1000,750)的屏幕坐标内,然后castray和intersects无法判断地形产生的碰撞又需要含ground level系列操作判断地面高度获得地形碰撞范围,然后这些对人体hitbox类别的碰撞判断不足,又要对骨骼坐标获取为中心构造一个圆柱体的区域坐标点集作为假想碰撞。
但是重点就是告诉你,cast ray这个操作是为了get获取,而不是set设定。

而且代码里不要说模型,游戏触发类代码里模型最终到落实到一个对象的种类和个例来控制和获取



31

主题

210

回帖

187

积分

见习骑士

Rank: 3

UID
2462463
第纳尔
1587
精华
0
互助
23
荣誉
0
贡献
0
魅力
83
注册时间
2015-3-3
鲜花(58) 鸡蛋(0)
发表于 2023-3-17 14:44:24 | 显示全部楼层
a1550887802 发表于 2023-1-5 13:01
其实除了用cast_ray和ground_level,还可以用用prop_instance_intersects_with_prop_instance,不过这个操 ...

求解prop_instance_intersects_with_prop_instance的用法,我看他不返回值啊,是想eq、lt一样的判断句吗?
您需要登录后才可以回帖 登录 | 注册(Register!)

本版积分规则

Archiver|手机版|小黑屋|骑马与砍杀中文站

GMT+8, 2024-12-27 12:47 , Processed in 0.120474 second(s), 26 queries , Gzip On, MemCached On.

Powered by Discuz! X3.4 Licensed

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表