Car Crash System

Hi everyone, all I simply want to do is make a system in which if a player hits an object in their car at a fast enough speed or whatever then it essentially just stops working smokes etc… I’m not 100% sure where to start and how to figure out if the car has hit something with enough force. Any ideas, please let me know :smiley:

2 Likes

2 Likes

Hes not asking someone to make him an entire system if you actually red correctly you would see that he said

12 Likes

Oh okay.

1 Like

Hmm, well you could attach a part infront of the car, and calculate the speed of the car and if that part is hit by anything and the car is going at a fast enough speed then loop through the car unanchor all the parts and put smoke and other effects you want in the different parts of the car!

3 Likes

I’m not sure but if you use a vehicle seat, idk if there is a property in that where you can check the current speed. But if it you can use it to check the speed right before it collides with a part, or you can use tick and see how much the humanoid root part is changing in position over time and by that way calculate the speed. Hope it helps

2 Likes

I’m not asking for a whole system to be made, I just want pointers :roll_eyes:

1 Like

Car crashes can be described by classical physics pretty well. In its simplest form, for the purpose of recreating this in a game, you should look at Newton’s laws of motion i.e. law of inertia (car stays in motion until it is acted upon by an external force) and the 1st law of thermodynamics i.e. that the total energy of a system is constant (kinetic energy of a car is transformed into malformation of the car when crashing).

Now we have two basic models to base your script on. Now we just need to check for collisions with objects that would enact a force on the car (e.g. check for collisions with anchored / large models or parts with a great enough mass to damage the car) and then based on the velocity at that impact, we can damage the car to some extent.

Edit:
I got bored and decided to play around with this. In no way is this a finished product, you’ll need to do far more than this, but it’s a start and should give you some idea on how to do this yourself:

Script:

-- local
local function create(obj)
	obj = Instance.new(obj)
	return function (props)
		for prop, val in next, props do
			obj[prop] = val
		end
		return obj
	end
end

-- init
local car = require(script.car_class).new(script.Parent)

-- fires when the car crashes as defined by our MassThreshold and VelocityThreshold properties
car.crashed:connect(function (hit, position, normal, surface, impact)
	-- debug
	print(
		('Our car instance collided with %s\'s %s surface (relative mass %d) at a velocity magnitude of %d studs/second'):format(hit.Name, surface, impact.relativeMass, impact.impactVelocity)
	)
	-- Instantiate our smoke / do any other animations
	create "Smoke" {
		Parent = car:getCar()
	}
end)

car:setMassThreshold(10):setVelocityThreshold(30):getCar().BodyVelocity.Velocity = Vector3.new(0, 0, -50)

Car module class:

-- helpers
local function create(obj)
	obj = Instance.new(obj)
	return function (props)
		for prop, val in next, props do
			obj[prop] = val
		end
		return obj
	end
end

