LSL Object Manipulation

Movement, Rotation & Physics - Master the art of bringing objects to life with dynamic motion and realistic physics in virtual worlds.


Course Code
LSL-202

Level
Intermediate

Duration
4-5 Hours

Certificate
Available

Lead Instructor

Sorin Todys - Advanced LSL Expert

With over 20 years of virtual world development experience, Sorin specializes in physics-based scripting and dynamic object manipulation. All classes take place at our dedicated Alife Virtual School region.

Course Overview

Take your scripting skills to the next level by learning how to make objects move, rotate, and interact with the physics engine!

What You'll Learn

  • Position and rotation fundamentals (vectors and rotations)
  • Moving objects with llSetPos() and llSetLocalPos()
  • Rotating objects with llSetRot() and llTargetOmega()
  • Physics engine integration and llSetStatus()
  • Building elevators and moving platforms
  • Creating smooth animations and transitions
  • Vehicle systems and dynamic movement
  • Performance optimization for moving objects

Learning Objectives

Upon completion, you will be able to:

  • Understand vector mathematics for 3D positioning
  • Move objects smoothly in any direction
  • Create rotation effects and spinning objects
  • Build functional elevators and transport systems
  • Implement physics-based movement
  • Optimize scripts for better performance
  • Create complex multi-object animations
Prerequisites: You should have completed SCR-301: Introduction to Scripting or have equivalent knowledge of LSL basics including variables, functions, events, and states.

Lesson 1: Understanding Vectors and Rotation

Vector Mathematics Fundamentals

In virtual worlds, everything exists in 3D space. To move and rotate objects, you need to understand vectors and rotations.

What is a Vector?

A vector is a set of three numbers representing a position or direction in 3D space:

vector position = ;

// Examples:
vector origin = <0.0, 0.0, 0.0>;        // World center
vector above = <0.0, 0.0, 1.0>;         // 1 meter up
vector forward = <1.0, 0.0, 0.0>;       // 1 meter forward (X axis)
vector sideways = <0.0, 1.0, 0.0>;      // 1 meter sideways (Y axis)
  • X axis: East (+) / West (-)
  • Y axis: North (+) / South (-)
  • Z axis: Up (+) / Down (-)
What is a Rotation?

A rotation is represented by a quaternion - a complex mathematical structure with 4 components (x, y, z, s). Most of the time, you'll use built-in functions instead of calculating these manually.

rotation rot = ;

// Instead of calculating quaternions, use helper functions:
rotation rot_90_z = llEuler2Rot(<0, 0, PI/2>);  // 90° around Z axis
rotation rot_180_x = llEuler2Rot();   // 180° around X axis
rotation rot_45_y = llEuler2Rot(<0, PI/4, 0>);  // 45° around Y axis

Key LSL Functions for Position and Rotation

Function Purpose Example
llGetPos() Get current position vector pos = llGetPos();
llSetPos() Set position (global coords) llSetPos(<128, 128, 25>);
llGetRot() Get current rotation rotation rot = llGetRot();
llSetRot() Set rotation llSetRot(llEuler2Rot(<0,0,PI/2>));
llEuler2Rot() Convert angles to rotation llEuler2Rot(<0, 0, PI/2>);
llRot2Euler() Convert rotation to angles vector angles = llRot2Euler(rot);

Practical Example: Simple Position Movement

// Move object up by 1 meter when touched
default
{
    touch_start(integer num)
    {
        // Get current position
        vector currentPos = llGetPos();
        
        // Move up by adding to Z coordinate
        vector newPos = currentPos + <0, 0, 1.0>;
        
        // Set the new position
        llSetPos(newPos);
        
        llSay(0, "Moved up 1 meter!");
    }
}
Important Limits:
  • llSetPos() can only move objects 10 meters per call
  • For longer distances, you need multiple calls or use llSetRegionPos()
  • Physical objects have different movement constraints

Lesson 2: Smooth Movement and Animation

Creating Smooth Motion with Timers

To create smooth movement, we use timers to move objects in small increments.

