object.face_toward

This function can be used to make one object face toward another. It only affects the object's heading (yaw), not its pitch or roll rotations.

Arguments

other

The object whose rotation should be copied.

x

The X-coordinate of an offset-position. The object will rotate to face other's position plus the offset position. Allowed values are integer constants between -128 and 127, inclusive, where 10 is equal to one Forge unit.

y

The Y-coordinate of an offset-position. The object will rotate to face other's position plus the offset position. Allowed values are integer constants between -128 and 127, inclusive, where 10 is equal to one Forge unit.

z

The Z-coordinate of an offset-position. The object will rotate to face other's position plus the offset position. Allowed values are integer constants between -128 and 127, inclusive, where 10 is equal to one Forge unit.

Example

-- make all WATCHING_YOU objects face toward the nearest player
for each object with label "watching_you" do
   alias nearest_player   = allocate temporary player
   alias nearest_distance = allocate temporary number
   nearest_player   = no_player
   nearest_distance = 30000

   for each player do
      if current_player.biped != no_object then
         alias current_vehicle  = allocate temporary object
         alias current_distance = allocate temporary number

         current_vehicle = no_object
         current_vehicle = current_player.get_vehicle()
         if current_vehicle != current_object then
            --
            -- We don't want to apply this effect to vehicles the player is in, as it 
            -- will turn those vehicles into inoperable beyblades. They'll try to turn 
            -- toward the player, but because the player is attached to whatever vehicle 
            -- they're riding in, they'll be displaced by the turning, which makes the 
            -- vehicle want to turn some more next frame; and so on, non-stop, until 
            -- the player exits the vehicle. Let's avoid that edge-case.
            
            current_distance = current_object.get_distance_to(current_player.biped)
            if current_distance < nearest_distance then
               nearest_distance = current_distance
               nearest_player   = current_player
            end
         end
      end
   end

   if nearest_player != no_player then
      current_object.face_toward(nearest_player.biped, 0, 0, 0)
   end
end

-- make all SPIN_YAW objects rotate on the yaw axis by one degree every frame
-- (60deg per second)
for each object with label "spin_yaw" do
   current_object.face_toward(current_object, 115, -2, 0)
end

-- make all SPIN_ROLL objects rotate on the roll axis by one degree every frame
-- (60deg per second)
--
-- This one is harder because we need to use object attachment and invisible Hill 
-- Markers to compose the rotations we want. The naive approach would be to spawn 
-- disposable Hill Markers, rotate them as needed, and then immediately delete 
-- them all. However, if we try that, then it seems like they get deleted *before* 
-- the rotations actually take effect, and there seem to be negative effects on 
-- game stability as well (as if the map is overloaded). Instead, we need to 
-- keep our Hill Markers around and reuse them.
--
alias roll_global_basis      = allocate global.object
alias unrotated_global_basis = allocate global.object
alias roll_1deg_reference    = allocate global.object
alias helper_marker_1        = allocate global.object
alias helper_marker_2        = allocate global.object
if roll_global_basis == no_object then
   --
   -- There are two rotation values that we really need:
   --
   --  - An object that isn't rotated
   --
   --  - An object that is nose-down, but otherwise not rotated
   --
   -- The former is the default rotation for any newly-created objects. The latter 
   -- can be accomplished by exploiting some jank in `object.place_between_me_and`: 
   -- it happens if you spawn something between an object and itself. We'll create 
   -- two objects with these rotations, then, and keep them around so that our 
   -- other Hill Markers can `copy_rotation_from` them.
   --
   for each object do
      if roll_global_basis == no_object then
         roll_global_basis      = current_object.place_between_me_and(current_object, hill_marker, 0)
         unrotated_global_basis = roll_global_basis.place_at_me(hill_marker, none, none, 0, 0, 0, none)
         
         -- These are recyclable markers that each SPIN_ROLL object can use to set 
         -- up a roll rotation by 1 degree. We'll also use them here, when setting 
         -- up the 1-degree rotation reference.
         helper_marker_1 = unrotated_global_basis.place_at_me(hill_marker, none, none, 0, 0, 0, none)
         helper_marker_2 = unrotated_global_basis.place_at_me(hill_marker, none, none, 0, 0, 0, none)
         
         -- When we're done, this will be an object whose rotation is exactly one 
         -- yaw-degree off from `roll_global_basis`. Right now, it starts off with 
         -- the same rotation as `roll_global_basis`: exactly nose-down, local up 
         -- coinciding with the world positive X-axis.
         roll_1deg_reference = roll_global_basis.place_at_me(hill_marker, none, none, 0, 0, 0, none)
         roll_1deg_reference.copy_rotation_from(roll_global_basis, true)
         
         -- Let's briefly use a more intuitive name for our helper marker.
         alias yaw_adjust = helper_marker_1
         
         yaw_adjust.copy_rotation_from(unrotated_global_basis, true)
         
         -- Now, we'll attach our 1-degree reference to the `yaw_adjust` marker, and 
         -- then rotate the `yaw_adjust` marker by one degree on the yaw axis. From 
         -- the point of view of our nose-down object, this is a roll rotation.
         -- 
         -- Imagine taking a Warthog, turning it nose-down, and placing it on top of a 
         -- turntable. Now imagine you're in the driver's seat. As the turntable rotates, 
         -- from your point of view, you're doing a barrel roll... a barrel ROLL. Get it?
         -- 
         roll_1deg_reference.attach_to(yaw_adjust, 0, 0, 0, relative)
         yaw_adjust.face_toward(yaw_adjust, 115, -2, 0)
         
         roll_1deg_reference.detach()
         --
         -- And now the 1-degree reference is set up! When we actually use it, we'll go 
         -- into more detail about how it works.
         --
      end
   end
end
--
for each object with label "spin_roll" do
   alias roll_marker = helper_marker_1
   alias yaw_to_roll = helper_marker_2
   
   --
   -- Let's recycle our helper markers from above. We'll have them copy the rotations 
   -- we set up before, so we can continue where we left off. (We don't want to use 
   -- the actual rotation markers from earlier, because we need them "fresh" for each 
   -- SPIN_ROLL object we want to spin. Think of the earlier trigger like having Halo: 
   -- Reach press Ctrl + C on some rotations, and now we're having it press Ctrl + V.)
   --
   
   roll_marker.copy_rotation_from(roll_1deg_reference, true)
   yaw_to_roll.copy_rotation_from(roll_global_basis, true)
   
   --
   -- So now, there's only a slight difference between the rotation of roll_marker 
   -- and the rotation of yaw_to_roll: specifically, one degree, along the world's 
   -- yaw axis. Remember what I said above: from the perspective of roll_marker, 
   -- that's going to be one degree of roll, not yaw. So how do we turn one degree 
   -- of marker-relative roll into one degree of current_object-relative roll?
   --
   -- If we attach roll_marker to yaw_to_roll, and then have yaw_to_roll copy the 
   -- rotation of current_object, then there will only be that *same* slight angle 
   -- difference between roll_marker and current_object -- and that difference will 
   -- represent one degree of roll relative to current_object.
   --
   
   roll_marker.attach_to(yaw_to_roll, 0, 0, 0, relative)
   yaw_to_roll.copy_rotation_from(current_object, true)
   roll_marker.detach()

   -- Rotate the current object to match `roll_marker`.
   current_object.copy_rotation_from(roll_marker, true)
end

Notes

See also