Flashcast is a raycasting library built for projectiles.
I made this because I was fed up of FastCast’s abstractions. Flashcast lets you have more fine-grained control over your bullets so you can implement your own systems (ex: gravity, reflection, physical bullets) without any hassle.
You can find some examples on the repository README linked below.
Basic Usage
local SPEED = 25
local MAX_DISTANCE = 1000
local GRAVITY = Vector3.new(0, -workspace.Gravity, 0)
local function gravity(bullet: Flashcast.Bullet, deltaTime: number)
local parallelComponent = bullet.direction:Dot(GRAVITY.Unit) * GRAVITY.Unit
local perpendicularComponent = bullet.direction - parallelComponent
local newDirection = perpendicularComponent + (parallelComponent + GRAVITY * deltaTime)
bullet.direction = newDirection.Unit * bullet.direction.Magnitude
end
local function maxDistance(bullet: Flashcast.Bullet)
if bullet.distanceTraveled > MAX_DISTANCE then
bullet:stop()
end
end
local flashcast = Flashcast.new()
local behavior = Flashcast.createBehavior()
:setDesiredFramerate(10) -- the bullet will move every 1 / 10 seconds
:beforeStep(maxDistance) -- applies a max distance check before moving the bullet
:afterStep(gravity) -- applies gravity after moving the bullet
local direction = Random.new():NextUnitVector()
local bullet = flashcast:spawnBullet(
behavior,
Vector3.new(0, 10, 0),
direction * SPEED
)
I rewrote Flashcast to work with a behavior pattern, framerates instead of ticks, and more.
You cannot pass a function to define the tick anymore, instead you have to connect a callback to flashcast.event and iterate through the bullets with :getBullets (yes, raycasts were renamed to bullets). Flashcast.Result does not exist anymore, you should just call bullet:stop() instead.
No more :onStop, there’s :isStopped, to use in an :afterStep callback.
No more state, you’ve got data to work with and Flashcast-made fields were moved to the bullet instance.
local flashcast = Flashcast.new()
local behavior = Flashcast.createBehavior()
:setDesiredFramerate(10)
:afterStep(function(bullet)
print(`bullet traveled {bullet.distanceTraveled} studs`)
end)
flashcast.event:Connect(function()
for _, bullet in flashcast:getBullets() do
bullet.desiredFramerate = os.clock()
end
end)
local bullet = flashcast:spawnBullet(behavior, Vector3.yAxis * 25, Vector3.xAxis * 25)
Learn more about 3.0.0 in the documentation ps: I haven’t updated the examples yet
I set up a quick test environment with 100 parts and 500 concurrent bullets spawning every half a second. They’re going 1000 studs a second. I’m also moving attachments for each bullet on :beforeStep. Flashcast:step took around 4-5 milliseconds per frame. Keep in mind the performance of a raycast can vary from different factors such as part count and length.
Hi, it can be used for anything, all it does is raycast in a direction and let you customize some behavior. It doesn’t move models or anything like that.
I’ve never seen the rockets go through walls and floors.
And also, the example places still use the old Flashcast so be wary of that. I’m working on making new ones.
Does this have incorporated replication? Just curious. Anyways cool module I’ll probably use it. I made my own projectiles before because I was fed up with how complicated fast cast was for making a bullet, but that system became hard to maintain and it felt wonky. I will be trying this out, I’ll try to remember to give some feedback.
nah, replication refers to the visualization of projectiles on clientside.
for example when using fast cast, the visual object representing the projectile is purely cosmetic. when visualized on the server, sure it’s easier, but when the client is moving the bullets on the server seem to lag behind. not only this, but doing purely cosmetic things, especially with base parts, can be laggy on its own. because of this we network through the server, and spawn separate projectile instances to follow a predetermined path, so that they are visually aligned for everyone. however if the projectiles are hit detection wise managed on the server it may appear to be off from where the projectile “actually hit”.