• 🏆 Texturing Contest #33 is OPEN! Contestants must re-texture a SD unit model found in-game (Warcraft 3 Classic), recreating the unit into a peaceful NPC version. 🔗Click here to enter!
  • It's time for the first HD Modeling Contest of 2024. Join the theme discussion for Hive's HD Modeling Contest #6! Click here to post your idea!

Cam System v3

Updating the description. Give it a second.

Code for the people who're too lazy to test the map.

Camera System
JASS:
//! 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

Keyboard movement
JASS:
//! 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

Keywords:
camera, cam, camera system, cam system, key movement, key arrow, movement, system, 3rd person camera, third person camera
Contents

Cam System v3 (Map)

Reviews
15:34, 28th Nov 2009 TriggerHappy: Decent enough. Approved.
Level 11
Joined
Apr 29, 2007
Messages
826
Hi! Great system, but i noticed that you couldn't go backwards or just turn around by pressing "down" buttom :cry: Otherwise a great system! 9/10

You might be interested in my new version which allows specifying some events for buttons, you can easily make them turn around now.


the BEST cam system I ever seen!!!!! 10000/10000!!! ;P I've tried others and get mad becouse the normal attck will not work. with this cam system you can do that, + its so much better.
Thanks

There are some things I need help with. When I add one of my character in the system (a human priest is the model) and animation 4. but when I walk, the animation does not play. But when I stop walking, the animation starts!? could you help me fix it?
The Priest's animation index for "walk" seems to be "1". I don't know why, some things are quite messed up there.

there is one more thing, where do I change the animation speed? my animation is a little slow I think.
You can't, sry. They are played with the default speed.

Hope you have answers to my questions and thanks for the ultimate camera system :)
No problem!
 
Level 2
Joined
Mar 25, 2008
Messages
11
Haha, do I need your cam system to get your movmentsystem to work? You know i just want the movementsystem, but it dosn't work for me :)
 
Level 2
Joined
Feb 25, 2010
Messages
10
You might be interested in my new version which allows specifying some events for buttons, you can easily make them turn around now.



Thanks


The Priest's animation index for "walk" seems to be "1". I don't know why, some things are quite messed up there.


You can't, sry. They are played with the default speed.


No problem!

Thanks for the help! Another question? Could you make it able to move backwards? :)
 
Level 2
Joined
Feb 25, 2010
Messages
10
Hi!

I've just got a awesome idea!
Maybe you could do so, that if you hold down the backward button, and any of the side buttons, you lock the camera at that angle, but your character starts to move sideways (Witch way depends on if you hold down the right or the left button)

When you release the backward button, it goes back to the normal setting. Would'ent that be cool??? :D
 
Level 4
Joined
Jun 19, 2010
Messages
113
system looks just awesome, but...
i really dont understand how to make it works!

am i must change something in text, or anything else?
well, i just copy trigger in map, and when i try to save it (map) WE shows many-many errors in that trigger :O
and nothing works

hope u understood me
my english makes some people cry


and
yep, me is total noob, i know.

ps
emmm...
or just help me find tutorial or other stuff
i can't find it by myself, ofc D:
 
Level 4
Joined
Jun 19, 2010
Messages
113
thank you, gonna try it.

I suggest you guys to use a GUI system instead. This will most likely be too difficult to archieve something delicious with rarely any knowledge about (v)Jass.

i can not do so.
most of my map is already finished, so i have not much choice there.
 
Level 4
Joined
Jun 19, 2010
Messages
113
look, i have started to make a map from yours. (becouse i have not got to move the trigger to my map)
i dont change anything in your cam or arrow movement trigger, i just push the "save" button, and that what happens...

"
f79887271da1.jpg


errors from nowhere.
after this save map just not work. (at .23 and .24 WC)

"
7daa10df1521.jpg


i do all just like you saying
have download that tool pack (version of helper - 5d), and... thats what happen. errors.
i realy don't know what is the problem, hope you will help me

and would be awesome, if we going to use teamviewer, or something.

emmm.. sorry if i annoying D:
 
Last edited:
Level 4
Joined
Jun 19, 2010
Messages
113
aaaaa..
i have downloaded a full pack of that tool, i was thinking that he is latest
i don't even knooooow
oh god
sorry sorry sorry D:
 
Level 11
Joined
Dec 5, 2009
Messages
846
When i do anyting, like put an unit on the ground or changing anything i can't start the map, only wc3 mainscreen will pop up, what am i doing wrong?
And i have the lastest version of JNPG.
 
Level 17
Joined
Jul 17, 2011
Messages
1,864
the camera should be able to go 360 dgrees around the unit when you press left or right. otherwise this is better than the witcher's system since it overrides the unit's issues order to walk and not attack but then this does not detect destructibles :D
 
Last edited:
Level 3
Joined
Dec 20, 2010
Messages
48
Can anyone please tell me where to place/change this :
JASS:
//! textmacro CAM_INIT_TRIGGER
    local integer i = 0
    loop
        exitwhen i > 9
        call Cam.create(i)
        set i = i+1
    endloop
//! endtextmacro
I've read but don't have any idea where to place/change with this.
Still Great System thought
 
Level 1
Joined
Dec 6, 2012
Messages
3
can someone please explain how to apply this system to my own custom unit.(im new to jass) and yes i have JNGP installed.
 
Top