What's a reliable way to create 2d hitboxes that touch consistently?

Hey everyone, I really need help on this one.

I am developing a 2d fighting game. Of course, you’d need functional 2d hitboxes in order for the game to work. I’ve hit many roadblocks when it came to this, and attempted a number of solutions.

Method #1: Physical Parts for hitboxes, using .Touched

I first tried using parts for hitboxes, with clear visual indicators like how they would appear in real fighting games.

However, the biggest issue is that hitboxes do not collide consistently. I do not know why this happens.



I no longer have the version history for this build as I’ve scrapped this quickly.

Possible causes:

  • Hitboxes aren’t out for longer than a split second, however I’ve tested this with a longer lasting hitbox and it still appears.
  • Collisions are handled on the server, and may be inconsistent to player position
  • Hitboxes are restrained to 0 on the Z axis, only moving X and Y. I don’t think this should be the issue, but roblox’s physics engine isn’t exactly the best and I suspect that such limited movement won’t trigger any collisions.

It may be unrelated, but there’s a LocalScript that keeps players on 0 on the Z axis. If a player were to move from that point, they are immediately teleported back to 0. I wonder if this has to do with the inconsistent hitboxes.

local function focus(p1root, p2root)
	if p1root.Position.X < p2root.Position.X then
		return CFrame.new(Vector3.new(p1root.Position.X, p1root.Position.Y, 0), Vector3.new(p1root.Position.X + 1, p1root.Position.Y, 0))
	else
		return CFrame.new(Vector3.new(p1root.Position.X, p1root.Position.Y, 0), Vector3.new(p1root.Position.X - 1, p1root.Position.Y, 0))
	end
end

if lastZ ~= p1root.CFrame.Z then
	p1root.CFrame = focus(p1root, p2root)
end
lastZ = p1root.CFrame.Z

Though despite this, this was the method I wanted to work the most. Not just because it is accurate to fighting games, but I can place the hitbox wherever I want. It could be a disjoint, part of a limb, etc.

Method #2: Raycasts from existing limbs, with an adjusted version of Swordphin’s hitboxes

I’ve used this method as kind of a “placeholder” hitbox system in the draft version of my game, and sure enough, it works fine.

Though, I have some issues with this.

  • Hitboxes are restrained to player limbs, so there cannot be any disjoints or projectiles.
  • Multiple attachments need to be created on each corner of a limb so that the “hitboxes” wont appear skinny
  • Rays are cast from the player’s server position, which is an issue because there is latency between the client and the server, so the player will have a millisecond delay on their positions. This will become a problem when I incorporate air combos into the game, since there is quite a noticeable delay in when players “jump”.

This was my placeholder system so I wasn’t intending on using this forever, because of the limitations of where I can place these hitboxes. I wanted to achieve something like the first method where there were actual hit BOXES, mostly so I could use disjoints and projectiles. Here’s an example from Guilty Gear Xrd

If anyone can come up with workarounds or any other possible methods, that’d be great! I’ve been at a roadblock for a whole month!

5 Likes

The most reliable way would probably be using Region3 (with parts if you choose)
Region3s are much more reliable as compared to using a touched event.

1 Like

I see, can Region3s follow the player as they move? Since players will be moving around a lot I don’t really want the hitboxes to stay anchored to just one position

Have you tried doing hit detection clientside. If you have can you explain what exactly did you do.

I tried method 2 clientside. It fixed the position issue but the rays did not detect anything. the raycast module might not be suited for clientside but I may go back and adjust it. However, method 1 is what I’m looking to achieve the most. Since I don’t have the version history for it, I’ll try and rescript it from clientside.

Yes, you just have to manually set it so they can follow the player as they move.

Client-side hit detection may be a godsend but… You can not trust the client so easily so you will need to detect distance between players via magnitude and set a threshold so that exploiters cant just exploit their client-side hitbox to expand how they see fit.

no need to be rude but this was definitely not how region3s were intended to be use and a simple benchmark will show that. I suppose the OP could use AABB collision seeing as the hitboxs dont seem to rotate at all

I use region3s for hitboxes for attacks on games I work on all the time. If you misunderstood, what I meant was that a physical hitbox for a player exists (as seen in Method #1) (regions aren’t created for this “hitbox”) and when an attack is performed, region3s are created which searches for the player’s hitbox. AABB collision seems like a decent idea, but it depends if the OP wants hitboxes to have different orientations/shapes.

Sorry to bring this up again after a while, could you elaborate on how to use AABB collision? Most guides I find are for GUIs and not for 3d environments. I figured you could use Region3s but the last post seems to say otherwise

Axis Aligned Boundary Box checks are for 2d collision detection. Could you clarify your question? The original post asks for 2d detection algorithms, which are not for 3d environments. If you’re unsure how to project your 3d positions to screen space, check out WorldToScreenPoint or WorldToViewportPoint.

Sorry about that, I meant 2d hitboxes in a way that uses 3d hitboxes confined to 0 on the Z axis. The characters are 3d but move in a 2d space and the hitboxes should reflect that

In this context there’s no functional difference between a Vector3 that has a Z constant of 0, and a Vector2. You can use model:GetBoundingBox() to get a bounding cframe, and a bounding size. Then you can find the extents of the bounding box by offsetting half size in all 4 directions (up, down, left, right).

With those extents you can now construct a 2d AABB by dropping the Z member from each position.

Does it update with player position or would I have to update it through a loop?

You’d need to solve for a new AABB for each character every engine step. That means 30hz heartbeat on the server and 60hz renderstepped on the clients (if clients even need to do collision detection).

Their boundary box is going to stretch and squeeze depending on what their animations are doing, and you want the most recently up to date version of that to keep things looking right to the players.

You could do 3d aabb actually it just would be a waste of computational power. Generate the points by using this method with the model:GetBoundingBox()

Then using those points check collision with this method

local box = {
  ["minX"] = point.x;
  ["minY"] = point.y;
  ["minZ"] = point.z;
  ["maxX"] = point.x + size.x;
  ["maxY"] = point.y + size.y;
  ["maxZ"] = point.z + size.z
}
local function isPointInsideAABB(point, box) -- point is the cframe
  return (point.x >= box.minX && point.x <= box.maxX) &&
         (point.y >= box.minY && point.y <= box.maxY) &&
         (point.z >= box.minZ && point.z <= box.maxZ);
end

I see, but i’m not sure if youre telling me whether it is a waste of computational power or not
I’m also worried about how expensive the process is

2d AABB collision checks are super cheap. He’s saying the 3d check would be wasteful because they’ll all have the same Z values, so you’d be better off doing the 2d check.

1 Like