SimpleCast - An Alternative to FastCast

CURRENT VERISON 1.2

SimpleCast seeks to be a simpler version of FastCast. FastCast and SimpleCast do not use roblox physics but simulate our own that is built in. With custom physics we can more arcuately project a projectile as it goes through 3D Space without all the lag. The API for moving a projectile is exposed in this module which allows you to project where your projectile may go before firing. (See Demo place for an example.) SimpleCast also has a Projectile Cache built in to help with optimizations. (Inspired from PartCache) SimpleCast also allows for CustomData to be added into each projectile. (See demo place for an example of this)

Module: SimpleCast [Version: 1.2] - Roblox
Demo Place: SimpleCast Demo Place - Roblox (Place has bouncing balls, and shows how you can visualize where a projectile will go. [check StarterGui and ReplicatedStorage]. Also has some basic replication. )

How to use:

--Local Script
--Require Simplecast and create Settings 
local SimpleCast = require(game.ReplicatedStorage.SimpleCast)

--This is a 'predicate' or 'lambda' that is passed into settings and we can damage players or terminate the cast 
local function onBallHit(self, hitObj: RaycastResult, castData: SimpleCast.CastData, newPosition: Vector3) 		
	self:CastTerminate(castData)
	return
end

local castSettings: SimpleCast.SimpleCastSettings = {
	MaxLifeTime = 5, --LIFETIME IS NOT DISTANCE BUT ACTUALLY HOW LONG IT FLYS FOR
	CacheSize = 50, --INIT CACHE SIZE
	CacheGrowthSize = 10, --GROWTH SIZE
	Gravity = GRAVITY, --GRAVITY CAN BE A VECTOR
	RaycastParam = raycastParams, --ROBLOX'S RAYCASTPARMS
	OnCastHit = onBallHit,
	Data = {
    --CUSTOM DATA
    },
	OnCastTerminate = function(castData: CastData) --FIRE ON CAST TERMINTE
       print("custom data: " .. castData.Data)
       --CLEAN UP OR RESET CUSTOM DATA
    end
}
--Create or get castObject
local ball: BasePart = ...
--Create a caster
local caster = SimpleCast.new(ball, castSettings)

--Fire our caster when Button1Down is pressed
Mouse.Button1Down:Connect(function() 	
	local rootPart = Player.Character.HumanoidRootPart
	local mouseHit = Mouse.Hit + offset
	local direction = (mouseHit.Position - rootPart.Position).Unit
	local velo = direction * SPEED
	local initPos = rootPart.Position

	caster:FireCast(velo, initPos)	
end)

API:

--GetPosition, GetVelocity and FastMag are static functions
GetPosition : (t: number, initVelo: Vector3, initPos: Vector3, gravity: Vector3) -> Vector3,
GetVelocity: (t: number, initVelo: Vector3, gravity: Vector3) -> Vector3,
FastMag: (vector: Vector3) -> number
	
new: (castObj: BasePart, simpleCastSettings: SimpleCastSettings) -> SimpleCastClass,
Raycast: (startPoint: Vector3, endPoint: Vector3) -> RaycastResult | nil,
FireCast: (initVelocity: Vector3, initPosition: Vector3, length: number) -> CastData,
CastTerminate: (castData: CastData) -> (), --PASS CastData to Terminate a projectile 
OnCastMove: (self: any, customData: CastData, oldVec: Vector3, newVec: Vector3) -> ()
Destroy: () -> (),

SimpleCastSettings = {
	MaxLifeTime: number,
	CacheSize: number,
	CacheGrowthSize: number,
	Gravity: Vector3,
	RaycastParam: RaycastParams,
	OnCastHit: (self: any, hitObj: RaycastResult, castData: CastData, newPosition: Vector3) -> (),
	CustomData: any,
	OnCastTerminate: (customData: CastData) -> () --FIRE ON CAST TERMINTE
    OnCastMove: (self: any, customData: CastData, oldVec: Vector3, newVec: Vector3)->(), FIRES AFTER CAST MOVES
}

