Is there any way of simulating the ray instantly?
I’ve tried figuring this out myself, but haven’t been able to…Does anyone know why when the FirePointObject on the Tool seems to either collide or be very close to colliding with another part, the bullet will fire at a completely different angle?
Sorry for the small Gif, but this showcases what I mean. You can see my first few bullets fire in random directions when touching or nearly touching another object, as well as the last few bullets. You also see one shot actually go in the correct direction when I’m further away from the object.
Is it possible to simulate air resistance and drag with FastCast?
This is a roblox issue with cursor detection sadly.
I personally have this issue with EVERYTHING thats cursor-based.
As far as I am aware there is no direct solution (I may be wrong)
You could attempt the following though.
~ Raycast from the camera origin to get the hit cframe of the mouse. (unsure if this will work.)
~ Or just detect if the gun is very close to something and make it shoot infront of the barrel by default instead of going to the cursor.
Hey, thanks for the response!
In a way, I believe I’m already doing what you’re suggesting, but slightly different. Rather than using the Cursor for getting the Mouse.Hit.Position
, I began using a Raycast from the center of the screen and then returning that position.
local function GetCenterOfScreen()
local position = Camera.ViewportSize / 2
local unitRay = Camera:ViewportPointToRay(position.X, position.Y)
local rayParams = RaycastParams.new()
rayParams.FilterDescendantsInstances = {Character}
rayParams.FilterType = Enum.RaycastFilterType.Blacklist
local raycastResult = Workspace:Raycast(unitRay.Origin, unitRay.Direction * 1_000, rayParams)
local hit = CFrame.new(raycastResult.Position)
return hit.Position
end
Although even with this, the issue still persists, unfortunately.
I was curious if you had an idea of how to get the direction forward of barrel? Currently I calculate the direction using the following equation fireDirection = (mousePoint - FirePointObject.WorldPosition).Unit
.
Additionally, for anyone else who might be curious about the issue, as my previous Gif might not have shown it off greatly, here’s a better one:
If someone is still looking for this, there’s a thread solving this issue:
Simply copy & paste the entire code block, set up the proper arguments (bullet speed, gravity, start position etc.) and use what the LaunchDirection
function returns as your direction
argument:
local CanReach,DIRECTION = LaunchDirection(..., ..., ..., ..., true)
Caster:Fire(FirePointObject.WorldPosition, DIRECTION, modifiedBulletSpeed, CastBehavior)
I would absolutely love a method to simulate once instantaneously. Similar to just WorldRoot:Raycast(), it would be FastCast:Once() that would return a hit. This way I could have FastCast hit reg on client and have a sanity check testing the entire path, including pierces and reflections if I have those implemented. I’ve tried numerous times to do hit reg on the server but the delay is very noticeable and makes gunplay awful. I’ve tried lag compensation methods such as player snapshots, but it still doesn’t beat client hit reg.
May i ask how do you use the pierce function, i have been trying to do ricochet for so long. thank you, sorry if im interupting your time
I have done this for only default projectile motion projectiles.
So it should work unless you are changing the acceleration or velocity after the projectile is in flight.
Sidenote:
But keep in mind to check out other lag compensation server sided solutions and such like CSGO and stuff.
Ultimately it’s up to you to decide.
I created a staff weapon that fires orbs of magic, and when one of these orbs intercepts a part with a “Shield” attribute they are reflected back to the original player. This works fine, but there is one caveat: the changes I try to make to some ray parameters don’t seem to work properly, specifically the FilterDescendantInstances
property.
When a player uses the staff to fire a projectile, the caster is told to ignore their character’s model; when the projectile is reflected back, the script tries to override the filter list with an array only containing the character of the player who reflected the projectile. This would allow the reflected projectile to hit the player who originally shot it, but in practice it refuses to work. The projectile goes through the staff user’s character every time, even if I try setting the ignore list to an empty array.
What gives? Am I not meant to change this property in run time? The band-aid solution I have right now is to not place the staff user’s character in the ignore list in the first place, which isn’t great because you can occasionally hit yourself when firing a projectile.
Hey, thanks for replying!
I recently checked out your solution while back and I have tried implementing it, unfortunately I don’t believe I was setting it up properly. I will give it another shot and see if I can get it working properly!
Also, I looked towards games like CS:GO and tried implementing their lag compensation methods, it didn’t really turn out well and made server hit reg slightly better but still inconsistent.
Best regards,
Scythe
I ended up fixing this issue by overriding the filter list in the CanRayPierce function, not OnRayPierced. Thanks for ADRENALXNE’s help, he had a similar post in this thread and found this solution.
This API member does not exist because it’s not so simple.
Imagine you do a hitreg with this hypothetical FastCast:Once()
and you detect a hit on the person you’re aiming at. Cool, all good so far. But what happens when you fire the bullet that has travel time and say, some dude happens along and walks into the path of the bullet before it hits the guy you were aiming it? Now your pre-calculated result is flat out wrong.
This is why the module comes with the hit simulation it does - because you should be simulating the bullet, travel time and all.
Ahh, I understand. Yeah I can see the complexity behind that and the issues that could arise. I appreciate you reading my reply and considering! I do really enjoy this module quite a lot, it’s been a major staple in many of my projects. Thanks a lot!
Is possible to make a projectile’s motion? I was looking on the dev forum and everything I didnt found I am trying to do something like this.
and I am doing something like:
caster.LengthChanged:Connect(function(cast, lastpoint, dir, length)
local offset = CFrame.new(0, 0, -length)
bullet.CFrame = CFrame.lookAt(lastpoint, lastpoint + dir):ToWorldSpace(offset)
end)
How do you make the bullet render immediately when the cast starts instead of when the cast first updates, since if you have it render when it updates, it’ll start rendering at various distances in front of the firepoint rather than actually at the firepoint. It really breaks immersion and I can’t seem to fix it, I’ve tried moving the bullet position to the firepoint after the first render as well, but it just doesn’t do anything.
you need to increase the downward acceleration, its in the castbehavior i believe
How can I make bullets pierce through the accessories?
How do I make both projectiles terminate when they hit each other? Right now only one random one gets terminated (usually the one that’s most recently fired).
EDIT: I’ve tried getting the bullet that it hit in OnRayHit, and returning it to PartCache in OnCastTerminating, but it didn’t work. The recently fired bullet gets returned, but it errors for the hit bullet saying that it’s not in-use (though it very obviously is as I tried doing table.find on the InUse table with the hit bullet, and it found it perfectly fine every time)
EDIT 2: Solved:) If anyone runs into this in the future, I keep all ActiveCasts in a table, storing them in the table on fire, having the projectile instance as the key, the ActiveCast as the value, and then when I determine that it hits a projectileI find the ActiveCast associated with the projectile instance from the table, and run :Terminate() on it.
Heya there!
There has been just one issue that I seemingly cannot solve.
Sometimes, the bullet ray shoots at the sky (past the zombie)? I’m guessing this is because of the muzzle being inside a zombie head. The video below showcases this: red part is muzzle position, green part is mouse position.
Here’s the module code that I use for the gun.
local setup = {}
setup.__index = setup
local PS = game:GetService("Players")
local RS = game:GetService("ReplicatedStorage")
local DBS = game:GetService("Debris")
local caster = require(script.Parent.Caster)
local partCache = require(script.Parent.Cache)
local damageDisplay = require(script.Parent.Parent.DamageDisplay)
local fx = RS.Events.FX
local effect = {
blood = "Blood",
hit = "Hit"
}
type params = {[string]: any}
local function VisualizeRay(dir: Vector3, origin: Vector3)
local mid = origin + dir / 2
local part = Instance.new("Part") do
part.Parent = workspace
part.Anchored = true
part.CFrame = CFrame.new(mid, origin)
part.Size = Vector3.new(.1, .1, dir.Magnitude)
part.Material = Enum.Material.Neon
part.BrickColor = BrickColor.Red()
part.CanCollide = false
part.CanQuery = false
part.CanTouch = false
task.delay(.2, function()
part:Destroy()
end)
end
end
local function VisualizePos(pos: Vector3, color: BrickColor)
local part = Instance.new("Part") do
part.Parent = workspace
part.Anchored = true
part.Position = pos
part.Size = Vector3.new(.5,.5,.5)
part.Material = Enum.Material.Neon
part.BrickColor = color
part.CanCollide = false
part.CanQuery = false
part.CanTouch = false
--task.delay(.2, function()
-- part:Destroy()
--end)
end
end
local function LoadBulletHole(parent: BasePart, pos: Vector3, normal: Vector3, hum: Humanoid)
local hole = Instance.new("Part") do
hole.CanCollide = false
hole.CanQuery = false
hole.CanTouch = false
hole.Transparency = 1
hole.Size = Vector3.new(.5, .5, .05)
hole.Parent = parent
hole.CFrame = CFrame.lookAt(pos, pos + normal)
end
local image = if hum then script.BloodHole:Clone() else script.PartHole:Clone() do
image.Parent = hole
end
local weld = Instance.new("WeldConstraint") do
weld.Parent = parent
weld.Part0 = parent
weld.Part1 = hole
end
DBS:AddItem(hole, 15)
end
function setup.new(params)
local self = {}
self.Tool = params.Tool
self.Owner = if self.Tool.Parent:IsA("Backpack") then self.Tool.Parent.Parent else PS:GetPlayerFromCharacter(self.Tool.Parent)
self.Character = self.Owner.Character or self.Owner.CharactedAdded:Wait()
self.Damage = params.Damage
self.AttackType = params.AttackType
self.Bullet = Instance.new("Part")
self.Multiplier = params.Multiplier
self.DistanceBeforeMultiply = params.DistanceBeforeMultiply
self.MinSpread = params.MinSpread
self.MaxSpread = params.MaxSpread
for i,v in pairs(params.BulletInfo) do
if i == "Trail" and v:IsA("Trail") then
local at0 = Instance.new("Attachment") do
at0.Parent = self.Bullet
at0.WorldPosition = (self.Bullet.CFrame * CFrame.new(0, 0, (self.Bullet.Size.Z / 2))).Position
end
local at1 = Instance.new("Attachment") do
at1.Parent = self.Bullet
at1.WorldPosition = (self.Bullet.CFrame * CFrame.new(0, 0, -(self.Bullet.Size.Z / 2))).Position
end
local clone = v:Clone() do
clone.Parent = self.Bullet
clone.Enabled = false
clone.Attachment0 = at0
clone.Attachment1 = at1
end
else
if self.Bullet[i] then
self.Bullet[i] = v
end
end
end
self.MaxDistance = params.MaxDistance
self.Speed = params.Speed
self.Gravity = params.Gravity
self.RaycastParameters = params.RaycastParameters
self.BulletParent = params.BulletParent
self.PartCache = partCache.new(self.Bullet, 100, self.BulletParent)
self.Hitbox = caster.new()
self.Behavior = caster.newBehavior() do
self.Behavior.RaycastParams = self.RaycastParameters
self.Behavior.HighFidelityBehavior = caster.HighFidelityBehavior.Default
self.Behavior.MaxDistance = self.MaxDistance
self.Behavior.Acceleration = self.Gravity
self.Behavior.CosmeticBulletContainer = self.BulletParent
self.Behavior.CosmeticBulletProvider = self.PartCache
self.Behavior.AutoIgnoreContainer = false
end
return setmetatable(self, setup)
end
function setup:Fire(mousePos, endPos)
local distBeforeMult = self.DistanceBeforeMultiply
local player = self.Owner
local hitbox = self.Hitbox
local speed = self.Speed
local damage = self.Damage
local gravity = self.Gravity
local multiplier = self.Multiplier
local behavior = self.Behavior
local cache = self.PartCache
local params = self.RaycastParameters
local attackType = self.AttackType
local maxSpread = self.MaxSpread
local minSpread = self.MinSpread
local direction = (mousePos - endPos).Unit
local debounce = {}
local connection = {}
VisualizePos(endPos, BrickColor.Red())
VisualizePos(mousePos, BrickColor.Green())
connection[1] = hitbox.LengthChanged:Connect(function(caster, origin, direction, length, velocity, bullet)
if not bullet then
return
end
if bullet:FindFirstChildWhichIsA("Trail") then
bullet:FindFirstChildWhichIsA("Trail").Enabled = true
end
local bulletLength = bullet.Size.Z / 2
local baseCFrame = CFrame.new(origin, origin + direction)
bullet.CFrame = baseCFrame * CFrame.new(0, 0, -(length - bulletLength))
end)
connection[2] = hitbox.RayHit:Connect(function(caster, ray, velocity, bullet)
local hitPart = ray.Instance
local hitPoint = ray.Position
local normal = ray.Normal
local model = ray.Instance:FindFirstAncestorOfClass("Model")
local hum = model and model:FindFirstChildOfClass("Humanoid")
fx:FireAllClients(if hum then effect.blood else effect.hit, hitPart, hitPoint)
LoadBulletHole(hitPart, hitPoint, ray.Normal, hum)
if hum and not PS:GetPlayerFromCharacter(model) then
if debounce[hum] then
return
end
--if attackType == "Destroying" then
-- local blacklist = {"Torso", "HumanoidRootPart"}
-- local rand = Random.new():NextInteger(1,65)
-- if rand <= 25 and hitPart and not table.find(blacklist, hitPart.Name) then
-- hitPart.Transparency = 1
-- task.delay(.4, function()
-- hitPart:Destroy()
-- end)
-- end
--end
local currDamage = if multiplier[hitPart.Name] then damage * multiplier[hitPart.Name] else damage
if player:DistanceFromCharacter(hitPoint) < distBeforeMult then
currDamage *= 1.3
end
debounce[hum] = true
hum:TakeDamage(currDamage)
damageDisplay.new(currDamage, hitPart)
end
end)
connection[3] = hitbox.CastTerminating:Connect(function(caster)
local cosmeticBullet = caster.RayInfo.CosmeticBulletObject
if cosmeticBullet then
if behavior.CosmeticBulletProvider then
pcall(function()
if cosmeticBullet:FindFirstChildWhichIsA("Trail") then
cosmeticBullet:FindFirstChildWhichIsA("Trail").Enabled = false
end
behavior.CosmeticBulletProvider:ReturnPart(cosmeticBullet)
for i,v in ipairs(connection) do
v:Disconnect()
end
end)
end
end
end)
pcall(function()
local dirCF = CFrame.lookAt(Vector3.new(), direction)
local spreadDir = CFrame.fromOrientation(0, 0, math.random(0, math.pi * 2))
local spreadAngle = CFrame.fromOrientation(math.rad(math.random(minSpread, maxSpread)), 0, 0)
local direction = (dirCF * spreadDir * spreadAngle).LookVector
local modifSpeed = (direction * speed)
hitbox:Fire(endPos, direction, modifSpeed, behavior)
end)
end
return setup
I’m not really sure how I can solve this. Any help is appreciated!
EDIT: I think I solved it. I just moved the muzzle point backwards by a few studs (it’s now practically in the player’s shoulder).