How to rotate a model using scripts

Hello, I have a car model, and I want to make it rotate itself, but I don’t know how to do that with scripts. I would like some tutorials or examples. Thank you.

22 Likes

Set a primary part of the model and then change the primary part of the cframe:

For example to rotate the model 90 degrees to the left you would do:

rotation = CFrame.Angles(0, math.rad(90), 0)

modelCFrame = model:GetPrimaryPartCFrame()

model:SetPrimaryPartCFrame( modelCFrame * rotation )

Make sure that the front face of the primary part is facing towards the front of the car.

EDIT: THIS IS NOT LONGER ACCURATE AS SETPRIMARYPARTCFRAME() IS BEING DEPRECATED
Please use Model:PivotTo(targetCFrame) like in the following code and ignore the above code:

rotation = CFrame.Angles(0, math.rad(90), 0)
modelCFrame = model:GetPivot()
model:PivotTo(modelCFrame * rotation)
76 Likes

Thanks, but is there a way to slowly have a transition of rotation? I tried writing this from getting the idea from a YouTube tutorial video, but it doesn’t seem to work.
Here is the script:

wait(5)
script.Parent:SetPrimaryPartCFrame(script.Parent:GetPrimaryPartCFrame() * CFrame.Angles(0, math.rad(90), 0))
3 Likes

Hi yes there is sorry for the late reply. You can do this:

local cframeTween = Instance.new("CFrameValue")
cframeTween.Value = script.Parent:GetPrimaryPartCFrame() -- Starter Cframe

game:GetService("TweenService"):Create(cframeTween, TweenInfo.new(1), {Value = script.Parent:GetPrimaryPartCFrame() * CFrame.Angles(0, math.rad(90), 0)}):Play()

cframeTween:GetPropertyChangedSignal("Value"):Connect(function()
  script.Parent:SetPrimaryPartCFrame(cframeTween.Value)
end)
12 Likes

I would suggest against using supergreatr299’s method because while it absolutely is a valid way to go about this, there is a cleaner one that does not rely on the creation of a ghost tween.

  1. Give your car model a PrimaryPart if it doesn’t have one.
  2. Use constraints (such as weld constraints for parts that do not need to move on their own)
  3. Use TweenService to tween the rotation of the PrimaryPart.CFrame of the model.
local carPrimaryPart = -- insert PrimaryPart here
local TweenService = game:GetService("TweenService")

local carTweenInfo = TweenInfo.new(-- specify duration, etc.)

local newCFrame = carPrimaryPart.CFrame * CFrame.Angles(0, math.rad(90), 0)

local carRotationTween = TweenService:create(carPrimaryPart, carTweenInfo, {CFrame = newCFrame})

carRotationTween:Play()

If you have properly attached all parts of your model to the PrimaryPart, the entire model will rotate smoothly. Hope this helps!

4 Likes

By the meaning of “Specify durations, etc.”, do I put a number? Can you please show me an example? Thanks.

Those are the arguments passed in TweenInfo class constructor method (the new function).
It is as follows: TweenInfo (roblox.com)

TweenInfo.new ( number time = 1.0, Enum easingStyle = Enum.EasingStyle.Quad, Enum easingDirection = Enum.EasingDirection.Out, number repeatCount = 0, bool reverses = false, number delayTime = 0 )

Real example:

local tweenInfo = TweenInfo.new(10, Enum.EasingStyle.Quint, Enum.EasingDirection.Out)

The rest of the arguments are optional.

3 Likes

Thanks, I couldn’t understand what to write. :grinning:

Hi! Did you manage to get this working? :slight_smile:

If not, I’ll show you my secrets haha. I’ve been looking on tweening entire models for ages and have been nearly eating my keyboard before I finally found out how to do this lol. I decided to make a little plug-in for it.

Prerequisites

First step: welding the model

This makes sure that everything will turn with the part we’ll tween in the second step.

  1. Set one part of the model as PrimaryPart.
  2. Now, select the model.
  3. Press the “Weld model” button from your plug-in toolbar.
    image
  4. You should now see that the welds have been created:
    image

Second part: scripting the movement!

I’ll post the script we used in V3 of Go-Karting Xtreme here. You’ll need to modify in order to make it rotate, as this was for a sliding roof from our racing track :slight_smile:

The GameSettings.Track.BigRoof1 stuff just refers to an ObjectValue which refers to the model.

You might also see the name “WeldEndPart” but it’s basically a part which is there so we can easily move it instead of editing the scripts if we ever needed to adjust the tween. You can just put a CFrame there.

--[[
	Name: TrackDoors
	Author: Jonas
	Description: Track Doors API
	
	© 2021 Go-Karting Xtreme
]]

local Services = {
	TweenService = game:GetService("TweenService");
}
local GameSettings = game.ServerScriptService.GameSettings;
local Dependencies = game:GetService("ServerScriptService"):WaitForChild("Dependencies")
local API = {}

local AnimationDuration = 50;

local originalPositions = {};
local currentState = "closed";
local debounce = false;


