Skip to main content

Melee Component Manual

Overview

The Melee Collision Component provides the collision detection feature on the motion trajectory of the character's weapon when playing the character's attack action.

Melee Collision Components

Adding Melee Collision Components

Select an object in the Hierarchy panel, then in the Inspector panel, click Add Component and select Melee Collision Component to add one.

image-20230728173924469

image-20230728174017144

After adding:

image-20230728174235157

Properties

In the Inspector panel, select LMeleeCollision and the relevant properties of this component will be displayed below.

image-20230803103336466

Debug

Debug is used to turn on or turn off the collision detection debugging information, which includes the weapon collider's motion trajectory, impact points, etc.

image-20230803093940189

PropertyDescription
Direction Of WeaponsUsed to display the direction of Weapons. Generally, the direction of a weapon is taken from one of the axis vectors of the weapon model's coordinate system. The weapon's axis vector can be switched in the Main Axis property in Weapons -> Advance, with Detailed Collision enabled.
image-20230803104033410
Collision ResultWhen enabled, the position at which the collision is generated during the collision detection process is displayed as a blue geometry.
Collision TrajectoryCan be enabled only when Collision Result is enabled. When enabled, the motion trajectory of the weapon during the Melee weapon collision detection process will be displayed in the scene as a gray geometry.
Exist TimeUsed to set the display time of the Collision Result geometry and the Collision Trajectory geometry.
Ignore Raycast ResultWhen enabled, only the impact point will be left when the raycast illuminates on an object in the scene, and a red ball will be drawn at the impact point.
Ignore Overlap ResultWhen enabled, the motion trajectory of the collider is no longer displayed in the scene.
Ignore Sweep ResultWhen enabled, the green line, the start and end position of the sweep detection are no longer drawn when objects collide in the scene.
Ignore Detailed Collision DataEnable/disable accurate collision detection. If disabled, the specific impact point of the collision detection will be calculated when accurate detection is performed. If enabled, it will only determine if any object is hit, and will not record the specific position where collisions occur.

Damage Event

Damage Event is used to calculate damage in game logic, including damage and impact.

image-20230803104214117

PropertyDescription
Generate Damage EventWhen enabled, the game logic can get the detailed damage information.
Damage DegreeThe amount of damage caused.
MomentumThe amount of impact force caused.

Ignore Game Object

Add or delete the game object that needs to be ignored.

image-20230731113421995

PropertyDescription
Ignore Game ObjectSelect the Game Object (the Game Object in the current Level) to be ignored , and this Game Object does not perform collision detection in the game.

Buttons

ButtonDescription
image-20230808112856338Add a new Ignore Game Object.
image-20230808112922018Delete the current Ignore Game Object.
image-20230808112952173Delete all Ignore Game Objects.
image-20230808113013310Copy the current Ignore Game Object.

Weapons

Add weapons. Select the colliders to be involved in the detection and the collision detection trigger method.

image-20230803104339756

PropertyDescription
Collider ComponentThe component that needs to be involved in the Melee weapon collision detection. Select the collider in this component to act as a weapon to perform collision detection.
Bone NameThe bone selected in the Collider Component that acts as a weapon.
Collider IndexSelect the collider to be involved in the Melee weapon collision detection under the current bone.
Interpolation NumberSelect the interpolation number. Interpolation Number: In the process of animation playback, there may be the case that the collider's displacement between frames is too large. In this case, an appropriate Interpolation Number needs to be selected to fill the collider's displacement between frames (If the weapon collider is too small or the speed of the attack action is too fast, the Interpolation Number needs to be increased, otherwise there is a probability of missing detection).
Weapon GroupNotify all Weapons in the corresponding group to turn on collision detection when the event is triggered.
ValidWhether the weapon is effective. Check it to take effect and uncheck it to not take effect.
Trigger ModeSelect the trigger mode.
  • None: The Melee weapon collision detection will not be triggered.
  • Movement: When displacement occurs, collision detection for Weapons will be enabled.
  • Collision Detection Notify: Enable collision detection for weapons via collision detection notify.
Detailed CollisionEnable the raycast collision to record impact points where collisions with weapons and raycasts occur.
Main AxisAdjust the raycast direction.

Script

Add the Script File.

image-20230802105656888

PropertyDescription
Script FileScript File name. Select the script file to bind to.
Specified Skeletal MeshAfter selecting any LSkeletalMeshComponent component in the current object, the current Melee component will perform collision detection according to the animation playback of the selected LSkeletalMeshComponent.

Quick Start

The following is an example of using Melee.

Creating Actors

Refer to Assembling Actors to create an Actor containing animations assets SK_Avatar_tpose, Avatar_Attack and Avatar_Walk.

image-20230803130832240

Adding Collision Detection Events to Animations

Click one of the animation assets in the Actor Editor to open the Animation Editor.

