Combat methods (Damaging humanoid)

Hello, I will keep it short and simple.

I want to find out which method would be the most efficient. Note, damaging happens when a player clicks the left button of the mouse.

  1. loop through workspace and use .magnitude to damage nearby players (server script)
  2. using .touched event on a blade of the weapon (server script)
  3. using .touched event locally, sending the player that got hit to the remote event (local script) - check if the player is near the blade, if so - damage the player (server script)

If you have more methods to share, please let me know below.

7 Likes

I would assume that method 2 would be the most efficient, since it does not require any communication between the client and server, which could add delay, and it does not seem to be vulnerable to remote event spoofing. I would not go with method 1 since it could give players false hits.

1 Like

Depending on the complexity of your weapon, I’d recommend raycasting, instead. As it’s frequently more accurate than using .Touched.
You could do it client-side, for extra performance, or server-side. If doing the former, you’d need to check if the player is near the blade, of course.

1 Like

I have tried raycasting method before, it was pretty efficient.

i had a different approach for mele hits in my prototype, what helped is @EgoMoose 's Rotated Region3 Module
for each attack type (combos or weapons) i had a table with information about the hitbox, something like:
local hitbox = {CFrame, Size}
which gave you a cframe offset from a players humanoidrootpart and the size of the hitbox, creating a part (to visualize the hitbox), i’d construct a rotated region3 with the module given the parts cframe (in front of the player, positioned however i want) and the vector3 size of the region, dettect all parts inside the region and filter them out (npc, player, duplicate part of player already hit ect.)
this would happen in one frame, preferably with a custom animation event of the impact.
i’ve tried all 3 methods plus raycasting and found that this was the absolute best option for both performance and accuracy

but (if for some reason you cant make this happen) out of your 3 methods listed i’d probably go for the first one for accuracy as touched events are unreliable. and probably just loop through the players instead of all parts of workspace

@Wingboy0 could you try explaining rotated region3 in use?

you can find all about it in the thread i linked, but in short, it allows you to create an imaginary part in workspace (in our case, in front of the players root where the hit detection happens) and check what parts are touching or inside that part (area) exactly like hitboxes work in other games.
theres also an indepth explanation by ego here:


(tons of math and confusing stuff, you don’t require that knowledge to use the API but its cool to know how they work / how to make one yourself)

EDIT: quick visual demo

1 Like

He mentions “(server script”) next to his idea for 2., so sounds like he wants the .touched detection to be handled by the server. Unless he wants to go down a very bad path, he will require communication between client/server via remotes. Example, player clicks mouse which fires an event to attach a .touched listener on the server to the blade for the duration of that attack/animation.

Yes, that is basically the idea of method 2. player clicks the mouse which will fire an event that triggers .touched event on a part.

1 Like

You can use a MeshPart for visually accurate collisions and GetTouchingParts (the more tris in the mesh the more lag this will cause so if your mesh is more than a few tris you should probably just switch to a Part). I would suggest using .Touched on the server, however do not use this alone as verification that a touch happened since the player can cause .Touched events for any part indirectly or directly connected to their root part (which they have NetworkOwnership of). That means anything attached to the player including Tool handles, accessories, etc.

When the .Touched event is fired you should use GetTouchingParts and check for character body parts.

1 Like

I like this post too much:

It describes a method of creating hitboxes via raycasting and mentions that Touched/GetTouchingParts (physics-based intersection detection) were rather inefficient for their use case.

4 Likes

How would you make raycasting as a trail? What would be the approach?

I would assume that base attachments are placed on the actual sword to create the points that make up the sharp ends of the blade that are used to attack with. From here, a raycast is fired a distance out from the attachment forward to determine the hit space in that frame.

Since the trails in this case are used purely for visualisation and the process isn’t described, I don’t know how you would accomplish that. I would assume that two more attachments are created to surround the base attachment at the top or the bottom, or another one is placed a distance out from the base attachment. Then from there it’s simple adding of a trail and configuration of its properties.

Never use Touched, that’s inefficient. And it’s not always accurate as I’ve heard, and it has problems with CFraming, etc.

For Sword Combat:

You want to use Region3, and once you’ve learned the basics of Region3, use EgoMoose’s Rotated Region 3. Normal Region3s don’t rotate but with EgoMoose’s Rotated Region 3 you can CFrame it accordingly to the Sword and the rotation will change.

For Punch Combat:

I would suggest looping through the Workspace, finding all models, checking if the Model has a humanoid and humanoidrootpart, then use this:

if (RootPart.Position + RootPart.CFrame.LookVector * 3 - EnemyPart.Position).Magnitude <= 3 then
	--Do combat stuff here
end

Make sure you’re looping through the workspace on the client, and once you’ve found the EnemyPart that’s closes to you, you can fire an event to the Server. The Server checks if you actually are close to the enemy using this same method and if you are, it will perform Effects, etc. If you’re doing hit effects, hit sounds, and other things that might happen for visual appearance when you hit your enemy, you want to fire a event to all of the clients on the Server so the Server can do less work therefor less lag. Want to do Combos? Add a ComboTable on the Client and insert “L” or “R” Depending on what key was clicked. This is pretty much what I use in my Punch Combat

With all of this in mind, you can create a Punch Combat system like this:

If I made any mistakes or logical errors feel free to correct me

Also, if you have any questions or need any help please do not hesitate to ask.

6 Likes

Don’t ever do this. It’s expensive and bad code, especially if you do this every time you require a hit to register against an entity with a Humanoid.

Track top-level entities that have Humanoids and keep them in a cache, such as through the CollectionService (you won’t need a cache with CS actually, let the backend handle that). You can then just iterate through anything tagged with your Humanoid identifier. Saves you

  • Good performance time,

  • the need to do something you don’t need to,

  • and your valuable sanity during development.

If you require the enemy’s root part position, check their Humanoid.RootPart. If you don’t set it, start setting it. This allows you to get a reference to the root without checking

  • A. If there’s parts under the humanoid’s parent,

  • B. If a model has a part named HumanoidRootPart,

  • C. For both a Humanoid and a RootPart as children of a model.

It’s also clean for your code. You just need to know if the Humanoid exists, then check for non-nil references in its properties.

3 Likes

So it’s okay for me to loop through everything in the workspace and add a tag to the model if it’s a humanoid once?

1 Like

Realistically no. If you don’t have any kind of arbitrary work going on or you’re capable of maintaining tags on Humanoids, you should perform Humanoid tagging in Studio as opposed to run time. Only then is iterating the entire workspace okay.

1 Like