// Smooth elevator that moves up and down
vector startPos;
vector endPos;
float moveSpeed = 0.5;  // Meters per second
integer moving = FALSE;
integer goingUp = TRUE;

default
{
    state_entry()
    {
        startPos = llGetPos();
        endPos = startPos + <0, 0, 10.0>;  // 10 meters up
        llSetText("Elevator\nTouch to Call", <1,1,1>, 1.0);
    }
    
    touch_start(integer num)
    {
        if (!moving)
        {
            moving = TRUE;
            llSetTimerEvent(0.1);  // Update every 0.1 seconds
            llSetText("Moving...", <1,1,0>, 1.0);
        }
    }
    
    timer()
    {
        vector currentPos = llGetPos();
        vector targetPos;
        
        if (goingUp)
            targetPos = endPos;
        else
            targetPos = startPos;
        
        // Calculate distance to move this frame
        vector direction = targetPos - currentPos;
        float distance = llVecMag(direction);
        
        if (distance < 0.1)
        {
            // Reached destination
            llSetPos(targetPos);
            llSetTimerEvent(0.0);
            moving = FALSE;
            goingUp = !goingUp;  // Toggle direction
            llSetText("Elevator\nTouch to Call", <1,1,1>, 1.0);
        }
        else
        {
            // Move towards target
            vector moveVector = llVecNorm(direction) * (moveSpeed * 0.1);
            llSetPos(currentPos + moveVector);
        }
    }
}
Understanding the Code:
  • llVecMag() - Returns the length/magnitude of a vector
  • llVecNorm() - Normalizes a vector to length 1.0
  • Timer updates every 0.1 seconds for smooth 10fps movement
  • Movement speed is controlled by moveSpeed variable

Advanced: Linked Prims Movement

// Move entire linkset (all connected prims together)
default
{
    touch_start(integer num)
    {
        // Get root prim position
        vector rootPos = llGetRootPosition();
        
        // Move entire linkset up 5 meters
        llSetLinkPrimitiveParamsFast(LINK_ROOT, [
            PRIM_POSITION, rootPos + <0, 0, 5.0>
        ]);
        
        llSay(0, "Entire object moved!");
    }
}

Lesson 3: Rotation and Spinning Objects

Instant Rotation with llSetRot()

// Rotate object 90 degrees when touched
default
{
    touch_start(integer num)
    {
        // Get current rotation
        rotation currentRot = llGetRot();
        
        // Create a 90-degree rotation around Z axis
        rotation rotateBy = llEuler2Rot(<0, 0, PI/2>);
        
        // Apply the rotation
        llSetRot(currentRot * rotateBy);
        
        llSay(0, "Rotated 90 degrees!");
    }
}

Continuous Spinning with llTargetOmega()

For objects that should spin continuously (like fans, wheels, propellers), use llTargetOmega():

// Spinning fan or propeller
float rotationSpeed = 2.0;  // Rotations per second

default
{
    state_entry()
    {
        // Spin around Z axis at 2 rotations per second
        llTargetOmega(<0, 0, 1>, rotationSpeed * TWO_PI, 1.0);
        llSetText("Spinning Fan", <0,1,1>, 1.0);
    }
    
    touch_start(integer num)
    {
        // Toggle on/off
        if (rotationSpeed > 0)
        {
            llTargetOmega(ZERO_VECTOR, 0, 0);
            rotationSpeed = 0.0;
            llSetText("Fan OFF", <1,0,0>, 1.0);
        }
        else
        {
            rotationSpeed = 2.0;
            llTargetOmega(<0, 0, 1>, rotationSpeed * TWO_PI, 1.0);
            llSetText("Fan ON", <0,1,0>, 1.0);
        }
    }
}
llTargetOmega Parameters:
  • Axis: Vector defining rotation axis (e.g., <0,0,1> for Z-axis)
  • Speed: Radians per second (use TWO_PI for rotations/sec)
  • Gain: Usually 1.0 (affects acceleration)

Smooth Rotation Animation

