I was going to say exit wound, but it’s more like an exit wound for basic parts.
I have a very basic bullet hole for parts, but how can I find the opposite side of the part?
Why would I make fun of you lol, not your fault. So, if I am correct this script is what makes the bullet hole whenever it hits a wall and you want it to wall bang (go through the wall)?
yeah, it does the whole cloning, setting up CFrames, makes the case go whoosh, sets up the tween, checks if the long, skinny hitbox touches anything (it aint that bad since tweens are real smooth), does a bit of doohicky stuff with raycasts, and yeah thats basically it
Well I would say, instead of doing doohicky stuff with workspace:Raycast() do Ray.new() even if it is depracated it is still very useful. It is a ray that goes through a wall but you can detect parts with workspace:FindPartOnRay()
Example:
local ray = Ray.new(bullet.CFrame.Position - bullet.CFrame.LookVector * 0.25,bullet.CFrame.LookVector * 10)
if ray then
local HitPart, HitPosition = workspace:FindPartOnRay(ray) --// For ignoring do :FindPartOnRayWithIgnoreList(Ray, {Table})
--// DO the funny stuff with HitPart and HitPosition. And due to the fact Ray.new doesn't stop on a part like usual workspace:RayCast() it can be used for Wall Bangs
end
yeah i changed that thinking the same thing but it still works the same as before
local ray = Ray.new(script.Parent.CFrame.Position,script.Parent.CFrame.LookVector * 100)
if ray then
local HitPart, HitPosition = workspace:FindPartOnRay(ray) --// For ignoring do :FindPartOnRayWithIgnoreList(Ray, {Table})
print(HitPart,HitPosition)
--// DO the funny stuff with HitPart and HitPosition. And due to the fact Ray.new doesn't stop on a part like usual workspace:RayCast() it can be used for Wall Bangs
end
while task.wait() do
local ray = Ray.new(script.Parent.CFrame.Position,script.Parent.CFrame.LookVector * 100)
if ray then
local HitPart, HitPosition = workspace:FindPartOnRay(ray) --// For ignoring do :FindPartOnRayWithIgnoreList(Ray, {Table})
print(HitPart,HitPosition)
--// DO the funny stuff with HitPart and HitPosition. And due to the fact Ray.new doesn't stop on a part like usual workspace:RayCast() it can be used for Wall Bangs
end
end
The only solution I can think of using workspace:Raycast is raycasting n-times until the limit is reached or no result, and add each result to the blacklist.
One downside is you can’t use a whitelist.
code:
function raycast(origin: Vector3, direction: Vector3, max: number?): (number, {[number]: RaycastResult})
max = max or 100
local result
local results = {}
local blacklist = {}
local count = 0
local endPoint = origin + direction
while count < max do
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = blacklist
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
result = workspace:Raycast(origin, endPoint - origin, rayParams)
if result then
table.insert(results, result)
table.insert(blacklist, result.Instance)
origin = result.Position
count += 1
else
break
end
end
return count, results
end
edit: a sollution without using a blacklist but with using the CanQuery and CanCollide property to ignore allready found parts instead.
Code:
function raycast(origin: Vector3, direction: Vector3, params: RaycastParams?, max: number?): (number, {[number]: RaycastResult})
max = max or 100
local result
local results = {}
local parts = {}
local count = 0
local endPoint = origin + direction
while count < max do
result = workspace:Raycast(origin, endPoint - origin, params)
if result then
table.insert(results, result)
table.insert(parts, {
part = result.Instance,
canCollide = result.Instance.CanCollide
})
result.Instance.CanCollide = false
result.Instance.CanQuery = false
origin = result.Position
count += 1
else
break
end
end
for _, data in ipairs(parts) do
data.part.CanQuery = true
data.part.CanCollide = canCollide
end
return count, results
end
local userInputService = game:GetService("UserInputService")
-- this function will simply create a part with a position and color
local function CreatePart(position, color)
local part = Instance.new("Part")
part.Position = position
part.Size = Vector3.one
part.Color = color
part.Shape = Enum.PartType.Ball
part.TopSurface = Enum.SurfaceType.Smooth
part.BottomSurface = Enum.SurfaceType.Smooth
part.Anchored = true
part.Parent = workspace
end
userInputService.InputBegan:Connect(function(input, processed)
if processed == true then return end
if input.UserInputType ~= Enum.UserInputType.MouseButton1 then return end
-- get the mouses click position in 3d space and the direction of the click
local mouseLocation = userInputService:GetMouseLocation()
local ray = workspace.CurrentCamera:ViewportPointToRay(mouseLocation.X, mouseLocation.Y)
-- shoot a ray from the mouses position in the direction of the click for 1000 studs
local results1 = workspace:Raycast(ray.Origin, ray.Direction * 1000)
-- if the ray does not hit anything exit the function and do nothing
if results1 == nil then return end
-- get a random color so its easier to match the part on the other side
local color = Color3.new(math.random(), math.random(), math.random())
-- create a part at the ray hit position with the random color
CreatePart(results1.Position, color)
-- now we whitelist the part that the ray hit so that the ray can only hit the same part when we shoot a ray backwards
local raycastParams = RaycastParams.new()
raycastParams.FilterType = Enum.RaycastFilterType.Whitelist
raycastParams.FilterDescendantsInstances = {results1.Instance}
raycastParams.IgnoreWater = true
-- shoot a ray backwards
local results2 = workspace:Raycast(ray.Origin + ray.Direction * 1000, -ray.Direction * 1000, raycastParams)
-- create a second part using the backwards rays position and use the same color as the first part
CreatePart(results2.Position, color)
end)
local function opositeHit(origin: Vector3, direction: Vector3, result: RaycastResult): Vector3
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = { result.Instance }
local newOrigin = origin + direction
local newDirection = result.Position - newOrigin
local result = workspace:Raycast(newOrigin, newDirection, params)
return result and result.Position or nil
end
Only the way you create the opposite ray is kinda weird?
It should go from destination to origin - destination
destination = origin + direction
So @5uphi’s works pretty well, but how do I use yours @S3nt1ne3l? I tried to put it in a script in a part, but the ray was nil, and so the instance and position were errors.
local function opositeHit(origin: Vector3, direction: Vector3, result: RaycastResult): Vector3
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = { result.Instance }
local newOrigin = origin + direction
local newDirection = result.Position - newOrigin
local result = workspace:Raycast(newOrigin, newDirection, params)
return result and result.Position or nil
end
opositeHit(script.Parent.Position,script.Parent.CFrame.LookVector*100)
the function takes a third argument, the result of the previous casted ray. the previous result is needed for the hit position and hit part. And I changed it a bit and now you can use the hit part as a third argument too.
local function oppositeHit(origin: Vector3, direction: Vector3, result: RaycastResult|Instance): Vector3
local params = RaycastParams.new()
params.FilterType = Enum.RaycastFilterType.Whitelist
params.FilterDescendantsInstances = { typeof(result) == "Instance" and result or result.Instance }
local newOrigin = origin + direction
local newDirection = origin - newOrigin
local result = workspace:Raycast(newOrigin, newDirection, params)
return result and result.Position or nil
end
local origin = script.Parent.Position
local direction = script.Parent.CFrame.LookVector*100
local result = workspace:Raycast(origin, direction)
local oppositeResult = result and oppositeHit(origin, direction, result)
-- or
local oppositeResult = result and oppositeHit(origin, direction, result.Instance)