How can I reflect projectiles off walls?

I basically hit a roadblock here, and with my current knowledge of scripting and lack of relevant information here. I’m reaching out to you people for help with my problem. But I’ll be using the default template since this is my first post here.

  1. What do you want to achieve? Keep it simple and clear!
    Basically whenever my projectile (in this case, a fireball), hits a wall or surface. It basically reflects off of it.

  2. What is the issue? Include screenshots / videos if possible!
    I’ve tried as many solutions as I could find here but to no avail, the “How to reflect rays on hit” guide was probably my best shot but was unable to work, I’d get hit with a “LookVector cannot be assigned to” or nothing happens.

  3. What solutions have you tried so far? Did you look for solutions on the Developer Hub?
    As stated before, the guide above was my best shot at it but didn’t work. And I didn’t see anything about ray/projectile reflecting on the Developer Hub.

Here’s the projectile register code for those interested in figuring something out.

--Spawns Fireball
	local connection
	connection = game:GetService("RunService").Heartbeat:Connect(function(step)
		local raycastresult = workspace:Raycast(fireballclone.Position, fireballclone.CFrame.lookVector*fireballspeed*step, raycastprams)
		if raycastresult then
			if raycastresult ~= nil and hit == false then
				hit = true
				local humanoid = raycastresult.Instance.Parent:FindFirstChild("Humanoid")
				if not humanoid then
					local humanoid = raycastresult.Instance.Parent.Parent:FindFirstChild("Humanoid")
				end
				if humanoid then
					humanoid:TakeDamage(fireballdamage)
					fireballclone:Destroy()
				else
					fireballclone:Destroy() -- Reflect would probably be somewhere here, after it detects hitting a part.
				end
			end
		end
		if fireballclone ~= nil then
			fireballclone.CFrame = fireballclone.CFrame + fireballclone.CFrame.lookVector*fireballspeed*step
		else
			connection:Disconnect()
		end
	end)

Sorry if I may have messed something up, this is my first post in general here so yeah. Any help would be appreciated. Thank you.

4 Likes

I used the link you posted and it was this result

If the video clip is close to the thing you want to do

What is your problem? Try to explain more widely

Yes, this is the result I’m looking for.

However when trying to apply to my fireball script, it results in a “LookVector cannot be assigned to” error. I decided to try it again but same issue happened. Here’s the same code with the reflect code added to it.

local connection
	connection = game:GetService("RunService").Heartbeat:Connect(function(step)
		local raycastresult = workspace:Raycast(fireballclone.Position, fireballclone.CFrame.lookVector*fireballspeed*step, raycastprams)
		if raycastresult then
			if raycastresult ~= nil and hit == false then
				hit = true
				local humanoid = raycastresult.Instance.Parent:FindFirstChild("Humanoid")
				if not humanoid then
					local humanoid = raycastresult.Instance.Parent.Parent:FindFirstChild("Humanoid")
				end
				if humanoid then
					humanoid:TakeDamage(fireballdamage)
					fireballclone:Destroy()
				else
					local reflect = fireballclone.CFrame.LookVector - (2 * fireballclone.CFrame.LookVector:Dot(raycastresult.Normal) * raycastresult.Normal) -- reflect code
					fireballclone.CFrame.LookVector = reflect
					hit = false
				end
			end
		end
		if fireballclone ~= nil then
			fireballclone.CFrame = fireballclone.CFrame + fireballclone.CFrame.lookVector*fireballspeed*step
		else
			connection:Disconnect()
		end
	end)

Here’s a gif of it in action & showing the same error as above. https://gyazo.com/93b8551f9f606999dc9bbb18f831ef14

Try this I think it helps you with what you want to do

This code when placed inside a StarterPlayer in StarterCharacterScripts

Arrange everything as pictured

Fire Ball Fired

Script

local FireBallEvent = script.Parent:WaitForChild("FireBallEvent")
local Root = script.Parent.Parent:WaitForChild("HumanoidRootPart")

local function onCreateFireBallFired(player, Location)

	local rng = Random.new()
	
	
	local FireBall = Instance.new("Part")
	FireBall.Name = "FireBall"
	FireBall.TopSurface = Enum.SurfaceType.Smooth
	FireBall.BottomSurface = Enum.SurfaceType.Smooth
	FireBall.Size = Vector3.new(2, 2, 2)
	FireBall.BrickColor = BrickColor.new("Really red")
	FireBall.Shape = Enum.PartType.Ball	
	FireBall.Material = Enum.Material.Neon
	FireBall.Anchored = true
	FireBall.CanCollide = false
	FireBall.Locked = true
	FireBall.CFrame = Root.CFrame
	FireBall.Parent = workspace
	
	-- Create Fire
    local fire = Instance.new("Fire")
    fire.Heat = 10
    fire.Color = FireBall.Color
    fire.SecondaryColor = Color3.new(1, 1, 1) -- White
    fire.Size = math.max(FireBall.Size.X, FireBall.Size.Z) -- Pick the larger of the two dimensions
    fire.Parent = FireBall
	
	local maxDistance = 200
	local curDistance = 0
	
	local stepDistance = 4
	local stepWait = 0
	
	local currentPos = Root.Position
	local currentNormal = CFrame.new(Root.CFrame.p, Location).lookVector
	
	local function Step(overrideDistance)
		
		-- Cast ray:
		local params = RaycastParams.new()
		local direction = currentNormal * (overrideDistance or stepDistance)
		params.FilterType = Enum.RaycastFilterType.Blacklist
		params.FilterDescendantsInstances = {script.Parent.Parent}
		local result = workspace:Raycast(currentPos, direction)
		local pos
		
		if result then
			pos = result.Position
		else
			pos = currentPos + direction
		end

		-- Update laser position:
		FireBall.Size = Vector3.new(2, 2, (pos - currentPos).Magnitude)
		FireBall.CFrame = CFrame.new(currentPos:Lerp(pos, 0.5), pos)
		
		local oldPos = currentPos
		currentPos = pos
		
		if result then
			-- r = d - 2(d DOT n)n
			-- Reflect:
			local norm = result.Normal
			local reflect = (currentNormal - (2 * currentNormal:Dot(norm) * norm))
			currentNormal = reflect
			Step(stepDistance - (pos - oldPos).Magnitude)
			return
		end
		
		curDistance = (curDistance + (pos - oldPos).Magnitude)
		
		-- Apply fade effect to laser as it approaches max distance from < 75 studs:
		if curDistance > (maxDistance - 75) then
			local d = (curDistance - (maxDistance - 75)) / 75
			FireBall.Transparency = d
		end
		
		-- Recurse if max distance not reached:
		if curDistance < maxDistance then
			wait(stepWait)
			Step()
		end
	end
	
	FireBall.Touched:connect(function(hit)	
	if hit.Parent.Name ~= script.Parent.Parent.Name then	
	local humanoid = hit.Parent:FindFirstChild("Humanoid")
	if humanoid then
	humanoid:TakeDamage(30)			
	FireBall:Destroy()			
	end		
	end		
	end)
	
	Step()		
			
	-- Done! Destroy laser:
	FireBall:Destroy()	
	
end
 
FireBallEvent.OnServerEvent:Connect(onCreateFireBallFired)

LocalScript

local FireBallEvent = script.Parent:WaitForChild("FireBallEvent")
local player = game.Players.LocalPlayer
local mouse = player:GetMouse()

mouse.Button1Down:Connect(function()
		
   local Location = mouse.Hit.p
   FireBallEvent:FireServer(Location)
		
end)

If you put everything in its proper place you will have this

If it doesn’t work well tell me about the problem

I wish you good luck in what you do

2 Likes