Triggers

Cam System.w3x
Variables
Cam System
// MAIN TRIGGERS \\
Camera System
Camera Keyboard Movement
// EXAMPLE \\
Example
//TESH.scrollpos=0
//TESH.alwaysfold=0
Name Type is_array initial_value
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! zinc

    library CameraSystem requires optional CameraKeyboardMovement
    {
        //////////////////////////////////////////////////////////////////////////
        //
        //      Configuration area
        
        //          - Just default variables which the system will use when no other ones are specified by the user.
        constant    real    CAMERA_DEFAULT_X        =   0,
                            CAMERA_DEFAULT_Y        =   0,
                            CAMERA_DEFAULT_ZANGLE   =   350,
                            CAMERA_DEFAULT_ZHEIGHT  =   190,
                            CAMERA_DEFAULT_ROTATION =   0,
                            CAMERA_DEFAULT_DISTANCE =   175,
                            
        //          - This is tricky. It defines the weight the measurements of the z position have. This system measures
        //            out 4 locations to get a neat z height, 2 of them are at the unit's location and 2 are at the camera
        //            location which is a bit further away. Those values define which measure has more weight - if you have
        //            low terrain with less cliff heights you should probably give the unit's measurement more weight.
        //            If you don't understand a bit of what I'm trying to explain, just play around a bit with those values
        //            and look what effect they might have.
                            CAMERA_TARGET_WEIGHT    =   1,
                            CAMERA_CAMERA_WEIGHT    =   2 - CAMERA_TARGET_WEIGHT,
        //          - What difference the measures have, if you have really steep cliffs (I'm not talking about blizzard cliffs)
        //            you should probably decrease this.
                            CAMERA_ZDIST_MEASURE    =   50,
                            
        //          - Pretty much self-explaining. You don't really have to change anything here.
                            CAMERA_LOOP_INTERVAL    =   0.01,
                            CAMERA_UPDATE_INTERVAL  =   0.2;
        //////////////////////////////////////////////////////////////////////////
        //
        //      Struct area
        
        public struct CAMERA
        {
        
        //////////////////////////////////////////////////////////////////////////
        //
        //      Struct variable area
        
            public
            {
                real x = CAMERA_DEFAULT_X, y = CAMERA_DEFAULT_Y,
                     zAngle = CAMERA_DEFAULT_ZANGLE, zHeight = CAMERA_DEFAULT_ZHEIGHT,
                     rotation = CAMERA_DEFAULT_ROTATION, distanceToTarget = CAMERA_DEFAULT_DISTANCE;
                
                player applyFor = null;
                unit   toFollow = null;
            }
            
            private
            {
                integer node;
                boolean activated = false;
            
                static timer t = CreateTimer();
                static integer count = 0;
                static thistype data[];
                
                static location loc = Location(0,0);
            }
            
            optional module CameraKeyboardMovement;
            
        //////////////////////////////////////////////////////////////////////////
        //
        //      Struct method area
            
            static method create(player p) -> thistype
            {
                thistype this = thistype.allocate();
                applyFor = p;
                static if (thistype.movementInit.exists) { movementInit(); }
                return this;
            }
            
            method apply()
            {
                if (count == 0)
                    TimerStart(t, CAMERA_LOOP_INTERVAL, true, static method thistype.cameraLoop);
                    
                data[count] = this;
                node = count;
                count += 1;
                
                activated = true;
            }
            
            private static method cameraLoop()
            {
                real tX = 0, tY = 0, tZ[], tzAngle = 0, tzHeight = 0, tRotation = 0;
                thistype this;
                integer i = 0;
                
                while (i < count)
                {
                    this = data[i];
                    static if (thistype.movement.exists) { movement(); }
                    
                    if (toFollow != null)
                    {
                        x = GetUnitX(toFollow); y = GetUnitY(toFollow);
                        tRotation = GetUnitFacing(toFollow)*bj_DEGTORAD;
                        tzHeight = GetUnitFlyHeight(toFollow);
                    }
                    
                    tX = x; tY = y;
                    
                    tX += CAMERA_ZDIST_MEASURE/2 * Cos(tRotation);
                    tY += CAMERA_ZDIST_MEASURE/2 * Sin(tRotation);
                    MoveLocation(loc, tX, tY);
                    tZ[0] = GetLocationZ(loc);
                    
                    tX -= CAMERA_ZDIST_MEASURE * Cos(tRotation);
                    tY -= CAMERA_ZDIST_MEASURE * Sin(tRotation);
                    MoveLocation(loc, tX, tY);
                    tZ[1] = GetLocationZ(loc);
                    
                    tX = GetCameraTargetPositionX() + CAMERA_ZDIST_MEASURE/2 * Cos(tRotation);
                    tY = GetCameraTargetPositionY() + CAMERA_ZDIST_MEASURE/2 * Sin(tRotation);
                    MoveLocation(loc, tX, tY);
                    tZ[2] = GetLocationZ(loc);
                    
                    tX -= CAMERA_ZDIST_MEASURE * Cos(tRotation);
                    tY -= CAMERA_ZDIST_MEASURE * Sin(tRotation);
                    MoveLocation(loc, tX, tY);
                    tZ[3] = GetLocationZ(loc);
                    
                    tZ[2] = ((tZ[0]-tZ[1])*CAMERA_TARGET_WEIGHT+(tZ[2]-tZ[3])*CAMERA_CAMERA_WEIGHT)/4;
                    
                    tX = x; tY = y;
                    
                    tRotation += rotation*bj_DEGTORAD;
                    tX -= (distanceToTarget+tZ[2]) * Cos(tRotation);
                    tY -= (distanceToTarget+tZ[2]) * Sin(tRotation);
                    MoveLocation(loc, tX, tY);
                    
                    tzAngle = zAngle + tZ[2];
                    tzHeight += zHeight + GetCameraField(CAMERA_FIELD_ZOFFSET) + GetLocationZ(loc) + RAbsBJ(tZ[2]) - GetCameraEyePositionZ();
                    
                    if (GetLocalPlayer() == applyFor)
                    {
                        PanCameraToTimed(tX, tY, CAMERA_UPDATE_INTERVAL);
                        SetCameraField(CAMERA_FIELD_ZOFFSET, tzHeight, CAMERA_UPDATE_INTERVAL);
                        SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, tzAngle, CAMERA_UPDATE_INTERVAL);
                        SetCameraField(CAMERA_FIELD_ROTATION, tRotation*bj_RADTODEG, CAMERA_UPDATE_INTERVAL);
                        SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, distanceToTarget+tZ[2], CAMERA_UPDATE_INTERVAL);
                    }
                    
                    i += 1;
                }
            }
            
            method operator active() -> boolean
                { return activated; }
            
            method operator active=(boolean b)
            {
                if (b && !activated)
                    apply();
                else if (!b && activated)
                {
                    data[node] = data[count-1];
                    data[node].node = node;
                    count -= 1;
                    
                    if (count == 0)
                        PauseTimer(t);
                        
                    activated = false;
                }
            }
            
            method destroy()
            {
                if (activated)
                {
                    data[node] = data[count-1];
                    data[node].node = node;
                    count -= 1;
                    
                    if (count == 0)
                        PauseTimer(t);
                }
                
                deallocate();
            }
        }
    }

