角色快速入门
概述
本文档将介绍动画树和状态机的创建,状态机状态的过渡,输入的绑定,最后编写脚本在关卡中可以控制角色行动。
创建项目
新建一个空项目,详见项目。
导入美术资源
导入骨架网格体和动画。详见资源工作流程。
Actor组装
详见Actor组装。
添加状态机
在动画编辑器中新建一个动画树tp_tree。
在动画树中添加一个状态机节点,并连接到最终动画姿势。
双击该状态机节点,进入状态机编辑界面,添加idle和run两个状态节点并连接这两个状态,使这两个状态间可形成一个循环。
双击idle状态节点,在该状态中添加站立动作。添加一个序列播放节点,并连接到最终动画姿势。
同样的,在run状态中添加跑步动作。
增加一个浮点类型的Speed参数。
设置idle→run这个状态迁移的条件为:Speed大于0.1。
设置run→idle这个状态迁移的条件为:Speed小于0.1。
保存。
输入设定编辑
在组件编辑器中依次点击菜单栏配置(Config) -> 项目设置(Project Settings)打开项目设置窗口。
在输入设置(Input Settings)的AxisMappingList中,增加类似下图中的7个按键。
设置角色
创建角色
在新关卡中,依次点击工具栏创建游戏对象(Create Game Object) -> 角色(Character)来创建一个玩家角色。
属性设置
修改CharacterMesh0(Inherited)组件的骨骼网格配置文件(Skeletal Mesh Config File)属性为之前创建的.actor文件。
继续修改默认行为覆盖(Default Action Override)属性为之前创建的tp_tree。
在大纲(Hierarchy)面板中选中CollisionCylinder(Inherited)后调整胶囊体的位置,选中CharacterMesh0(Inherited)后调整角色网格体的位置,使胶囊体尽可能在包裹角色的前提下,让角色蒙皮的脚部贴地。
在CollisionCylinder(Inherited)组件下添加一个摄像机摇臂组件(Spring Arm Component)。
在摄像机摇臂组件下添加一个摄像机组件(Camera Component)。
调整摄像机组件至合适位置。
选择角色对象,将其自动持有玩家(Auto Possess Player)属性设置为Player0,这个时候PIE会自动使用角色身上的摄像机。
设置角色对象的使用控制器偏航角(Use Controller Angle Yaw)属性为false。
设置摄像机摇臂组件的使用Pawn操控旋转(Use Pawn Control Rotation)属性为true,做碰撞测试(Do Collision Test)属性为false和启用摄像机延迟(Enable Camera Lag)属性为true。
设置CharMoveComp(Inherited)的为运动确定旋转方向(Orient Rotation To Movement)属性为true。
编写角色控制脚本
在项目的script文件夹中,增加一个controller.lua文件,编写如下脚本代码。
--动画资源类型
AT_UNKNOWN = 0
AT_SKELETON = 1
AT_SKELETON_AS_ANIMSEQUENCE = 2
AT_ANIMSEQUENCE = 3
AT_MONTAGE = 4
AT_BLENDSPACE = 5
AT_BLENDSPACE1D = 6
AT_AIMOFFSETBLENDSPACE = 7
AT_ANIMTREE = 8
local IE_Pressed = 0 --按键按下
local IE_Released = 1 --按键抬起
local IE_Repeat = 2
local IE_DoubleClick = 3
local IE_Axis = 4
local IE_MAX = 5
local CAMERA_DISTANCE_CHANGE_SPEED = 0.5
local CAMERA_DISTANCE_MIN = -1
local CAMERA_DISTANCE_MAX = 50
--use this for initialization
function on_begin_play(component)
local owner = component.ActorOwner
if nx_is_valid(owner) then
local input_comp = owner.InputComponent
if nx_is_valid(input_comp) then
nx_bind_script(owner, nx_current())
--第一个参数对应输入设置中的Axis Name
--最后一个参数为自定义事件名
input_comp:AddAxisBinding("MoveForward", true, false, true, "InputAxisEvent_MoveForward")
input_comp:AddAxisBinding("MoveRight", true, false, true, "InputAxisEvent_MoveRight")
input_comp:AddAxisBinding("Turn", true, false, true, "InputAxisEvent_Turn")
input_comp:AddAxisBinding("LookUp", true, false, true, "InputAxisEvent_LookUp")
input_comp:AddAxisBinding("AdjustCameraDis", true, false, true, "InputAxisEvent_AdjustCameraDis")
--第二个参数为AddAxisBinding中的最后一个参数,最后一个参数表示脚本中的函数名
nx_callback(owner, "InputAxisEvent_MoveForward", "on_moveforward")
nx_callback(owner, "InputAxisEvent_MoveRight", "on_moveright")
nx_callback(owner, "InputAxisEvent_Turn", "on_turn")
nx_callback(owner, "InputAxisEvent_LookUp", "on_lookup")
nx_callback(owner, "InputAxisEvent_AdjustCameraDis", "on_adjust_camera_dis")
nx_callback(owner, "on_velocity_changed", "on_velocity_changed")
end
end
nx_callback(component, "on_tick", "tick")
end
--use this for release
function on_end_play(component)
end
--获取actor
function character_get_actor(character)
if nx_is_valid(character) then
local mesh_component = character.MeshComponent
if nx_is_valid(mesh_component) then
local vis_base = mesh_component.VisBase
if nx_is_valid(vis_base) and nx_is_kind(vis_base, "Actor") then
return vis_base
end
end
end
return nx_null()
end
--获取spring_arm
function character_get_spring_arm(character)
if nx_is_valid(character) then
local spring_arm_component = character:FindComponentByClassName("LSpringArmComponent")
return spring_arm_component
end
return nx_null()
end
--向前移动回调
function on_moveforward(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end
--获得控制器Y轴角度
local controller = owner.Controller
if nx_is_valid(controller) then
local yaw = controller.AngleY
--获得向前方向
local x, y, z = nx_function("ext_angle_get_forward_vector", 0.0, yaw, 0.0)
--增加移动量
owner:AddMovementInput(x, y, z, axis_value)
end
return 1
end
--向右移动回调
function on_moveright(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end
--获得控制器Y轴角度
local controller = owner.Controller
if nx_is_valid(controller) then
local yaw = controller.AngleY
--获得向右方向
local x, y, z = nx_function("ext_angle_get_right_vector", 0.0, yaw, 0.0)
--增加移动量
owner:AddMovementInput(x, y, z, axis_value)
end
return 1
end
--左右旋转(绕Y轴旋转)回调
function on_turn(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end
owner:AddControllerYawInput(axis_value)
return 1
end
--上下旋转(绕X轴旋转)回调
function on_lookup(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end
owner:AddControllerPitchInput(-axis_value)
return 1
end
--鼠标滚轮回调
function on_adjust_camera_dis(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end
local spring_arm_component = character_get_spring_arm(owner)
if nx_is_valid(spring_arm_component) then
local delta = axis_value * CAMERA_DISTANCE_CHANGE_SPEED
local cur_value = spring_arm_component.TargetArmLength
local new_value = cur_value + delta
if delta > 0 then
if new_value > CAMERA_DISTANCE_MAX then
new_value = CAMERA_DISTANCE_MAX
end
spring_arm_component.TargetArmLength = new_value
else
if new_value < CAMERA_DISTANCE_MIN then
new_value = CAMERA_DISTANCE_MIN
end
spring_arm_component.TargetArmLength = new_value
end
end
return 1
end
--速度变化回调
function on_velocity_changed(owner, component_id, new_x, new_y, new_z, old_x, old_y, old_z)
local actor = character_get_actor(owner)
if nx_is_valid(actor) then
if actor:GetBlendActionCount() > 0 then
local action_name = actor:GetBlendActionName(0)
local action_type = actor:GetActionType(action_name)
local action_index = actor:GetActionIndex(action_name)
if action_type == AT_ANIMTREE then
local speed = math.sqrt(new_x * new_x + new_y * new_y + new_z * new_z)
actor:SetAnimTreeValue(action_index, "Speed", speed)
nx_set_custom(actor,"CurSpeed",speed);
end
end
end
return 1
end
绑定角色控制脚本
在角色对象中添加一个脚本组件(Script Component)。
将脚本组件的脚本文件(Script File)属性设置为之前所写的controller.lua。
保存。
运行
运行后可查看效果。