//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