function openTrack(doorLabel,duration)
	local TweenService = game:GetService("TweenService")
	local Group = doorLabel.value
	local PrimaryPart = Group.PrimaryPart

	local PanelSlideInfo = TweenInfo.new(
		duration,
		Enum.EasingStyle.Quad,
		Enum.EasingDirection.InOut
	)

	local PanelSlideTween = TweenService:Create(PrimaryPart, PanelSlideInfo, {
		CFrame = Group.WeldEndPart.CFrame
	})

	PanelSlideTween:Play()
end

function closeTrack(doorLabel, duration) 
	local TweenService = game:GetService("TweenService")
	
	local Group = doorLabel.value
	local PrimaryPart = Group.PrimaryPart

	local PanelSlideInfo = TweenInfo.new(
		duration,
		Enum.EasingStyle.Quad,
		Enum.EasingDirection.InOut
	)

	local PanelSlideTween = TweenService:Create(PrimaryPart, PanelSlideInfo, {
		CFrame = Group.OriginalPosition.CFrame
	})
	PanelSlideTween:Play()
end
-------------------------------------------------------------------
function API:Open()
	if debounce or currentState == "open" then
		return "debouncing" 
	end;
	
	debounce = true;
	
	-- Smallest parts
	originalPositions["SmallRoof1"] = GameSettings.Track.SmallRoof1.Value.PrimaryPart.CFrame;
	openTrack(GameSettings.Track.SmallRoof1,AnimationDuration);
	originalPositions["SmallRoof2"] = GameSettings.Track.SmallRoof2.Value.PrimaryPart.CFrame;
	openTrack(GameSettings.Track.SmallRoof2,AnimationDuration);
	-- Bigger parts
	originalPositions["BigRoof1"] = GameSettings.Track.BigRoof1.Value.PrimaryPart.CFrame;	
	openTrack(GameSettings.Track.BigRoof1,AnimationDuration);
	originalPositions["BigRoof2"] = GameSettings.Track.BigRoof2.Value.PrimaryPart.CFrame;
	openTrack(GameSettings.Track.BigRoof2,AnimationDuration);
	
	wait(AnimationDuration);
	debounce = false;	
	currentState = "open"
	return "done";
end

function API:Close()
	if debounce or currentState == "closed" then 
		return "debouncing" 
	end;
	debounce = true;

	-- Smallest parts
	closeTrack(GameSettings.Track.SmallRoof1,AnimationDuration);
	closeTrack(GameSettings.Track.SmallRoof2,AnimationDuration);

	-- Bigger parts
	closeTrack(GameSettings.Track.BigRoof1,AnimationDuration);
	closeTrack(GameSettings.Track.BigRoof2,AnimationDuration);
	
	wait(AnimationDuration);
	debounce = false;
	currentState = "closed"	
	return "done";
end


-------------------------------------------------------------------

return API

Make sure to let me know if you have any questions!

Before I forget, you can use CFrame tweening (what was used here) for rotations as well :slight_smile: Refer to the replies above mine for that!

8 Likes

Thanks, but I’m not trying to create a opening door, and I haven’t tried filling out the TweenInfo, so I don’t know if it works. :grinning:

I’m pretty sure SetPrimaryPartCFrame has some floating point issues that cause the model to slightly move apart each time it is called, so you should use PivotTo instead.

It should also work with what you’re trying to do. However, feel free to try out whatever you think fits and keep me posted! :slight_smile:

1 Like

Thanks, it worked for the direction, but it didn’t work the way I wanted it to work. I want the car to actually turn, but it just goes towards the direction, which I set it to 45 degrees.

Maybe, can you help me with this, @supergreatr299?

This is a video showing you my explanation:

Oh yeah I just read up on that, thank you.

1 Like

cant thank you enough bro, need this badly :blue_heart::blue_heart:

What’s crazy is that I essentially did the same thing, but it won’t actually do it?
The same formula works on my other functions but not here…

		local posPivot = GhostObject:GetPivot()
		local orX, orY, orZ = GhostObject:GetPivot():ToOrientation()
		local orYDeg = math.deg(orY)

		if orYDeg >= 0  and orYDeg <= 45 then

			GhostObject:PivotTo(posPivot * CFrame.Angles(0, math.rad(0), 0))

		elseif orYDeg >= 45 and orYDeg <= 90 then

			GhostObject:PivotTo(posPivot * CFrame.Angles(0, math.rad(90), 0))

		elseif orYDeg >= 90 and orYDeg <= 180 then

			GhostObject:PivotTo(posPivot * CFrame.Angles(0, math.rad(180), 0))

		elseif orYDeg <= -45 and orYDeg >= -90 then

			GhostObject:PivotTo(posPivot * CFrame.Angles(0, math.rad(-90), 0))
			
		elseif orYDeg <= 0 and orYDeg >= -45 then
			
			GhostObject:PivotTo(posPivot * CFrame.Angles(0, math.rad(0), 0))

		end

Managed to fix it, just had to remove the posPivot.