// Smoothly rotate object to face target direction
rotation targetRotation;
float rotationSpeed = 0.5;  // Radians per second
integer rotating = FALSE;

default
{
    touch_start(integer num)
    {
        // Rotate to face toucher
        key toucher = llDetectedKey(0);
        vector toucherPos = llList2Vector(llGetObjectDetails(toucher, [OBJECT_POS]), 0);
        vector myPos = llGetPos();
        
        // Calculate direction to toucher
        vector direction = toucherPos - myPos;
        
        // Convert to rotation (facing toucher)
        targetRotation = llRotBetween(<1,0,0>, llVecNorm(direction));
        
        rotating = TRUE;
        llSetTimerEvent(0.1);
    }
    
    timer()
    {
        rotation currentRot = llGetRot();
        rotation deltaRot = targetRotation / currentRot;
        
        vector axis;
        float angle;
        llRot2Axis(deltaRot, axis, angle);
        
        if (llFabs(angle) < 0.05)
        {
            llSetRot(targetRotation);
            llSetTimerEvent(0.0);
            rotating = FALSE;
            llSay(0, "Facing you!");
        }
        else
        {
            float stepAngle = rotationSpeed * 0.1;
            if (stepAngle > llFabs(angle))
                stepAngle = llFabs(angle);
            
            rotation stepRot = llAxisAngle2Rot(axis, stepAngle);
            llSetRot(currentRot * stepRot);
        }
    }
}

Lesson 4: Physics-Based Movement

Understanding Physics in LSL

When you enable physics on an object, it becomes affected by gravity, collisions, and forces.

Physics Status Flags
// Enable/disable physics
llSetStatus(STATUS_PHYSICS, TRUE);   // Enable physics
llSetStatus(STATUS_PHYSICS, FALSE);  // Disable physics

// Other useful flags:
llSetStatus(STATUS_PHANTOM, TRUE);   // No collisions
llSetStatus(STATUS_ROTATE_X, FALSE); // Lock X-axis rotation
llSetStatus(STATUS_ROTATE_Y, FALSE); // Lock Y-axis rotation
llSetStatus(STATUS_ROTATE_Z, FALSE); // Lock Z-axis rotation

Applying Forces and Impulses

// Physics-based cannon ball
default
{
    state_entry()
    {
        // Make object physical
        llSetStatus(STATUS_PHYSICS, TRUE);
        
        // Launch upward and forward
        vector force = <10.0, 0.0, 15.0>;  // Forward and up
        llApplyImpulse(force, FALSE);
        
        llSetText("Cannonball!", <1,0.5,0>, 1.0);
    }
    
    collision_start(integer num)
    {
        llSay(0, "BOOM! Hit something!");
        llDie();  // Remove object
    }
}

Controlled Physics Movement

// Simple hover vehicle
float hoverHeight = 1.0;
float thrust = 5.0;

default
{
    state_entry()
    {
        llSetStatus(STATUS_PHYSICS, TRUE);
        llSetBuoyancy(1.0);  // Neutralize gravity
        llSetTimerEvent(0.1);
    }
    
    touch_start(integer num)
    {
        // Apply forward thrust
        vector forceDirection = <1, 0, 0> * llGetRot();
        llApplyImpulse(forceDirection * thrust, FALSE);
    }
    
    timer()
    {
        // Maintain hover height
        vector pos = llGetPos();
        float groundHeight = llGround(ZERO_VECTOR);
        float currentHeight = pos.z - groundHeight;
        
        if (currentHeight < hoverHeight)
        {
            llApplyImpulse(<0, 0, 0.5>, FALSE);
        }
    }
}
Physics Limitations:
  • Physical objects consume more server resources
  • Regions have limits on total physical objects
  • Physics can be unpredictable with complex shapes
  • Use physics only when necessary

Lesson 5: Complete Elevator System

Professional Elevator with Call Buttons

Let's build a complete multi-floor elevator system with call buttons.

Elevator Platform Script:

// Main Elevator Platform Script
list floors;  // List of floor heights
integer currentFloor = 0;
integer targetFloor = 0;
integer moving = FALSE;
float moveSpeed = 2.0;
integer comChannel = -5678;