image-20230803131246746

In Asset Browser of the Animation Editor, select Avatar_Attack, right-click it to open the shortcut menu, then select Convert Skeleton To AnimSeq, enter the name in the pop-up window and click the OK button to complete the conversion. This animation sequence asset will be used to add the collision detection event.

image-20230803162035661

Double-click the converted animation sequence asset, right-click the Notify track and click Add Notify -> Collision Detection Notify to add a Collision Detection Notify.

image-20230803162406565

After adding:

image-20230803162622335

Select appropriate frames of the Notify as its start and end based on the model's action position in the Viewport. Refer to Adjusting State Notifies to adjust the Notify.

AdjustNotify

Right-click the created Collision Detection Notify and set Trigger Weight in the pop-up Notify window. It determines whether to trigger the Notify when blending animations, and the Notify will be triggered only when the current animation blending degree exceeds the set value. When Trigger Weight is set to 0, the Melee weapon collision detection will be performed during the Notify triggering period, even if the character is not playing an attack action.

image-20230803170803991

Select the Collision Detection Notify, then in the Details Panel, click the image-20230803171035899button to add a Weapon Group and set it to be notified. If no specific Weapon Group is set, then all Weapons in the Melee Collision Component will be notified.

image-20230803172027163

After setting, click File (in the Menu bar) -> Save All.

image-20230803172437958

Configuring Animation Trees

Create an Animation Tree, then create a State Machine node as well as the Animation Parameter to be used, and set the state transition conditions. The state graph is shown below:

image-20230803174942335

Note: For details of this step, please refer to Character Quick Start -> Adding State Machine Nodes.

The Animation Tree associated with the idle state:

image-20230803175306538

The Animation Tree associated with the walk state:

image-20230803175332423

In the Slot Manager, create a slot named MeleeSlot.

image-20230807152559370

Add a Slot "MeleeSlot" node to the Animation Tree and connect the nodes together as shown below.

image-20230807152533177

For how to create slots and add Slot nodes, please refer to Animation Trees -> Slot Nodes.

After editing, click the Save button.

image-20230804095121517

Configuring Actors

In the Actor Editor, click Asset Details, then set Default Action to the created Animation Tree, and click the Save button after setting.

image-20230804143438206

Creating Ragdolls

Refer to Ragdoll Editor to create a Ragdoll resource for SK_Melee_Demo.actor, and add a Rigidbody to the bone hand_r.

image-20230804142127414

Creating Characters

Create a Level and click Create Game Object -> Character to create a Character object.

image-20230803110206293

In the Inspector panel, select CharacterMesh0(Inherited), and drag the .actor to be used from the Project panel into Skeletal Mesh Config File.

image-20230803111008766

After dragging:

image-20230803111541395

In the Inspector panel, select ColliderCylinder(Inherited) and CharacterMesh0(Inherited), then adjust the position of the Character's capsule and mesh respectively, so that the capsule wraps around the Character as much as possible and the feet of the Character's skin are on the ground. The capsule also needs to be above the ground.

image-20230803112017415

Add a Spring Arm Component and a Camera Component to the Character and adjust the position and angle of the camera component to the appropriate values.

image-20230804100523797

Select LCharacter(Instance) in the Inspector panel and set Auto Possess Player to Player 0.

image-20230804164000348

Adding Melee Collision Components

Select the created Character object in the Hierarchy panel, and add a Melee Collision Component to the object (Refer to Adding Melee Collision Components).

image-20230803105156125

Set the properties of the Melee Collision Component in the lower part of the Inspector panel.

Configure the damage in Damage Event and decide whether to enable Generate Damage Event as needed. If Damage Event is enabled, then configure the appropriate Damage Degree and Momentum.

image-20230807152949332

Game Objects to be ignored can be added in Ignore Game Object.

image-20230807140425681

Click the image-20230804145028480button in the Weapons title bar to add a weapon entry, then set Collider Component to CharacterMesh0, Bone Name to hand_r, and Trigger Mode to Collision Detection Notify , and check Detailed Collision. The detailed configuration is shown below:

image-20230807140615512

After configuring each property, check Direction Of Weapons, Collision Result and Collision Trajectory in Debug, and set Exist Time to 0.5.

image-20230807153105706

Creating Walls

Drag a model from the Project panel into the Level as a wall, and adjust its Position and Scale to the appropriate values.

image-20230804160006504

Binding Scripts

Select the created Character object in the Hierarchy panel, then in the Inspector panel, click the Add Component button and select Script Component to add one.

image-20230804162317962

image-20230808113354042

Right-click a blank space in the Resource Preview window to open the Shortcut Menu and select Script File to create one.

image-20230804162638906

Drag the created Script File into the Script File of the Script Component (LScript).

image-20230804163135315

After dragging:

