Sign in to follow this  
Jayceon

Custom wheel

Recommended Posts

Hello everyone!

I tried to make custom wheels to vehicles (like tuning element) but i have some problems with code.

When the wheel camber angle is not default, the wheel get not good rotations.

 

local createdCustomWheels = {}

bindKey("f2", "down",
	function()
		local vehicle = getPedOccupiedVehicle(localPlayer)
		
		if vehicle then
			addCustomWheel(vehicle, 1075, "front")
		end
	end
)

addEventHandler("onClientPreRender", root,
	function()
		for vehicle, value in pairs(createdCustomWheels) do
			if vehicle and isElement(vehicle) and isElementStreamedIn(vehicle) then
				local vehicleX, vehicleY, vehicleZ = getElementPosition(vehicle)

				if value["wheel_lf_dummy"] then
					local componentX, componentY, componentZ = getVehicleComponentPosition(vehicle, "wheel_lf_dummy")
					local componentRX, componentRY, componentRZ = getVehicleComponentRotation(vehicle, "wheel_lf_dummy")

					attachElements(value["wheel_lf_dummy"], vehicle, componentX, componentY, componentZ, componentRX, -15 + componentRY, componentRZ)
				end
				
				if value["wheel_rf_dummy"] then
					local componentX, componentY, componentZ = getVehicleComponentPosition(vehicle, "wheel_rf_dummy")
					local componentRX, componentRY, componentRZ = getVehicleComponentRotation(vehicle, "wheel_rf_dummy")
					
					attachElements(value["wheel_rf_dummy"], vehicle, componentX, componentY, componentZ, componentRX, -15 + componentRY, componentRZ)
				end
			end
		end
	end
)

function addCustomWheel(vehicle, wheelId, side)
	if vehicle and wheelId and side then
		local vehicleX, vehicleY, vehicleZ = getElementPosition(vehicle)
		
		if side == "front" then
			local lfX, lfY, lfZ = getVehicleComponentPosition(vehicle, "wheel_lf_dummy")
			local rfX, rfY, rfZ = getVehicleComponentPosition(vehicle, "wheel_rf_dummy")
			
			setVehicleComponentVisible(vehicle, "wheel_lf_dummy", false)
			setVehicleComponentVisible(vehicle, "wheel_rf_dummy", false)
			
			createdCustomWheels[vehicle] = {}
			
			createdCustomWheels[vehicle]["wheel_lf_dummy"] = createObject(wheelId, vehicleX, vehicleY, vehicleZ)
			createdCustomWheels[vehicle]["wheel_rf_dummy"] = createObject(wheelId, vehicleX, vehicleY, vehicleZ)
			
			setElementCollidableWith(createdCustomWheels[vehicle]["wheel_lf_dummy"], vehicle, false)
			setElementCollidableWith(createdCustomWheels[vehicle]["wheel_rf_dummy"], vehicle, false)
			
			setObjectScale(createdCustomWheels[vehicle]["wheel_lf_dummy"], 0.7)
			setObjectScale(createdCustomWheels[vehicle]["wheel_rf_dummy"], 0.7)
			
			attachElements(createdCustomWheels[vehicle]["wheel_lf_dummy"], vehicle, lfX, lfY, lfZ, 0, 0, 0)
			attachElements(createdCustomWheels[vehicle]["wheel_rf_dummy"], vehicle, rfX, rfY, rfZ, 0, 0, 0)
		end
	end
end

 

Share this post


Link to post

You need to lock either Y or X, forgot which. One of them has lean that makes all hell breaks loose when applied.

  • Like 1

Share this post


Link to post

You need to lock the Y component relative to the X component with an offset of -15 or whatever tilt looks good for you. I'll get you an example once I get to test it out.

Edited by myonlake
  • Like 1

Share this post


Link to post

Alright, I managed to figure it out for you. I also included the OOP version.

So, I found out attachElements doesn't have the custom order parameter which allows you to set the order of the rotation. The expected rotation order would be ZYX, in OOP this is not the case however. I am not entirely sure why this is, it might be because of some simple rule but I just don't realize it right now... maybe it's written somewhere in the depths of the Wiki, but I cba to find it right now.

I changed some of the parameters for the addVehicleCustomWheel function to allow tilt and scale upon call. I also added a command /customwheels so you can try it out by typing /customwheels [tilt] [scale]