default
{
    state_entry()
    {
        // Define floor positions (Z heights)
        floors = [0.0, 10.0, 20.0, 30.0];  // 4 floors
        
        // Listen for floor requests
        llListen(comChannel, "", NULL_KEY, "");
        
        llSetText("Elevator\nFloor: " + (string)(currentFloor + 1), <1,1,1>, 1.0);
    }
    
    listen(integer channel, string name, key id, string msg)
    {
        // Commands: "goto_0", "goto_1", "goto_2", "goto_3"
        if (llSubStringIndex(msg, "goto_") == 0)
        {
            targetFloor = (integer)llGetSubString(msg, 5, -1);
            
            if (targetFloor != currentFloor && !moving)
            {
                moving = TRUE;
                llSetTimerEvent(0.1);
                llSetText("Moving to Floor " + (string)(targetFloor + 1), <1,1,0>, 1.0);
            }
        }
    }
    
    timer()
    {
        vector currentPos = llGetPos();
        float targetHeight = llList2Float(floors, targetFloor);
        vector basePos = llGetPos();
        basePos.z = targetHeight;
        
        float distance = llFabs(currentPos.z - targetHeight);
        
        if (distance < 0.05)
        {
            // Arrived at floor
            currentPos.z = targetHeight;
            llSetPos(currentPos);
            currentFloor = targetFloor;
            moving = FALSE;
            llSetTimerEvent(0.0);
            llSetText("Elevator\nFloor: " + (string)(currentFloor + 1), <0,1,0>, 1.0);
            
            // Ding sound
            llPlaySound("elevator_ding", 1.0);
        }
        else
        {
            // Move towards target
            float moveAmount = moveSpeed * 0.1;
            if (moveAmount > distance)
                moveAmount = distance;
            
            if (currentPos.z < targetHeight)
                currentPos.z += moveAmount;
            else
                currentPos.z -= moveAmount;
            
            llSetPos(currentPos);
        }
    }
    
    touch_start(integer num)
    {
        // Manual floor selection
        targetFloor = (currentFloor + 1) % llGetListLength(floors);
        
        if (!moving)
        {
            moving = TRUE;
            llSetTimerEvent(0.1);
        }
    }
}

Call Button Script (place on buttons at each floor):

// Elevator Call Button Script
integer myFloor = 0;  // Change for each floor: 0, 1, 2, 3
integer comChannel = -5678;

default
{
    state_entry()
    {
        llSetText("Call Elevator\nFloor " + (string)(myFloor + 1), <1,1,1>, 1.0);
    }
    
    touch_start(integer num)
    {
        llSay(comChannel, "goto_" + (string)myFloor);
        llSetText("Called!\nFloor " + (string)(myFloor + 1), <0,1,0>, 1.0);
        llSetTimerEvent(3.0);
    }
    
    timer()
    {
        llSetText("Call Elevator\nFloor " + (string)(myFloor + 1), <1,1,1>, 1.0);
        llSetTimerEvent(0.0);
    }
}
Building Tips:
  1. Create the elevator platform prim
  2. Add the main elevator script to the platform
  3. Create call button prims at each floor
  4. Edit myFloor variable in each button (0, 1, 2, 3)
  5. Adjust floor heights in the floors list to match your building

Lesson 6: Performance Optimization

Best Practices for Moving Objects

1. Use Appropriate Timer Intervals
// DON'T: Too frequent
llSetTimerEvent(0.01);  // 100 updates/second - wasteful

// DO: Optimal frequency
llSetTimerEvent(0.1);   // 10 updates/second - smooth enough
llSetTimerEvent(0.2);   // 5 updates/second - good for slow movement
2. Stop Timers When Not Needed
// DON'T: Timer always running
timer()
{
    if (moving)
    {
        // Do movement
    }
    // Timer keeps running even when not moving!
}