//! endzinc
//TESH.scrollpos=0
//TESH.alwaysfold=0
//! zinc

    library CameraKeyboardMovement
    {
    
        //CONFIGURABLES
            //How much a unit should turn around when pressing left/right. Leave the * bj_DEGTORAD, or it won't work.
            //Default is the unit's turn speed, if you want to leave that, just set TURN_ANGLE to 0.
            constant real    TURN_ANGLE      = 0 * bj_DEGTORAD;
            //Animation that the unit get's when no key is pressed.
            constant string  ANIM_STOP       = "stand";
            //Default animation of a unit if none is found.
            constant integer ANIM_DEFAULT    = 6;
            
            //Same for this library, because the cam variables are private. (And should stay so)
            constant real    LOOP_INTERVAL   = 0.01,
                             UPDATE_INTERVAL = 0.2;
            
            function CanUnitMove(unit who) -> boolean
            {
                return UnitAlive(who) && !IsUnitPaused(who) && !(GetUnitAbilityLevel(who, 'Bens') > 0) && /*
                  */!(GetUnitAbilityLevel(who, 'Bena') > 0) && !(GetUnitAbilityLevel(who, 'Beng') > 0)     && /*
                  */!(GetUnitAbilityLevel(who, 'BSTN') > 0) && !(GetUnitAbilityLevel(who, 'BPSE') > 0);
            }
        //CONFIGURABLES
    
        CAMERA TriggerCam = -1;
        public CAMERA PlayerCameras[];
        
        public function GetTriggerCam() -> CAMERA
        {
            return TriggerCam;
        }
    
        public module CameraKeyboardMovement
        {
            integer animationIndex = ANIM_DEFAULT;
            real animationDur = 0;
        
            private
            {
                boolean upPressed, downPressed, rightPressed, leftPressed, playAnimation;
                trigger onKeyEvent;
                
                real animationCount = 0;
            }
        
            method movementInit()
            {
                upPressed = false; downPressed = false; rightPressed = false; leftPressed = false; playAnimation = false;
                
                onKeyEvent = CreateTrigger();
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_UP_DOWN);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_UP_UP);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_DOWN_DOWN);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_DOWN_UP);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_RIGHT_DOWN);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_RIGHT_UP);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_LEFT_DOWN);
                TriggerRegisterPlayerEvent(onKeyEvent, applyFor, EVENT_PLAYER_ARROW_LEFT_UP);
                
                PlayerCameras[GetPlayerId(applyFor)] = this;
                
                registerKeyEvent(function()
                {
                    TriggerCam = PlayerCameras[GetPlayerId(GetTriggerPlayer())];
                
                    if (GetTriggerEventId() == EVENT_PLAYER_ARROW_UP_DOWN) {
                        TriggerCam.upPressed = true;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_UP_UP) {
                        TriggerCam.upPressed = false;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_DOWN_DOWN) {
                        TriggerCam.downPressed = true;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_DOWN_UP) {
                        TriggerCam.downPressed = false;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_RIGHT_DOWN) {
                        TriggerCam.rightPressed = true;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_RIGHT_UP) {
                        TriggerCam.rightPressed = false;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_LEFT_DOWN) {
                        TriggerCam.leftPressed = true;
                    } else if (GetTriggerEventId() == EVENT_PLAYER_ARROW_LEFT_UP) {
                        TriggerCam.leftPressed = false;
                    } 
                });
            }
        
            method movement()
            {
                real x, y, ox, oy, facing, movespeed;
                if (CanUnitMove(toFollow))
                {
                    x = GetUnitX(toFollow); y = GetUnitY(toFollow); facing = GetUnitFacing(toFollow)*bj_DEGTORAD;
                    ox = x; oy = y;
                    movespeed = GetUnitMoveSpeed(toFollow);
                
                    if (upPressed && !downPressed)
                    {
                        playAnimation = true;
                        
                        if (rightPressed && !leftPressed)
                        {
                            x += movespeed * LOOP_INTERVAL * Cos(facing - GetUnitDefaultTurnSpeed(toFollow));
                            y += movespeed * LOOP_INTERVAL * Sin(facing - GetUnitDefaultTurnSpeed(toFollow));
                        }
                        else if (!rightPressed && leftPressed)
                        {
                            x += movespeed * LOOP_INTERVAL * Cos(facing + GetUnitDefaultTurnSpeed(toFollow));
                            y += movespeed * LOOP_INTERVAL * Sin(facing + GetUnitDefaultTurnSpeed(toFollow));
                        }
                        else
                        {
                            x += movespeed * LOOP_INTERVAL * Cos(facing);
                            y += movespeed * LOOP_INTERVAL * Sin(facing);
                        }
                            
                        SetUnitPosition(toFollow, x, y);
                        
                        if (RAbsBJ(GetUnitX(toFollow) - x) > 0.5 || RAbsBJ(GetUnitY(toFollow) - y) > 0.5)
                        {
                            SetUnitPosition(toFollow, x, oy);
                            
                            if (RAbsBJ(GetUnitX(toFollow) - x) > 0.5)
                            {
                                SetUnitPosition(toFollow, ox, y);
                                
                                if (RAbsBJ(GetUnitY(toFollow) - y) > 0.5)
                                {
                                    SetUnitPosition(toFollow, x, y);
                                }
                            }
                        }
                    }
                    else
                    {
                        if (playAnimation)
                        {
                            playAnimation = false;
                            SetUnitAnimation(toFollow, "stand");
                        }
                    }
                    
                    if (rightPressed && !leftPressed)
                    {
                        if (TURN_ANGLE == 0)
                        {
                            SetUnitFacingTimed(toFollow, (facing - GetUnitDefaultTurnSpeed(toFollow)) * bj_RADTODEG, UPDATE_INTERVAL);
                        }
                        else
                        {
                            SetUnitFacingTimed(toFollow, (facing - TURN_ANGLE) * bj_RADTODEG, UPDATE_INTERVAL);
                        }
                    }
                    else if (!rightPressed && leftPressed)
                    {
                        if (TURN_ANGLE == 0)
                        {
                            SetUnitFacingTimed(toFollow, (facing + GetUnitDefaultTurnSpeed(toFollow)) * bj_RADTODEG, UPDATE_INTERVAL);
                        }
                        else
                        {
                            SetUnitFacingTimed(toFollow, (facing + TURN_ANGLE) * bj_RADTODEG, UPDATE_INTERVAL);
                        }
                    }
                    
                    animationCount += LOOP_INTERVAL;
                    
                    if (animationCount >= animationDur && playAnimation)
                    {
                        SetUnitAnimationByIndex(toFollow, animationIndex);
                        animationCount = 0;
                    }
                }
            }
            
            method registerKeyEvent(code cb) -> triggeraction
            {
                return TriggerAddAction(onKeyEvent, cb);
            }
            
            method unregisterKeyEvent(triggeraction ta)
            {
                TriggerRemoveAction(onKeyEvent, ta);
            }
        }
    }

