My question is what elements of a combat system should be done on the server and what should be done on the client?
I want hit boxes, hitstun, knockback, and other elements that would go in a fighting game. I just dont know how those are commonly implemented.
Hello I have made my own complex combat system so I’ll just tell you what I did. I handled almost everything server side including animations with a base Entity class. The dodge roll was handled client side but that’s because the roll logic uses run service. For hitboxes I used raycast hitbox v4. For knockback I used runservice (for players) and heartbeat (for NPCs). As I mentioned I used a base entity class that all players and enemy NPC’s use. This class has methods like Damage(), Block(), IsDodging() etc etc. Hope this helps.
2 Likes
Thank you that helped. So the base Entity class is something you made? Also what do you mean by using runservice for roll logic?
Yea so you can make classes in lua like this (in a module script):
local Entity = {}
Entity.__index = Entity
function Entity.new(name)
local self = setmetatable({}, Entity)
return self
end
return Entity
Im not sure how familiar you are with OOP or classes but it’s very useful for stuff like this.For the roll logic, I didn’t write the code but it uses RenderStepped to change your AssemblyLinearVelocity during the roll.
function OnRenderStepped()
local DashSpeed = EaseQuarticIn(_DashSpeed, 0, math.min(tick() - LastDash, _DashDuration), _DashDuration)
local DashVelocity = LastMDirection * DashSpeed
local Velocity = Root.AssemblyLinearVelocity
Root.AssemblyLinearVelocity = DashSpeed > 0 and Vector3.new(DashVelocity.X, Velocity.Y, DashVelocity.Z) or Velocity
end
1 Like
In most of my games, I do something like this:
Client Input → Server Attack → Client Hitbox → Server Damage
Now for hitstun and interrurption, proxies are the best option. newproxy() generates an empty but unique value that can be used to see if something has changed. To demonstrate, here’s a stun function with and without proxies.
function BeStunned(Time)
InStun = true
task.wait(Time)
InStun = false
--//If this function is run again before it has ended, it will un-stun the player twice, and earlier than intended.
end
StunProxy = newproxy()
function BeStunned(Time)
LProxy = newproxy()
StunProxy = LProxy
InStun = true
task.wait(Time)
if LProxy == StunProxy then --//If the function has not been run again, then we can continue.
InStun = false
end
end
1 Like
Thank you, i didnt know about proxies