Anyway, have fun, either one works, whichever you like the best.

I also cleaned up and commented the code just because people might be interested in this, so it's better if this is cleaned up for future reference.

For you specifically, the fix would be to look into the calculateVehicleWheelRotation function, which shows how I've attached the custom wheel to the vehicle. Those contents should replace your attachElements, because attachElements doesn't work, you have to attach manually with position and rotation...

Client-side

-- Table containing vehicles that have custom wheels
local createdCustomWheels = { }

--[[ /customwheels [ number tilt, number scale ]
	 Adds custom wheels to your currently occupied vehicle and optionally applies a tilt angle and wheel scale. ]]
addCommandHandler( 'customwheels',
	function( _, tilt, scale )
		-- Let's get our vehicle
		local vehicle = getPedOccupiedVehicle( localPlayer )

		-- Oh, we have a vehicle!
		if ( vehicle ) then
			-- Let's give it a wheel now
			addVehicleCustomWheel( vehicle, 1075, tilt, scale )
		end
	end
)

-- Let's bind that command to F2 as requested by OP
bindKey( 'f2', 'down', 'customwheels' )

--[[ void addVehicleCustomWheel ( vehicle vehicle, number model [ , number tilt, number scale ] )
	 Adds custom wheels to the vehicle. ]]
function addVehicleCustomWheel( vehicle, model, tilt, scale )
	-- If we've given the object's model number
	if ( tonumber( model ) ) then
		-- Let's delete any old ones
		for _, wheel in pairs( createdCustomWheels[ vehicle ] or { } ) do
			destroyElement( wheel.object )
		end

		-- And let's nil it to be clear
		createdCustomWheels[ vehicle ] = nil

		-- Let's set some component names we want to customize
		local wheels = { 'wheel_lf_dummy', 'wheel_rf_dummy' }

		-- Let's iterate through those components
		for i = 1, #wheels do
			-- Let's hide the existing component
			setVehicleComponentVisible( vehicle, wheels[ i ], false )

			-- Initialize our wheel table
			local wheel = {
				tilt = tonumber( tilt ) or 0, -- We'll default a non-number tilt angle to 0
				name = wheels[ i ], -- Let's store the component name
				object = createObject( model, Vector3( ) ) -- Let's make a new wheel object
			}

			-- Let's set the vehicle as the wheel object's parent
			setElementParent( wheel.object, vehicle )

			-- Let's make sure the wheel is not colliding with the vehicle
			setElementCollidableWith( wheel.object, vehicle, false )

			-- Let's change the scale
			setObjectScale( wheel.object, tonumber( scale ) or 0.7 )

			-- Let's update that original table
			wheels[ i ] = wheel
		end

		-- And let's store all of those wheels now
		createdCustomWheels[ vehicle ] = wheels
	end
end