image-20230807153319360

Script Files

The following is the reference script melee_character_demo.lua.

Refer to the on_setup_input_component() function in the following script to bind a callback to the Character.

Refer to the on_leftclick_pressed() function in the following script to blend the Attack animation in the callback function.

--script template

require("public_attr")

local IE_Pressed = 0 --Key pressed
local IE_Released = 1 --Key released
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

---------------------
--default callbacks--
---------------------

--use this for initialization
function on_begin_play(component)
local owner = component.GameObjectOwner

if nx_is_valid(owner) then
nx_bind_script(owner, nx_current())

nx_callback(owner, "on_setup_input_component", "on_setup_input_component")
nx_callback(owner, "on_velocity_changed", "on_velocity_changed")

local input_comp = owner.InputComponent

if nx_is_valid(input_comp) then
on_setup_input_component(owner, input_comp)
end
end

nx_callback(component, "on_tick", "tick")
end

--use this for release
function on_end_play(component)
end

--setup input component
function on_setup_input_component(pawn, input_comp)
if nx_find_custom(input_comp, "binded") and input_comp.binded then
return
end

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")

input_comp:AddCombinationBinding("LeftClick", IE_Pressed, true, false, true, "InputActionEvent_LeftClick_Pressed")


nx_callback(pawn, "InputAxisEvent_MoveForward", "on_moveforward")
nx_callback(pawn, "InputAxisEvent_MoveRight", "on_moveright")
nx_callback(pawn, "InputAxisEvent_Turn", "on_turn")
nx_callback(pawn, "InputAxisEvent_LookUp", "on_lookup")
nx_callback(pawn, "InputAxisEvent_AdjustCameraDis", "on_adjust_camera_dis")

nx_callback(pawn, "InputActionEvent_LeftClick_Pressed", "on_leftclick_pressed")

input_comp.binded = true

end

--Get the 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

--Get the 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