-- init
local car = { }
function car.new(model)
	local this = { }
	this.car             = nil
	this.mass            = nil
	this.bounds          = nil
	this.currentVelocity = nil
	this.lastPosition    = nil
	this.update          = Instance.new 'BindableEvent'
	this.crashed         = this.update.Event
	this.connections     = { }
	this.massThreshold   = 0 --> Determines the minimum relative mass our object needs to be to damage our car
	this.veloThreshold   = 0 --> Determines the minimum velocity we need to be travelling to cause damage => You could alter this to be partly determined by the mass of the object instead
	
	-- local
	local function getMass(part)
		local density = PhysicalProperties.new(part.Material).Density
		local size    = part.Size
		local volume  = size.x * size.y * size.x
		return density * volume
	end
	
	local function recurseMass(obj)
		local mass = 0
		local recurse do
			function recurse(item)
				for i, v in next, item:GetChildren() do
					if v:IsA 'BasePart' then
						mass = mass + getMass(v)
					end
					recurse(v)
				end
			end
		end
		return mass
	end
	
	local function normalToSurface(cf, normal)
		normal = cf:vectorToObjectSpace(normal)
		local x, y, z = normal.x, normal.y, normal.z
		if x ~= 0 and (y == 0 and z == 0) then
			return x > 0 and 'Right' or 'Left'
		elseif y ~= 0 and (x == 0 and z == 0) then
			return y > 0 and 'Top' or 'Bottom'
		elseif z ~= 0 and (x == 0 and y == 0) then
			return z > 0 and 'Back' or 'Front'
		end
		return 'Back'
	end
	
	local function carCollision(hit)
		if not this.currentVelocity then
			return
		end
		if hit and hit.Parent then
			local mass = getMass(hit)
			-- Is it at least the same or more mass than ourselves?
			if mass - this.mass > this.massThreshold then
				-- Are we travelling faster than our threshold velocity for damage to occur?
				if this.currentVelocity.magnitude > this.veloThreshold then
					-- Find the position, normal and surface of the hit to pass back for some kind of impact on that part etc
					local _, collision, normal = game.Workspace:FindPartOnRayWithWhitelist(
						Ray.new(this.bounds.Position, (hit.Position - this.bounds.Position).unit * (hit.Position - this.bounds.Position).magnitude),
						{hit}
					)
					local surface = normalToSurface(hit.CFrame, normal)
					
					-- Perform our crash event
					this:crash(hit, collision, normal, surface, {
						relativeMass   = mass - this.mass,
						impactVelocity = this.currentVelocity.magnitude
					})
				end
			end
		end
	end
	
	-- private
	function this._construct(obj)
		if typeof(obj) ~= 'Instance' then
			return warn 'Unable to instantiate, provide an instance'
		end
		
		-- construct our basic variables and our hit box
		if obj:IsA 'Part' then
			this.mass   = getMass(obj)
			this.bounds = obj
		else
			this.mass = recurseMass(obj)
		
			local cf, size = obj:GetBoundingBox()
			this.bounds = create 'Part' {
				Name         = 'BOUNDING_BOX';
				CanCollide   = false;
				Anchored     = obj.PrimaryPart.Anchored;
				Size         = size;
				Transparency = 1;
				Parent       = obj;
			}
			_ = not this.bounds.Anchored and create 'Weld' {
				Parent = this.bounds;
				Part0  = obj.PrimaryPart;
				Part1  = this.bounds;
				C0     = obj.PrimaryPart.CFrame:toObjectSpace(cf);
			}
		end
		this.car = obj:IsA "Model" and obj.PrimaryPart or obj
		
		if not this.lastPosition then
			this.lastPosition = this.bounds ~= obj and (function () local cf = obj:GetBoundingBox() return cf.p end)() or obj.CFrame.p
		end
		this.connections['joint'] = game:GetService('RunService').Heartbeat:connect(function (delta)
			if not this.car or not this.car.Parent then
				return this:destroy()
			end
			
			-- move our bounding box along with our car if it's anchored
			local cf = this.bounds ~= obj and obj:GetBoundingBox() or obj.CFrame
			if this.bounds ~= obj then
				this.bounds.CFrame = cf
			end
			
			-- set up our velocity determinants
			local pos = cf.p
			this.currentVelocity = (pos - this.lastPosition) / delta
			this.lastPosition    = pos
		end)
		this.connections['collision'] = this.bounds.Touched:connect(carCollision)
		
		return this
	end
	
	-- public
	function this:getMass()
		return this.mass
	end
	
	function this:getCar()
		return this.car
	end
	
	function this:setMassThreshold(val)
		this.massThreshold = val
		return this
	end
	
	function this:setVelocityThreshold(val)
		this.veloThreshold = val
		return this
	end
	
	function this:crash(hit, position, normal, surface, impact)
		-- Remove our listeners
		for i, v in next, this.connections do
			if v then
				v:disconnect()
			end
		end
		if this.bounds ~= this.car then
			this.bounds:Destroy()
		end
		-- Remove our body objects if we're not anchored
		if not this.car.Anchored then
			for i, v in next, this.car:GetChildren() do
				if v:IsA "BodyVelocity" or v:IsA "BodyPosition" or v:IsA "BodyGyro" then
					v:Destroy()
				end
			end
		end
		this.update:Fire(hit, position, normal, surface, impact)
	end
	
	function this:destroy()
		-- Remove all listeners and delete our car
		for i, v in next, this.connections do
			if v then
				v:disconnect()
			end
		end
		if this.car and this.car.Parent then
			this.car:Destroy()
		end
	end
	
	-- construct
	return this._construct(model)
end

return car

Place file: car_collisions.rbxl (22.9 KB)

13 Likes

OP said hes not 100% sure where to start and yes yours might work as intended but it is way to complicated

1 Like

In what way is it too complicated? I’m more than happy to explain the code further if it would help you better understand the code if you’re struggling :slight_smile:

As far as I’m concerned, a script that took me ~20 minutes to write and demonstrates how to implement this in a replicable way, as well as solving several issues that OP would likely have had to return to Scripting Support for isn’t very complicated. Similarly, if you note in my post, I do mention that this code isn’t a finished example and shouldn’t be used as one.

2 Likes

Well I dont think objected oriented programming is what OP was really looking for, more procedural code is what I think he wanted something minimalistic and simple.

1 Like

