without getting super math heavy (because, will it always be a circle or do you want any arbitrary shape)
what you could do is something like this (forgive the random sizes, assume these are all just parts in the pink color
and the idea is when the npc is hitting the player, to find the closest node (pink) and hit towards that node. This would work even on square or custom shaped-maps
this doesn’t take advantage of any geometry though, but should be decently efficient. If you know you’re always going to be in a circle, you could consider the angle and distance from the center of the stage
knowing that angle means that you would probably just want to hit towards the same angle, as a straight line to the edge is probably going to be much closer than a curved one. You could make it feel a bit more “human” if you consider the distance too, where if the NPC is close to the center of the stage, just hit in a random direction until you feel like they’re close enough to start pushing to the edge.
Divide the distance from the circle’s center to the NPC by the radius. This will give you the percentage of how far the NPC has moved away from the circle.
Then you need to understand at what speed the refinery can move the player if he stands in the center of the circle and multiply by a percentage
local radius = 10
local magnitude = (Body.PrimaryPart.Position - Player.HumanoidRootPart.Position).Magnitude
local percentage = 1 - radius / magnitude
local power = 1000000 * percentage
maybe you could try using a pathfinding system / voxel grid to detect the edge of a part?
You could run something like that in a loop and update it every 5 seconds or so to save on performance
thats a good idea for automating it, i already have a pathfinding system that can detect edges to trigger pathfinding and etc
using such system with a voxel map of the desireed part is a good idea, ill see what i can do with that
(if i can figure out how to make a voxel map of course)
I’ve used something like this for an audio muffling system. It’s very efficient and barely effects performance at all. Voxel grids are a little complicated to make, but it’s worth it in my opinion.
If your maps could potentially be any shape, an intuitive and not (too) costly solution would be to create “barriers” for each map, parts that surround it on the edges. When the player is hit by an enemy, to get the knockback direction, loop through the list of barriers and call :GetClosestPointOnSurface() for each one. Whichever returned point is closest is where the knockback for the player should be directed.
This does take a bit more manual work of placing parts around the edges, but it’s easy to understand and code, and it’s not too much of a hassle. Plus you get concavities for free, since you’re specifying where players should be knocked back to, meaning you can have pits in the middle of your map.
Make a preset grid. Think of the Default Baseplate grid, you know how it has those box texture things in it? Think of those as your grids
Put that in a distance you’re comfortable with, and then make parts in a and put in in something like 10x1x10 grid (x,y,z)
Heres a piece of code you can put in the command line to get an example of what im talking about cuz im not good with words lol
local gridSize = 10 -- Size of the grid (10x10x10)
local voxelSizeXZ = 4 -- Size of each voxel on X and Z axes
local voxelSizeY = 1 -- Size of each voxel on Y axis
local offset = voxelSizeXZ / 2 -- Offset to center the grid
for x = 1, gridSize do
for y = 1, gridSize do
for z = 1, gridSize do
local voxel = Instance.new("Part")
voxel.Size = Vector3.new(voxelSizeXZ, voxelSizeY, voxelSizeXZ) -- Y is 1 stud
voxel.Position = Vector3.new(
x * voxelSizeXZ - offset,
y * voxelSizeY, -- Y position is based on voxelSizeY
z * voxelSizeXZ - offset
)
voxel.Anchored = true
voxel.Parent = workspace
end
end
end
print("Voxel grid generated with Y = 1 stud")
maybe you can use raycasts and cast directly down from the grid and match it to the nearest edge of a part? Or you can use this grid for the pathfind, which is what i would do.
Also, using grids for your NPC system would make it much more precise. Think of this grid as echolocation for the NPC, you can detect parts inside of the grid if you wanted to on a precise level compared to using something like magnitude and distance.
this causes some MAJOR lag with higher numbers, and with my map being relativly large, it lags alot. so maybe adding offset in between the grid parts will be required, it’ll be less accurate, but hopefully alot less laggy
i need a pivot point where the grid is generated from so it can be generated around the npc
i apologise for not being to experienced in this
heres my slightly altered code since it only needs to be on 1 y
local gridSize = 500 -- Size of the grid (10x10x10)
local voxelSizeXZ = 1 -- Size of each voxel on X and Z axes
local voxelSizeY = 1 -- Size of each voxel on Y axis
local offset = voxelSizeXZ / 2 -- Offset to center the grid
local PivotPoint = Vector3.new(0,50,0)
for x = 1, gridSize do
for z = 1, gridSize do
local voxel = Instance.new("Part")
voxel.Size = Vector3.new(voxelSizeXZ, voxelSizeY, voxelSizeXZ) -- Y is 1 stud
voxel.Position = Vector3.new(
x * voxelSizeXZ - offset,
PivotPoint.Y, -- Y position is based on voxelSizeY
z * voxelSizeXZ - offset
)
voxel.Anchored = true
voxel.Parent = workspace
end
end
this would be good for simple maps that forever stay the same, but with player input the map can change quite a bit, but this is something i didnt actually know and mgith be pretty handy in the future!
It was meant to be an example of what it would look like. I’d recommend building your own grid and fine tuning it. It doesn’t need to expand the entire map but rather just a certain radius (i think anyway xd) Also I’m pretty sure you don’t need to use parts for this, you can use attachments to get the positions of the grid too
that also works, also i jsut figured out how the offsets worked, i jsut wanted the displays to be 1 stud nto realising that it also controls the offsets, so i can do that
but for the raidius thing,
that might have to be used, and with the suggestion from one of the posts above saying to make it only aim for edge if its sort of close, its also a pretty good idea for that, ill see what i can do with this and report back, tho i still have 0 clue on how to put a pivot point for the grid, but ill try and figure it out
im struggling with being able to position the center of the grid, how would i do this?
(heres what i did, making the position in the corner)
local gridSize = 50 -- Size of the grid (10x10x10)
local voxelSizeXZ = 5 -- Size of each voxel on X and Z axes
local offset = voxelSizeXZ / 2 -- Offset to center the grid
local PivotPoint = Vector3.new(54.863, 775.262, -57.502)
for x = 1, gridSize do
for z = 1, gridSize do
local voxel = Instance.new("Part")
voxel.Size = Vector3.new(1,1,1) -- Y is 1 stud
voxel.Position = Vector3.new(
(x * voxelSizeXZ - offset)+PivotPoint.X,
PivotPoint.Y,
(z * voxelSizeXZ - offset)+PivotPoint.Z
)
voxel.Anchored = true
voxel.Parent = workspace
end
end
to center it u need to adjust the position calculation is relative to the pivot point
The issue is the grid starts at 1,1 and extends to (gridsize, gridsize) which places the grid in the corner rather than centered around the PivotPoint
Try this;
local gridSize = 50 -- Size of the grid (50x50)
local voxelSizeXZ = 5 -- Size of each voxel on X and Z axes
local PivotPoint = Vector3.new(54.863, 775.262, -57.502)
-- Calculate the total size of the grid
local totalGridSizeXZ = gridSize * voxelSizeXZ
-- Calculate the offset to center the grid
local offsetXZ = totalGridSizeXZ / 2
for x = 1, gridSize do
for z = 1, gridSize do
local voxel = Instance.new("Part")
voxel.Size = Vector3.new(1, 1, 1) -- Y is 1 stud
-- Adjust the position to center the grid around the PivotPoint
voxel.Position = Vector3.new(
PivotPoint.X + (x * voxelSizeXZ - offsetXZ),
PivotPoint.Y,
PivotPoint.Z + (z * voxelSizeXZ - offsetXZ)
)
voxel.Anchored = true
voxel.Parent = workspace
end
end
also you can put all of the parts in a model if you havent already
This actually works great!
im goign to head off to bed since its getting late, but here is the code i have used, and i will put it to use when i can!
local gridSize = 50 -- Size of the grid (50x50)
local voxelSizeXZ = 5 -- Size of each voxel on X and Z axes
local PivotPoint = Vector3.new(54.863, 775.262, -57.502)
-- Calculate the total size of the grid
local totalGridSizeXZ = gridSize * voxelSizeXZ
-- Calculate the offset to center the grid
local offsetXZ = totalGridSizeXZ / 2
local function IsLocationTravelable(location:Vector3)
local rayinfo = RaycastParams.new()
rayinfo.FilterType = Enum.RaycastFilterType.Exclude
rayinfo.RespectCanCollide = true
--rayinfo.FilterDescendantsInstances = char:GetDescendants()
rayinfo.CollisionGroup = "Default"
local info = workspace:Raycast(location,Vector3.new(0,-20,0),rayinfo)
if info then
return info.Instance
end
return false
end
for x = 1, gridSize do
for z = 1, gridSize do
local pos = Vector3.new(
PivotPoint.X + (x * voxelSizeXZ - offsetXZ),
PivotPoint.Y,
PivotPoint.Z + (z * voxelSizeXZ - offsetXZ)
)
if not IsLocationTravelable(pos) then
local voxel = Instance.new("Part")
voxel.Size = Vector3.new(1, 1, 1) -- Y is 1 stud
-- Adjust the position to center the grid around the PivotPoint
voxel.Position = pos
voxel.Anchored = true
voxel.Parent = workspace
end
end
end