--Moving forward callback
function on_moveforward(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end

--Get the controller Angel Y
local controller = owner.Controller

if nx_is_valid(controller) then
local yaw = controller.AngleY
--Get the forward vector
local x, y, z = nx_function("ext_angle_get_forward_vector", 0.0, yaw, 0.0)

--Add movement input

owner:AddMovementInput(x, y, z, axis_value)
end

return 1
end

--Move right callback
function on_moveright(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end

--Get the controller Angel Y
local controller = owner.Controller

if nx_is_valid(controller) then
local yaw = controller.AngleY
--Get the right vector
local x, y, z = nx_function("ext_angle_get_right_vector", 0.0, yaw, 0.0)

--Add movement input
owner:AddMovementInput(x, y, z, axis_value)
end
return 1
end

--Left and right rotation (rotate around the Y-axis) callback
function on_turn(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end

owner:AddControllerYawInput(axis_value)

return 1
end

--Up and down rotation (rotate around the X-axis) callback
function on_lookup(owner, axis_value)
if not nx_is_valid(owner) then
return 0
end

owner:AddControllerPitchInput(-axis_value)

return 1
end

--Mouse wheel callback
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_leftclick_pressed(owner)
local actor = character_get_actor(owner)
if not nx_is_valid(actor) then
return
end

actor:BlendAction("Attack", false, false, true, 1.0, false, "MeleeSlot", true)
end

--Velocity change callback
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


function set_tree_state(actor, state_name, enable)
if not nx_is_valid(actor) then
return
end

-- Set state machine variables
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
actor:SetAnimTreeValue(action_index, state_name, enable)
end
end
end

-- Toggle ragdoll
function toggle_ragdoll(owner, key_name)
local actor = character_get_actor(owner)
if not nx_is_valid(actor) then
return
end

nx_set_value("default_actor", actor)

local mesh_component = owner.MeshComponent
if not nx_is_valid(mesh_component) then
return
end

-- Record mesh_component
actor.mesh_component = mesh_component

local enable_ragdoll = not mesh_component.SimulatePhysics

if (enable_ragdoll) then
mesh_component.SimulatePhysics = enable_ragdoll
set_tree_state(actor, "IsDead", true)
else
local capsule = owner.CapsuleComponent
if nx_is_valid(capsule) then
-- Record capsule
actor.capsule = capsule
end

-- Save Snapshot
actor:SavePoseSnapshot("finalpose")

mesh_component.SimulatePhysics = enable_ragdoll

-- Notify blended snapshot
set_tree_state(actor, "IsStopped", true)

-- Play the getup action
actor:BlendAction("GetUp_Back_montage", false, false, true, 1.0)

set_tree_state(actor, "IsDead", false)

-- Pause for 2 frames
nx_pause(0)
nx_pause(0)

-- Notify no more blended snapshot
set_tree_state(actor, "IsStopped", false)
end
end

function tick(component, delta_time)
update_capsule_location()
end

-- Update capsule location in ragdoll state
function update_capsule_location()
local actor = nx_value("default_actor")
if not nx_is_valid(actor) then
return
end

if not nx_find_custom(actor, "mesh_component") then
return
end

local mesh_component = actor.mesh_component
if not nx_is_valid(mesh_component) then
return
end

if mesh_component.SimulatePhysics then
if not nx_find_custom(actor, "capsule") then
return
end

local capsule = actor.capsule
if not nx_is_valid(capsule) then
return
end

local x, y, z = actor:GetNodeWorldPosition("pelvis")
capsule:SetPosition(x, capsule.PositionY, z)
end
end

public_attr.lua

--Resource Manager: Global Variables

MODEL_PATH = "mdl\\"
MODEL_PATH_DX9 = ""
ACTOR_PATH = "ini\\actor\\"
ACTOR_PATH_DX9 = "ini\\actor\\"
LIGHT_PATH = "ini\\light\\"
LIGHT_PATH_DX9 = "ini\\light\\"
EFFECT_PATH = "ini\\effect\\"
PARTICLE_PATH = "ini\\particle\\"
SOUND_PATH = "snd\\"
REVERB_PATH = "reverb\\"
TRIGGER_PATH = "ini\\trigger\\"
PROBE_PATH = "ini\\light_probe\\"
VOLUME_FOG_PATH = "ini\\volume_fog\\"
MATERIAL_PATH = ""

--Resource Type Definitions
TYPE_MODEL = "model"
TYPE_ACTOR = "actor"
TYPE_LIGHT = "light"
TYPE_EFFECT = "effect"
TYPE_PARTICLE = "particle"
TYPE_SOUND = "sound"
TYPE_REVERB = "reverb"
TYPE_TRIGGER = "trigger"
TYPE_PROBE = "light_probe"
TYPE_VOLUME_FOG = "volume_fog"
TYPE_DECAL = "decal"
TYPE_GROUP = "group"
TYPE_RIPPLE = "ripple"
TYPE_SNOW = "snow"
TYPE_RAIN = "rainlayer"
TYPE_UI3D = "ui3d"

--Animation Resource Types
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

TYPE_LIST = {
"model",
"actor",
"light",
"effect",
"particle",
"decal",
"sound",
"reverb",
"trigger",
"light_probe",
"volume_fog",
"ripple",
"snow",
"rainlayer",
}

FORM_TREE_BROWSER = "common_form\\form_tree_browser"
SEARCH_PATH = "ini\\common_form\\form_tree_browser\\"
SEARCH_CONFIG = SEARCH_PATH .. "form_put_visual.ini"
SEARCH_CONFIG_TEMP = "cache\\common_form\\form_tree_browser\\form_put_visual_temp.ini"
GROUP_CONFIG = "ter\\visual_group.ini"

--Get the visual_put file
function get_search_file()
local ini = nx_create("IniDocument")

ini.FileName = nx_resource_path() .. SEARCH_CONFIG

if not ini:LoadFromFile() then
nx_destroy(ini)
return 0
end

local file = ini:ReadString("SEARCH_CONFIG", "search_file", "form_put_visual.ini")

nx_destroy(ini)

return nx_resource_path() .. SEARCH_PATH .. file, file
end

Debugging

Click the PIE button. Move the character to the wall and left-click to make the character play the attack action with his right hand colliding with the wall.

image-20230807105359069

  • Collision Trajectory in Grey : The motion trajectory during the Melee weapon collision detection.
  • Collision Trajectory in Blue: There are collisions in the weapon motion trajectory rough detection.
  • Raycast Detection in Red: The impact points where raycasts collide with objects in the scene.
  • Sweep Detection in Green: When the weapon (hand_r's collider) collides with objects in the scene, the collider shape is drawn at the start point and end point and connected with a green line (Not displayed when the collider is a sphere).

When the collider is a box:

image-20230804174855077

When the collider is a sphere:

image-20230804171423711

When Weapons -> Trigger Mode -> Detailed Collision is enabled, the yellow line in the box below represents the orientation of the weapon's raycast axis vector.

image-20230807105144392

In each of the following debugs, the selected collider is a box.

Turning off Collision Trajectory

Uncheck Collision Trajectory in Debug.

EnableCollisionTrajectory

image-20230807095557312

Turning off Collision Result

Uncheck Collision Result in Debug.

EnableCollisionResult

image-20230807095500245

Turning off Raycast Detection

Check Ignore Raycast Result in Debug.

IgnoreRaycastResult

image-20230807095726001

Turning off Motion Trajectory

Check Ignore Overlap Result in Debug.

IgnoreOverlapResult

image-20230807095857698

Turning off Sweep Detection

Check Ignore Sweep Result in Debug.

IgnoreSweepResult

image-20230807100028930