So the reason you, and the OP, should use OOP is that it provides you with a solution that is easy to maintain and modify. My code, although not a finished product as mentioned, answers the basis of his question:

And clearly demonstrates (1) a method to deetermine if the car has hit something (2) if it has hit it with enough force to damage the car itself as well as (3) how to act upon this event by creating smoke and to stop the car from working - the latter of which is procedural and simple as you may note.

As I have used OOP, OP can examine my code, determine how he would like to change it if he desires to use it as a framework, and modify it to adapt it further into a completed project, or tear out the parts he requires thanks to its OOP nature. I appreciate that it may look complex but in truth, I think for the functionality it currently has, it’s quite a simple solution - OOP doesn’t make it anymore complex, it just provides OP with a solution that be modified and maintained easier, as well as applied to a number of cars in his game without replicating code.

2 Likes

OOP is overrated you dont need it to make efficient functioning code.

1 Like

I appreciate you may think that but this thread is a question by OP on how to make a system that determines whether a car has crashed - you are currently derailing it by debating the functionality and efficiency of OOP vs non-OOP and questioning the functionality of my own solution without truly explaining why and/or providing your own solution. I appreciate you are trying to help but I don’t think our debate over OOP will be of any use to OP unless you make it relevant to his question and/or provide a solution better than the above.

4 Likes

OP has already seen my post and gone about scripting it im just here to inform you on some things

1 Like

Hey! I once browsed looking for a possible way to create something like this before. Your best option to keep it simple and sweet is to create a part named “Collider” or such. This is what we will use to detect when the car comes into collision with something. You will also insert a NumberValue named “Health” and set it’s value to 100 or higher if you wish. Insert some smoke aswell and customise it to your liking and set Enabled to false.

script.Parent.Touched:Connect(function(Hit) -- We use this to detect when our "Collider" hits a part

local Speed = math.floor((script.Parent.Velocity - Hit.Velocity).magnitude) -- Detecting the speed the part is travelling at

if Speed > 30 and not game.Players:GetPlayerFromCharacter(Hit.Parent) and not Hit.CanCollide == false then -- If Speed is above the desired speed you want, and not a Player or a part with CanCollide set to false then do code 

 script.Parent.Health.Value = script.Parent.Health.Value - script.Parent.Velocity.Magnitude / 1.06 -- Takes away "Health" based on the speed

print("You damage your vehicle at a speed of: "..Speed)
end

if script.Parent.Health.Value =< 30 then
script.Parent.Smoke.Enabled = true
end
-- If you want to stop the player from being able to stop driving you can access the DriveSeat and set Disabled to true.

Hope this helps! I’m sure their are many other alternatives you can tackle this idea with, but i found this to be the most simple personally.

6 Likes

Oops, change =< to <= i did a typo.

2 Likes

Let me help further as you seem to be confused, and as I mentioned, we should really keep this relevant to the post.

  1. As you only attach a part to the front of the car, you will only be able to detect head on collisions
  2. Calculating purely the speed is fine but if you don’t account for mass as I have, then the car will break if the front-facing collision detector hits anything incl. players or other small objects that shouldn’t necessarily break a car e.g. a malleable metal bin

I’m not sure where this came from as I never said it was required to make efficient coding. If you mean efficiency in terms of processing power, you are correct that there is a trade off between OOP and procedural coding - OOP provides you with increased modularity and improved programming efficiency (in terms of developer efficiency when coding) but will be slightly slower than procedural due to runtime lookup.

The solution provided is an example, and an example is just that - as I mentioned OP can choose what to take from it. The solution is minimalistic & simplistic as it not only provides OP with a solution that answers his original post, but provides him with a model that calculates collisions based on the bounds of the object (solving the problem in your solution of it only detecting front on collisions) - dealing with both unanchored and anchored cars, as well as providing a deterministic solution to calculating collisions with (1) objects that are of a great enough mass to cause damage (solving the issue with your code where it would break if any object hit it) and (2) if the car is travelling at a great enough velocity.

Similarly, it also provides OP with a mechanism to determine where the collision position is, so that in the future OP could deform the car based on the position, velocity of the crash, and the relative forces thanks to the calculation of masses. To top it off, it also provides OP with a solution that provides him with the surface that the car hit - which would allow him to deform the surface of the object he hit if he so desired in the future.

As you can see, none of this is too complex if you understand the code. Once again, if you or OP do not understand the code I’m more than happy to help, or if you both desire I can rip out the relevant code to make my solution seem less complex to you.

1 Like

You should make it blow up and kill the player if they crash hard enough :wink:

2 Likes

I’m really sorry, I don’t really understand what your code is doing. The fuction?

1 Like