UPDATE 1.2

  • Casts are no longer tied to FPS
  • Added OnCastMove, runs after cast is moved.

NOTES:
When the caster is created a Pre-Simulation event is connected.

GetPosition(t: number, initVelo: Vector3, initPos: Vector3, gravity: Vector3): Vector3 is the brains behind the movement of this module. GetPosition returns the position at a given time.

GetVelocity(t: number, initVelo: Vector3, gravity: Vector3): Vector3 is the derivative of GetPosition and will return the velocity at a given time.

FastMag(vector: Vector) is just vector.Magnitude but without the square root. Hence the name ‘fast mag’. It is never used in this module but I figured I would include it anyways.

For help on Raycastparms: RaycastParams | Roblox Creator Documentation

I am still working on a few things but overall the API will not change. I am welcome to any suggestions or criticism. I will put a GitHub repo sometime.

I currently use the same methods as PartCache to cache my bullets. I am trying to see if I can find a better way to do it but I think that any other method may be overkill and will not result in better performance that will matter.

If this does not meet your needs I recommend using FastCast @Xan_TheDragon put tons of work into it and it is a great module.

44 Likes

API CHANGE

Changed DataCleanUpLambda to OnCastTerminate. OnCastTerminate still takes a method but it now passes the CastData type. Fires when a cast is terminated still.

4 Likes

A demo video with about 3 thousand projectiles.

External Media
4 Likes

Other than being simpler is there any reason to use this over FC? Such as networking or benchmarking?

Edit: just saw the video, very impressive, but how does the server handle it? Latency, lag etc.

4 Likes

Can it give me this error like in FastCast???

Players.VSCPlays.Backpack.Tool.FastCastRedux.ActiveCast:198: attempt to index nil with 'Raycast'

2 Likes

Probably not. You are not going to get the same errors with SimpleCast as you would with FastCast since they are two different modules.

5 Likes

What is the point of using this plugin when fast cast exists even if it is simpler?

2 Likes

Alternatives or just personal preference. I’d rather use a much simpler module if I’m not already making my own, but it mostly just comes down to what people like the best.

6 Likes

I understand that and after going over the source code of the module it looks like that it was literally just built off fastcast and part-cache code which is actually a good thing.

3 Likes

dumb question: how can I edit the amount of projectiles?

bc rn, I’m just doing

for i=1,50 do
  local initVelo, initPos = fireBall(ZERO)
  BallEvent:FireServer(initVelo, initPos, os.time())
end

2 Likes

Well, I just found out the maker of FastCast left roblox. But like I said in my post if this does not meet you needs use Fastcast its a great module.

3 Likes

This would fire 50 projectiles if SimpleCast is connected to BallEvent.

2 Likes

So, I actually did just realize an issue with how I implemented how my projectiles move over time. Currently if you have low FPS or have an FPS unlocker bullets will go slower or faster. I forgot to take that into account when implementing that part. I am working on a fix but I won’t be able to finish it till Saturday or Sunday. I have an exam coming up so that is where my focus is.

In terms of client to server to other clients it is the same as FastCast. SimpleCast does not handle replication by default. You have to implement it your self. You should see the same performance as you do from FastCast. Once I get SimpleCast off of the FPS issue I will create a demo of a simple replication setup.

1 Like

so I’m guessing that’s the correct method?

1 Like

Yes as long as BallEvent has the caster in it.

1 Like

Benchmark

GPU: Gt 1030 (pretty old)

100 Projectiles:
chart

Fastcast: 8 FPS
Simplecast: 12 FPS

500 Projectiles:
chart (1)

FastCast: 2 FPS
Simplecast: 4 FPS

May or may not be in accurate in some parts

2 Likes

Thank you for the benchmarks! I will do some of my own when I get some free time.

Made an update. Added OnCastMove which fires after a cast is moved. Casts are also no longer tied to FPS.

This is great for those who need something simpler than fastcast.

3 Likes

Thanks!

I’d see how a lot of people would just think this is useless in comparison to fast cast, but I just find fast cast especially tedious to setup for prototyping small stuff.

2 Likes