Scripting Helpers is winding down operations and is now read-only. More info→
Ad
Log in to vote
1

May someone explain how each part in this script works - line including math.atan2?

Asked by 9 years ago
local player = game.Players.LocalPlayer
repeat wait() until player:GetMouse() and player.Character
local mouse = player:GetMouse()
local character = player.Character

local atan2, pi, dir, torso, torsoPos = math.atan2, math.pi

game:GetService("RunService").RenderStepped:connect(function()
    torso = character:FindFirstChild("Torso")
    if torso then
        torsoPos = torso.Position
        dir = (mouse.Hit.p - torsoPos).unit
        torso.CFrame = CFrame.new(torsoPos) * CFrame.Angles(0, atan2(dir.X, dir.Z) + pi, 0)
    end
end)
0
Use codeblock bro drew1017 330 — 9y
0
Do you know how trigonometric functions and their inverses work? Were you taught that in school? funyun 958 — 9y

1 answer

Log in to vote
0
Answered by
BlueTaslem 18071 Moderation Voter Administrator Community Moderator Super Administrator
9 years ago
local atan2, pi, dir, torso, torsoPos = math.atan2, math.pi

This establishes atan2 as a shorter name of math.atan2 and pi as a shorter name for math.pi.

It also defines dir, torso, and torsoPos as local variables, which is a bad thing -- variables should always be defined in the narrowest scope possible -- they should be defined where they are used, and not before.

game:GetService("RunService").RenderStepped:connect(function()

Do this function, constantly (every time the frame is rendered, which will be approximately 60 times a second)

    torso = character:FindFirstChild("Torso")

Get the Torso in the player's character (which may not exist because they may be dead or not yet spawned)

    if torso then

If the torso does exist (they are alive and spawned)

        torsoPos = torso.Position

save the position of the torso to torsoPos. This just shortens the name from torso.Position.

        dir = (mouse.Hit.p - torsoPos).unit

mouse.Hit.p is the point in space where the mouse is currently hovering.

Subtracting one vector from another gets the displacement between the two -- it's the vector "between" them. Thus B - A is in the direction of B from A. Thus, (mouse.Hit.p - torsoPos) is the way pointing towards the mouse from the torso's position.

You take the .unit because a displacement includes distance, but for directions, we don't want distance usually. In this code the .unit is unnecessary

        torso.CFrame = 

Set the torso's CFrame -- we're going to make it point at the mouse.

            CFrame.new(torsoPos)

this is a CFrame with the default orientation at the same position as Torso. This means it will reset how the torso is rotated, but keep it in the same place.

            * CFrame.Angles(0, atan2(dir.X, dir.Z) + pi, 0)

Multiplying by a CFrame rotates by that amount.

atan2(y, x) gives you the angle between (0, 0)--(1, 0) (the x-axis) and (x, y). Thus, this is the right amount to spin the default CFrame in order to get the torso to face towards the mouse. We have to add pi probably because this is backward.

Rotations are measured in radians, so pi is half of a full revolution.

Slightly Simpler

There's a slightly simpler way to accomplish this.

local flat = Vector3.new(1, 0, 1) -- Something we can use to ignore changes in Y

local toMouse = (mouse.Hit.p - torso.Position)
local toMouseFlat = toMouse * flat

torso.CFrame = CFrame.new(torso.Position, torso.Position + toMouseFlat)

toMouse * flat gets us the direction towards the mouse, but ignores y -- that way the torso only turns side to side, but doesn't look up and down.

CFrame.new(x, y) gives you a CFrame at the position of x facing towards y.

We want to face towards the mouse, but have it at the same y as the torso. torso.Position + toMouseFlat is exactly that:

torso + toMouseFlat = (tx, ty, tz) + (1, 0, 1) * ((mx, my, mz) - (tx, ty, tz)) = (tx, ty, tz) + (mx, 0, mz) - (tx, 0, tz) = (mx, ty, mz).

We could also explicitly construct this:

local p = torso.Position
local m = mouse.Hit.p
torso.CFrame = CFrame.new(p, Vector3.new(m.x, p.y, m.z))

EDIT: After thinking about it, the final way is much clearer.

The method using flat avoids using .x and .y and .z, which usually is cleaner, but in this case it just makes it messy. Further explanation of it:

The flat variable essentially describes only the horizontal parts of a position. When you multiply vectors, you multiply each component. That means the resulting .x and .z will be the same (since * 1) but the resulting .y will be 0 (since * 0).

That means toMouseFlat is in the direction of the mouse from the torso, but is completely flat. We can then look from torso to torso + toMouseFlat, or, in other words, look in the direction of toMouseFlat from the torso.

0
I have two questions: with the flat varialbe, why is 1 set on the x and z and also can you explain the multiplying of to mouseflat variable. Blockeus 68 — 9y
Ad

Answer this question