// DO: Stop timer when done
timer()
{
    // Do movement
    if (reachedDestination)
    {
        llSetTimerEvent(0.0);  // Stop the timer
        moving = FALSE;
    }
}
3. Use llSetLinkPrimitiveParamsFast()
// DON'T: Slow method
llSetPos(newPos);
llSetRot(newRot);

// DO: Fast method (for child prims)
llSetLinkPrimitiveParamsFast(LINK_THIS, [
    PRIM_POSITION, newPos,
    PRIM_ROTATION, newRot
]);
Memory Management:
  • Avoid storing large lists if possible
  • Use global variables for frequently accessed values
  • Clear listeners when not needed with llListenRemove()
  • Monitor script memory with llGetFreeMemory()

Hands-On Exercises

Exercise 1: Sliding Door

Task: Create a door that slides open sideways when touched and closes after 5 seconds.

Requirements:

  • Door should slide 2 meters to the side
  • Use smooth animation (timer-based)
  • Auto-close after 5 seconds
  • Show "OPEN" or "CLOSED" in floating text

Exercise 2: Spinning Coin

Task: Create a collectible coin that spins continuously and disappears when touched.

Requirements:

  • Spin around Z-axis at 1 rotation per second
  • Slowly bob up and down (0.5 meters)
  • Give points to player on touch
  • Play sound and remove object when collected

Exercise 3: Moving Platform

Task: Create a platform that moves back and forth between two points.

Requirements:

  • Move 10 meters forward, then back
  • Pause for 2 seconds at each end
  • Continuous loop (never stops)
  • Smooth movement at consistent speed

Exercise 4: Teleport Pad

Task: Create a teleport pad that moves an avatar to a destination with a visual effect.

Requirements:

  • Spin the pad when touched
  • Particle effect or glow
  • Teleport avatar to set destination
  • Reset animation after 2 seconds
Hint

Use: llSetLinkPrimitiveParamsFast() for effects and position changes

Exercise 5: Rotating Security Camera

Task: Create a security camera that rotates back and forth scanning an area.

Requirements:

  • Rotate 90 degrees in each direction
  • Pause briefly at each extreme
  • Emit detection beam (particle system)
  • Flash red light when avatar enters range

Challenge: Complete Vehicle

Task: Create a rideable vehicle with forward/backward movement and steering.

Requirements:

  • Physics-based movement
  • Seat for avatar (llSitTarget)
  • Arrow key controls (via permissions)
  • Rotation for steering
  • Speed control (accelerate/brake)
  • Sound effects for engine

Quick Reference Guide

Essential Movement Functions

Function Purpose Example
llSetPos() Set position (10m limit) llSetPos(pos + <0,0,1>);
llSetRegionPos() Set position (no limit) llSetRegionPos(<128,128,50>);
llSetLocalPos() Child prim position llSetLocalPos(<1,0,0>);
llSetRot() Set rotation llSetRot(llEuler2Rot(<0,0,PI/2>));
llTargetOmega() Continuous spinning llTargetOmega(<0,0,1>, TWO_PI, 1.0);
llApplyImpulse() Physics push llApplyImpulse(<0,0,10>, FALSE);

Vector Math Helpers

Function Purpose
llVecMag(v) Get vector length/distance
llVecNorm(v) Normalize to length 1.0
llVecDist(a, b) Distance between two points

Constants

  • PI = 3.14159... (180 degrees)
  • TWO_PI = 6.28318... (360 degrees)
  • PI_BY_TWO = 1.57079... (90 degrees)
  • ZERO_VECTOR = <0, 0, 0>
  • ZERO_ROTATION = <0, 0, 0, 1>

Course Complete!

Congratulations on mastering LSL object manipulation!

You now have the skills to create dynamic, moving, and rotating objects that bring your virtual world to life.

What You've Mastered

  • Vector mathematics and 3D positioning
  • Smooth movement animation
  • Rotation and spinning effects
  • Physics-based movement
  • Complete elevator systems
  • Performance optimization

Next Steps

  • Complete all hands-on exercises
  • Build your own elevator system
  • Experiment with physics vehicles
  • Take LSL-301: Advanced Scripting Techniques
Back to School Home View All Courses