--[[ void calculateVehicleWheelRotation ( vehicle vehicle, table wheel )
	 Let's calculate the wheel rotation for given wheel(s). ]]
function calculateVehicleWheelRotation( vehicle, wheel )
	-- If we have many wheels in the given argument
	if ( type( wheel ) == 'table' ) and ( #wheel > 0 ) then
		-- Let's iterate through them all
		for i = 1, #wheel do
			-- Let's call the method alone with just the iterator
			calculateVehicleWheelRotation( vehicle, wheel[ i ] )
		end

		-- Let's stop here now
		return
	end

	-- If we have an object
	if ( wheel.object ) then
		-- Let's get the rotation vector of the original component
		local rotation = Vector3( getVehicleComponentRotation( vehicle, wheel.name, 'world' ) )

		-- Let's set our tilt angle
		rotation.y = wheel.tilt

		-- Let's make sure the wheel is at the original component's position
		setElementPosition( wheel.object, Vector3( getVehicleComponentPosition( vehicle, wheel.name, 'world' ) ) )

		-- Let's finally set the rotation (in ZYX order, important!)
		setElementRotation( wheel.object, rotation, "ZYX" )
	end
end

-- Render-time!
addEventHandler( 'onClientPreRender', root,
	function( )
		-- Let's iterate through all the vehicles
		for vehicle, wheels in pairs( createdCustomWheels ) do
			-- If we have a vehicle, it's streamed in and it has wheels
			if ( vehicle ) and ( isElementStreamedIn( vehicle ) ) and ( #wheels > 0 ) then
				-- Let's calculate wheel rotation!
				calculateVehicleWheelRotation( vehicle, wheels )
			end
		end
	end
)

Client-side (OOP)

-- Table containing vehicles that have custom wheels
local createdCustomWheels = { }

--[[ /customwheels [ number tilt, number scale ]
	 Adds custom wheels to your currently occupied vehicle and optionally applies a tilt angle and wheel scale. ]]
addCommandHandler( 'customwheels',
	function( _, tilt, scale )
		-- Let's get our vehicle
		local vehicle = localPlayer:getOccupiedVehicle( )

		-- Oh, we have a vehicle!
		if ( vehicle ) then
			-- Let's give it a wheel now
			vehicle:addCustomWheel( 1075, tilt, scale )
		end
	end
)

-- Let's bind that command to F2 as requested by OP
bindKey( 'f2', 'down', 'customwheels' )

--[[ void Vehicle:addCustomWheel ( number model [ , number tilt, number scale ] )
	 Adds custom wheels to the vehicle. ]]
function Vehicle:addCustomWheel( model, tilt, scale )
	-- If we've given the object's model number
	if ( tonumber( model ) ) then
		-- Let's delete any old ones
		for _, wheel in pairs( createdCustomWheels[ self ] or { } ) do
			wheel.object:destroy( )
		end

		-- And let's nil it to be clear
		createdCustomWheels[ self ] = nil

		-- Let's set some component names we want to customize
		local wheels = { 'wheel_lf_dummy', 'wheel_rf_dummy' }

		-- Let's iterate through those components
		for i = 1, #wheels do
			-- Let's hide the existing component
			self:setComponentVisible( wheels[ i ], false )

			-- Initialize our wheel table
			local wheel = {
				tilt = tonumber( tilt ) or 0, -- We'll default a non-number tilt angle to 0
				name = wheels[ i ], -- Let's store the component name
				object = Object( model, Vector3( ) ) -- Let's make a new wheel object
			}

			-- Let's set the vehicle as the wheel object's parent
			wheel.object:setParent( self )

			-- Let's make sure the wheel is not colliding with the vehicle
			wheel.object:setCollidableWith( self, false )

			-- Let's change the scale
			wheel.object:setScale( tonumber( scale ) or 0.7 )

			-- Let's update that original table
			wheels[ i ] = wheel
		end

		-- And let's store all of those wheels now
		createdCustomWheels[ self ] = wheels
	end
end

--[[ void Vehicle:calculateWheelRotation ( table wheel )
	 Let's calculate the wheel rotation for given wheel(s). ]]
function Vehicle:calculateWheelRotation( wheel )
	-- If we have many wheels in the given argument
	if ( type( wheel ) == 'table' ) and ( #wheel > 0 ) then
		-- Let's iterate through them all
		for i = 1, #wheel do
			-- Let's call the method alone with just the iterator
			self:calculateWheelRotation( wheel[ i ] )
		end

		-- Let's stop here now
		return
	end

	-- If we have an object
	if ( wheel.object ) then
		-- Let's get the rotation vector of the original component
		local rotation = Vector3( self:getComponentRotation( wheel.name, 'world' ) )

		-- Let's set our tilt angle
		rotation.y = wheel.tilt

		-- Let's make sure the wheel is at the original component's position
		wheel.object:setPosition( self:getComponentPosition( wheel.name, 'world' ) )

		-- Let's finally set the rotation
		wheel.object:setRotation( rotation )
	end
end

-- Render-time!
addEventHandler( 'onClientPreRender', root,
	function( )
		-- Let's iterate through all the vehicles
		for vehicle, wheels in pairs( createdCustomWheels ) do
			-- If we have a vehicle, it's streamed in and it has wheels
			if ( vehicle ) and ( vehicle:isStreamedIn( ) ) and ( #wheels > 0 ) then
				-- Let's calculate wheel rotation!
				vehicle:calculateWheelRotation( wheels )
			end
		end
	end
)

 

Edited by myonlake
  • Like 2

Share this post


Link to post
2 minutes ago, Jayceon said:

Big thanks to you. I'm now very happy. Thank you.

You're welcome.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.