Raycasting Distance - Position problem

I am creating a raycast weapon system that casts a projectile to where the raycast hits or stops. I am using the distance equation to find the distance between the muzzle position of the weapon and the hit position to find the total distance between these two, I am then dividing this by the total speed of the projectile which is 4000. I hoped that this would allow me to calculate the time it would take for the projectile to get to the raycasts hit point so that it could then remove the bullet. Though this is not working correctly as the bullet is shown to go through the wall. Have I done something incorrectly?

This is the part of the code where it calculates this:

local waiting = (muzzlePos - Position).Magnitude
	bv.MaxForce = Vector3.new(math.huge,math.huge,math.huge)
	bv.Velocity = bulletPart.CFrame.LookVector * 4000
	wait(waiting/4000)
	print(Position)
	print(bulletPart.Position)
	bulletPart:Destroy()

At first it seemed that it would work perfectly though it didnt. The two print statements “Position” and “bulletPart.Position” should be the exact same when the bullet is deleted. Though the bullet is visually seen going slightly through the wall. And the outputs are sometimes slightly to largely different.

Gif, showing its the projectile not the raycast(raycast stops at the hit pos)
https://gyazo.com/444f65f719330b291c916da126612cf8

output (both values should be the same)
shot1
image
shot2
image

Could someone tell me what I have done wrong? Or does this just not work on roblox.

2 Likes

To add on to this, we know there are much better ways to use raycasting in weapons and have done so many times but are just curious if this method would work

I tested this out in Studio out of curiousity, but unfortunately had the same results as you. I assume it’s to do with setting the MaxForce to math.huge, I had success when I tested it with a lower MaxForce:

-- test
local bulletPart = game.Workspace.Bullet
local muzzlePos = bulletPart.CFrame.p
local Position  = bulletPart.CFrame * CFrame.new(0, 0, -200)

game.Workspace.Wall.CFrame = Position
Position = Position.p

local bv = bulletPart.BodyVelocity

bv.MaxForce = Vector3.new(1, 1, 1) * 1000

bulletPart.Anchored = false
wait()
local begin = time()
bv.Velocity = bulletPart.CFrame.lookVector * 400
bulletPart.Touched:connect(function ()
	print(time() - begin, "time taken (s)")
end)

local v = bv.Velocity.magnitude
local t = (muzzlePos - Position).magnitude / v

delay(t, function ()
	print("Deleted at time", t, "(s)")
	bulletPart.Anchored = true
end)

Although, I am wondering why you’re using velocity as well as raycasting? It makes more sense for you to increment the bullet’s position using CFrame whilst raycasting incrementally.

The reason for this is that I am unsure of how to properly increment the CFrame and wanted to try a different method.

Here you go:

local PROJECTILE_SPEED = 3   -- how fast projectile moves
local RAY_DISTANCE     = 500 -- max distance it can travel
local PROJECTILE_DROP  = 0   -- whether the bullet drops or not, needs to be negative number if you want it to drop

local fireBullet = (function (A, B, projectile, ignore_model, ignore_func)
	ignore_func = ignore_func or (function () return false end)
	
	if not projectile then
		return
	end
	
	local shot_dir = B.lookVector * RAY_DISTANCE
	local shot_ray = Ray.new(B.p, shot_dir)
	
	local _, true_shot = game.Workspace:FindPartOnRay(shot_ray, ignore_model)
	
	local drop = CFrame.Angles((math.random() * PROJECTILE_DROP) * 0.01, 0, 0)
	
	projectile.Anchored = true
	projectile.CFrame   = CFrame.new(A.p, true_shot)
	projectile.Parent   = game.Workspace
	
	local Dist, Hit, Pos, endPos, Surface = 0
	repeat
		local start = projectile.Position
		    end_pos = ((projectile.Position + (projectile.CFrame * drop).lookVector * PROJECTILE_SPEED) - projectile.Position).unit
		
		local dir_ray = Ray.new(
			start,
			end_pos.unit * PROJECTILE_SPEED
		)
		Hit, Pos, Surface = game.Workspace:FindPartOnRay(dir_ray, ignore_model)
		projectile.CFrame = CFrame.new(Pos, Pos + dir_ray.Direction)
		
		Dist = Dist + PROJECTILE_SPEED
		wait()
	until (Hit and not ignore_func(Hit)) or Dist > RAY_DISTANCE

	return {
		distance    = Dist;
		hit         = Hit;
		hit_pos     = Pos;
		hit_surface = Surface;
		projectile  = projectile;
	}
end)

With example usage:

-- example usage:
local ignore_these_hits = (function (part)
	-- don't ignore anything unless it's called "ignore_me"
	if part.Name == "ignore_me" then
		return true
	end
	return false
end)

local hit_data = fireBullet(
	CFrame.new(0, 5, 0),			     -- Start position of bullet (must be CFrame)
	game.Workspace.CurrentCamera.CFrame, -- Player's camera position (must be CFrame)
	game.Workspace.Bullet,				 -- Pass any bullet part
	game.Worspace.Character,			 -- Pass a model you want it to ignore, e.g. the user's character that is shooting
	ignore_these_hits 					 -- Function for the raycasting to ignore any objects defined in the function as it shoots
)

if hit_data then
	print("Bullet travelled:", hit_data.distance)
	if hit_data.hit then
		print("Bullet hit:", hit_data.hit, "at position:", hit_data.hit_pos, "on surface:", hit_data.hit_surface)
	else
		print("Bullet did not hit anything, landed at location:", hit_data.projectile.CFrame)
	end
	
	-- remove bullet
	hit_data.projectile:Destroy()
end
1 Like

Thanks, this will help greatly.

No worries! Apologies it doesn’t solve your initial solution, but I hope it’ll be a good enough alternative solution :slight_smile: