本帖最后由 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地面基础面是考虑场景物碰撞面的)。
|