532: Barbarian Invasion Simulation

September 13, 2011 Justin 1.3: Instructional Strategies

Rules of the Game

  • Form up to 4 groups.
  • All prims must be physical. This is essential, because otherwise the collision detection won’t work, and the barbarians will pass right through.
  • No prim can be larger than 2m x 2m x 2m. Plan on stacking your objects. Be aware that the barbarians will try to push your structures or walk around them if they can’t get past, so make sure you cover as much area as you can.
  • Optional: Limit the number of prim types each individual (or group) can use. For example, each user could use up to 3 cubes, 3 pyramids, 3 cylinders, etc.

How to Use the Scripts

Place the two scripts in different objects. The tower script goes in the object the barbarians will advance upon. The barbarian script goes in as many objects as you want, scattered around the tower object. Currently, this simulation only works on a flat surface.

Click the tower object to start the simulation. Touch it again to stop the simulation and send the barbarians back to their original places.

LSL Script for Tower (the object the barbarians move toward)

To adjust the speed of the simulation, modify timerSec. A higher number makes the barbarians advance slower. A lower number makes them advance quicker. Minimum is 0.5 seconds.

float timerSec = 2.0;   // Default timer seconds.

default
{
    state_entry()
    {
    }

    touch_start(integer num)
    {
       // Make sure only the owner can use this.
       if (llDetectedOwner(0) == llGetOwner())
       {
           state activated;
       }
    }
}

state activated
{
    state_entry()
    {
        string speak = (string) llGetPos() + "|" + (string) timerSec;
        llRegionSay(-123, speak);
        llSay(0, "Starting Sim");
    }

    touch_start(integer num)
    {
       if (llDetectedOwner(0) == llGetOwner())
       {
           llRegionSay(-123, "Stop Sim");
           llSay(0, "Stopping Sim");
           state default;
       }
    }
}

LSL Script for Barbarians (position these at varying places around the tower)

// The sideways variable is used when the object can't move forward any more. It keeps track of the last direction the object went and how many interations. 0+ = left, 0- = right. When the object collides with something, it alternates its trajectory by inversing the number, then incrementing the absolute value). When it reaches a maximum amount, it stops.

vector originalPos;
vector destinationPos;
vector basePos;
float movement = 2;        // Movement each step takes
float dx = 0;   // DeltaX
float dy = 0;   // DeltaY
float slope = 0;
float distance = 0;
float timerSec = 1.0;

calcMovement()
{
    vector currentPos = llGetPos();

    basePos.x = destinationPos.x;
    basePos.y = currentPos.y;
    basePos.z = currentPos.z;

    // Determine the slope of the line between the two points.
    slope = (currentPos.y - destinationPos.y) / (currentPos.x - destinationPos.x);

    // Calculate the distance between the two points (Pythagorean theorem).
    float lengthA = llFabs((float) destinationPos.y - (float) basePos.y);
    float lengthB = llFabs((float) basePos.x - (float) currentPos.x);
    distance = llSqrt(llPow(lengthA, 2) + llPow(lengthB, 2));

    // Calculate DeltaX.
    dx = llSqrt(llPow(movement, 2) / (1 + llPow(slope, 2)));

    // Calculate DeltaY (Pythagorean theorem).
    dy = llSqrt(llPow(movement, 2) - llPow(dx, 2));
}

default
{
    state_entry()
    {
        // Listen for commands from the tower.
        llListen(-123, "", "", "");
        originalPos = llGetPos();
        llSetTimerEvent(0);
    }

    listen(integer channel, string name, key id, string message)
    {
       if (message == "Stop Sim")
       {
            llOwnerSay("Retreating!");
            llSetTimerEvent(0);
            vector currentPos = llGetPos();
            while (llGetPos() != originalPos)
            {
                llSetPos(originalPos);
            } 
       }
       else if (message != "")
       {
           originalPos = llGetPos();
           vector currentPos = llGetPos();
            list strlist = llParseString2List(message, ["|"], [""]);
            vector dest = (vector) llList2String(strlist, 0);
            destinationPos.x = dest.x;
            destinationPos.y = dest.y;
           destinationPos.z = currentPos.z;

           if (llList2String(strlist, 1) != "")
           {
                timerSec = (float) llList2String(strlist, 1);
            }

            // Randomly increase or decrease the timer by 0.5, or leave it the same.
            timerSec += llFrand(1.0) - 0.5;
            calcMovement();

           llOwnerSay("Attacking!");

           llSetTimerEvent(timerSec);
       }
    }

    timer()
    {
        vector lastPos = llGetPos();
        vector newPos = lastPos;

        // Determine which direction we need to move, since dx,dy are just absolute values of change.
        if (lastPos.x > destinationPos.x) {
           newPos.x -= dx;
        }
        else {
           newPos.x += dx;
        }

        if (lastPos.y > destinationPos.y) {
           newPos.y -= dy;
        }
        else {
           newPos.y += dy;
        }
        llSleep(timerSec / 2);
        llSetPos(newPos);
    }

    // When a collision starts, immediately back up to the last previous position (-dx, -dy), then move left or right (random) one full movement step. If the collision occurs when moving left or right, back up again. The object cannot travel more than "maxSideways" distance to the left or right.
    collision_start(integer num_detected)
    {
       // Back it up!
       vector lastPos = llGetPos();
       vector newPos = lastPos;

       if (lastPos.x > destinationPos.x) {
           newPos.x -= -dx;
       }
       else {
           newPos.x += -dx;
       }

       if (lastPos.y > destinationPos.y) {
           newPos.y -= -dy;
       }
       else {
           newPos.y += -dy;
       }

       llSetPos(newPos);

       // Try moving either left or right, then resume normal forward direction, toward the destination. We'll need to recalculate the slope and dx,dy for this.
       lastPos = llGetPos();
       newPos = lastPos;
       integer newDirection = 1 + (integer)(llFrand(2));
       if (newDirection == 1)  // Move left
       {
           newPos.x -= -dy;
           newPos.y -= -dx;
       }
       else    // Move right
       {
           newPos.x += -dy;
           newPos.y += -dx;
       }
       llSetPos(newPos);

       // Now we need to recalculate the slope and dx,dy.
       calcMovement();
    }
}

edtech532, game, games, Second Life,


Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Powered by WordPress. Designed by elogi.