//! endzinc

    native UnitAlive takes unit whichUnit returns boolean
//TESH.scrollpos=0
//TESH.alwaysfold=0
library CamExampele initializer init requires CameraSystem

    private function rotate takes nothing returns nothing
        // If the pressed key was down, we will rotate the unit by 180°
        // GetTriggerEventId() returns the id so we can check which arrow was pressed or released.
        if GetTriggerEventId() == EVENT_PLAYER_ARROW_DOWN_DOWN then
            call SetUnitFacing(PlayerCameras[GetPlayerId(GetTriggerPlayer())].toFollow, GetUnitFacing(PlayerCameras[GetPlayerId(GetTriggerPlayer())].toFollow) + 180)
        endif
    endfunction

    private function init takes nothing returns nothing
        local group g = CreateGroup()
        local unit  u
        
        // Creating the camera struct for Player 1 (Red)
        local CAMERA cam = CAMERA.create(Player(0))
        
        // Getting the hero of Player 1
        call GroupEnumUnitsInRange(g, 0, 0, 999999, null)
        loop
            set u = FirstOfGroup(g)
            exitwhen u == null

            if GetUnitTypeId(u) == 'O000' then
                exitwhen true
            endif
            
            call GroupRemoveUnit(g, u)
        endloop
        call DestroyGroup(g)
        
        // Setting the unit which the camera follows to the hero we just found out
        set cam.toFollow = u
        // Change the camera to active
        set cam.active = true
        // This is a member of the keyboard plugin. We have to set a animationIndex (for most units) and a animation duration (for all units).
        // How do you get the index? Seriously. No idea. Play around with numbers from 0 to whatever until you get a good-looking walk
        // animation
        // How do you get the animation duration?
        // Place a unit in the editor, click on it and click through it's animations until you find the walk animation. Write down the duration
        // and you're done.
        set cam.animationDur = 0.733
        
        // Registering a new key event is easy - just like this.
        call cam.registerKeyEvent(function rotate)
        
        // Nulling is cool.
        set g = null
        set u = null
    endfunction
    
endlibrary
Top