saw792
Is known to say things. That is all.
- Reaction score
- 280
Camera System
By saw792
By saw792
Code:
First Person Camera System v1.00 by saw792
// -First person camera including:
// -Mouse controlled camera angle (uses trackables)
// -Arrow key movement
// -Lock to unit of your choice, or dummy created by system
// -Can be modified to Third Person by changing a config global
Requirements:
Code:
-Requirements:
// -A vJASS preprocessor (eg: JassHelper, Jass Newgen Pack)
// -Dummy unit with no mode;, no attacks and locust model
// -Trackable model (see import manager of test map)
// -Preplaced rects for walkable areas (see below: Instructions)
Instructions:
Code:
-Instructions for use:
// 1. Convert two empty triggers to custom text, delete all text
// 2. Paste TrackableAPI library into one empty trigger
// 3. Paste FirstPerson library into the other empty trigger
// 4. Identify all areas on map that should be walkable by first person unit
// 5. Create rects in Rect Palette on the inside border of all walkable areas
// NB: Remember! Trackables will only work if there is a clear line of site!
// Keep this in mind when placing rects. The rect borders must be visible
// to the unit in the area. Also, try to place borders between rects on
// top of eachother to prevent areas with no trackable coverage
// 6. Rename all placed rects to FP1, FP2, FP3, FP4 etc (case sensitive)
// 7. Modify Config Global RECT_COUNT below to the number of rects placed
// 8. Modify Config Function RectInit to include a textmacro line for every
// preplaced region (eg: for three rects, copy and paste the runtextmacro
// line twice replacing the second "1" with "2" and the third "1" with "3"
// 9. Use custom script: call EnableFirstPersonForPlayer(player, locked unit,
// x coordinate of dummy, y coordinate of dummy, boolean arrowkey)
// NB: Use null for locked unit to use a dummy created by the system.
// x and y have no effect when locked unit is not null
// Example: Custom Script: call EnableFirstPersonForPlayer(Player(0), null, 0, 0, true)
// -Credits to AceHart for arrow key template
// -Credits to TheHelper members, who generally help with anything you need
// -By saw792 (TheHelper.net, wc3campaigns.net, USWest)
How it works:
The system works by surrounding a set of preplaced regions with trackables at different heights forming four walls around it (not along the ground or the ceiling).. The camera is then locked to a unit within a region. When the mouse moves on the horizon it then is forced to track over a trackable. These track events are all recorded and the camera is adjusted each time based on the distance between the locked unit and the trackable and the angle (both vertical and horizontal angle, adjusting rotation and angle of attack). To allow smooth passing between regions with the arrow key movement the camera is not adjusted when within a certain range of the trackable wall.
The trackable model used is in the shape of a cube, so that the track events are counted from any angle. The density of trackables can be easily modified in the config globals.
A possible extension of this system involves using the hit events of the trackables (ie., when a trackable is clicked) to trigger a gunshot or some other event.
Entire Code:
JASS:
library TrackableAPI
//***************************************************************************
// Trackable API v2.00 by saw792
// -Credits to KaTTana for the basic system
// -Credits to Vexorian for CheckPathability
// -Modified CreateTrackableZ to include terrain height
// -Modified CreateTrackableZ to automatically store
// owner, x, y, and z coordinates
// -Modified CreateTrackableZ to add event to global
// trigger for external use
// -By saw792 (TheHelper.net, wc3campaigns.net, USWest)
//
//***************************************************************************
globals
private gamecache trackstore = InitGameCache("trackcache.w3v")
trigger TrackTrigger = CreateTrigger()
endglobals
private function H2I takes handle h returns integer
return h
return 0
endfunction
private function SetTrackOwner takes trackable t, integer i returns nothing
call StoreInteger(trackstore, I2S(H2I(t)), "owner", i)
endfunction
private function SetTrackableX takes trackable t, real x returns nothing
call StoreReal(trackstore, I2S(H2I(t)), "x", x)
endfunction
private function SetTrackableY takes trackable t, real y returns nothing
call StoreReal(trackstore, I2S(H2I(t)), "y", y)
endfunction
private function SetTrackableZ takes trackable t, real z returns nothing
call StoreReal(trackstore, I2S(H2I(t)), "z", z)
endfunction
function GetTrackOwner takes trackable t returns player
return Player(GetStoredInteger(trackstore, I2S(H2I(t)), "owner"))
endfunction
function GetTrackableX takes trackable t returns real
return GetStoredReal(trackstore, I2S(H2I(t)), "x")
endfunction
function GetTrackableY takes trackable t returns real
return GetStoredReal(trackstore, I2S(H2I(t)), "y")
endfunction
function GetTrackableZ takes trackable t returns real
return GetStoredReal(trackstore, I2S(H2I(t)), "z")
endfunction
function CreateTrackableZ takes string path, real x, real y, real z, real face, player p returns trackable
local location l = Location(x, y)
local destructable d = CreateDestructableZ( 039;OTip039;, x, y, GetLocationZ(l) + z, 0.00, 1, 0 )
local trackable tr = CreateTrackable( path, x, y, face )
call RemoveDestructable( d )
call SetTrackableX(tr, x)
call SetTrackableY(tr, y)
call SetTrackableZ(tr, z)
call SetTrackOwner(tr, GetPlayerId(p))
call TriggerRegisterTrackableTrackEvent(TrackTrigger, tr)
set d = null
call RemoveLocation(l)
set l = null
return tr
endfunction
private function CheckPathabilityTrickGet takes nothing returns nothing
set bj_rescueChangeColorUnit = bj_rescueChangeColorUnit or (GetEnumItem()!=bj_itemRandomCurrentPick)
endfunction
private function CheckPathabilityTrick takes item p, real x, real y returns boolean
local integer i=30
local rect r
call SetItemPosition(p,x,y)
if ((Pow(GetItemX(p)-x,2)+Pow(GetItemY(p)-y,2))<=100) then
return true
endif
set r=Rect(x-i,y-i,x+i,y+i)
set bj_itemRandomCurrentPick=p
set bj_rescueChangeColorUnit=false
call EnumItemsInRect(r,null,function CheckPathabilityTrickGet)
call RemoveRect(r)
set r=null
return bj_rescueChangeColorUnit
endfunction
function CheckPathability takes real x, real y returns boolean
local item it = CreateItem(039;ciri039;,x,y)
local boolean b = CheckPathabilityTrick(it,x,y)
call SetItemVisible(it,false)
call RemoveItem(it)
set it=null
return b
endfunction
endlibrary
JASS:
library FirstPerson initializer Init requires TrackableAPI
//******************************************************************************************
// Config Globals
globals
//Rect globals
private constant integer RECT_COUNT = 1 //Number of preplaced rects
private constant integer TRACK_DENSITY = 25 //Number of trackables along each
//side of a rect
//Camera globals
private constant real CAM_ZOOM = 100 //Change this to change the 'zoom' of the camera
private constant real CAM_DISTANCE = 100 //Increase this to make a third person camera
//Do not decrease below 100
private constant real CAM_HEIGHT = 180 //Change to alter height off the ground
private constant real CAM_MAX_HEIGHT = 400 //Maximum height of camera target
private constant real CAM_MIN_ADJUST_DISTANCE = 300 //Minimum distance locked unit must be for cam to turn
//Arrowkey globals
private constant real ARROW_TIMER_RATE = 0.05 //Timer countdown for arrow key movement
private constant real ARROW_MOVE_SPEED = 600 //Distance moved per second with arrow key held
//Dummy unit globals
private constant integer LOCKED_UNIT_CODE = 039;h000039; //Raw code of dummy unit. Used when no unit
//is set in the Enable function
private constant string TRACK_PATH = "Cube.mdx" //Custom path of trackable model
endglobals
// End Config Globals
// Config Functions
private function RectInit takes nothing returns nothing
private keyword FPRect
//! textmacro RectInit takes INTEGER
set FPRect[$INTEGER$] = gg_rct_FP$INTEGER$
//! endtextmacro
//Copy this line for every preplaced rect you have made, changing the 1 to the appropriate integer.
//! runtextmacro RectInit("1")
endfunction
// End Config Functions
//*******************************************************************************
// Do not edit below here
//*******************************************************************************
globals
private trigger ArrowKeyUp = CreateTrigger()
private trigger ArrowKeyDown = CreateTrigger()
private trigger ArrowKeyLeft = CreateTrigger()
private trigger ArrowKeyRight = CreateTrigger()
private boolean array UpOn
private boolean array DownOn
private boolean array LeftOn
private boolean array RightOn
private keyword Track
private Track array data
private unit array dummy
private rect array FPRect
endglobals
private struct Track
private real x
private real y
private real z
static method create takes player p returns Track
local Track t = Track.allocate()
local real minx
local real maxx
local real miny
local real maxy
local real lx
local real ly
local integer index = 0
loop
set index = index + 1
exitwhen index >= RECT_COUNT + 1
set minx = GetRectMinX(FPRect[index])
set maxx = GetRectMaxX(FPRect[index])
set miny = GetRectMinY(FPRect[index])
set maxy = GetRectMaxY(FPRect[index])
set lx = (maxx - minx) / TRACK_DENSITY
set ly = (maxy - miny) / TRACK_DENSITY
set t.z = 0
loop
set t.x = minx + 1
set t.y = miny + 1
set t.z = t.z + 50
exitwhen t.z >= CAM_MAX_HEIGHT + 50
loop
exitwhen t.y >= maxy - 1
set t.x = minx + 1
call CreateTrackableZ(TRACK_PATH, t.x, t.y, t.z, 0, p)
set t.x = maxx - 1
call CreateTrackableZ(TRACK_PATH, t.x, t.y, t.z, 0, p)
set t.y = t.y + ly
endloop
set t.y = miny + 1
set t.x = minx + 1
loop
exitwhen t.x >= maxx - 1
set t.y = miny + 1
call CreateTrackableZ(TRACK_PATH, t.x, t.y, t.z, 0, p)
set t.y = maxy - 1
call CreateTrackableZ(TRACK_PATH, t.x, t.y, t.z, 0, p)
set t.x = t.x + lx
endloop
endloop
call TriggerSleepAction(0.00) //Included to prevent reaching loop limit
endloop
return t
endmethod
endstruct
function EnableFirstPersonForPlayer takes player p, unit locked, real x, real y, boolean arrowkey returns nothing
if data[GetPlayerId(p)] != null then
call BJDebugMsg("Already enabled")
return
endif
if locked == null then
set dummy[GetPlayerId(p)] = CreateUnit(p, 039;h000039;, x, y, 90)
else
set dummy[GetPlayerId(p)] = locked
call SetUnitFacing(dummy[GetPlayerId(p)], 90)
endif
set data[GetPlayerId(p)] = Track.create(p)
if IsTriggerEnabled(TrackTrigger) == false then
call EnableTrigger(TrackTrigger)
call FogEnableOff()
call FogMaskEnableOff()
endif
if GetLocalPlayer() == p then
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, CAM_DISTANCE, 0)
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, -2.00, 0)
call SetCameraField(CAMERA_FIELD_ZOFFSET, CAM_HEIGHT, 0)
call SetCameraField(CAMERA_FIELD_FIELD_OF_VIEW, CAM_ZOOM, 0)
call SetCameraTargetController(dummy[GetPlayerId(p)], 0, 0, false)
endif
if arrowkey then
call TriggerRegisterPlayerEvent(ArrowKeyUp, p, EVENT_PLAYER_ARROW_UP_DOWN)
call TriggerRegisterPlayerEvent(ArrowKeyDown, p, EVENT_PLAYER_ARROW_DOWN_DOWN)
call TriggerRegisterPlayerEvent(ArrowKeyLeft, p, EVENT_PLAYER_ARROW_LEFT_DOWN)
call TriggerRegisterPlayerEvent(ArrowKeyRight, p, EVENT_PLAYER_ARROW_RIGHT_DOWN)
call TriggerRegisterPlayerEvent(ArrowKeyUp, p, EVENT_PLAYER_ARROW_UP_UP)
call TriggerRegisterPlayerEvent(ArrowKeyDown, p, EVENT_PLAYER_ARROW_DOWN_UP)
call TriggerRegisterPlayerEvent(ArrowKeyLeft, p, EVENT_PLAYER_ARROW_LEFT_UP)
call TriggerRegisterPlayerEvent(ArrowKeyRight, p, EVENT_PLAYER_ARROW_RIGHT_UP)
set UpOn[GetPlayerId(p)] = false
set DownOn[GetPlayerId(p)] = false
set LeftOn[GetPlayerId(p)] = false
set RightOn[GetPlayerId(p)] = false
if IsTriggerEnabled(ArrowKeyUp) == false then
call EnableTrigger(ArrowKeyUp)
call EnableTrigger(ArrowKeyDown)
call EnableTrigger(ArrowKeyLeft)
call EnableTrigger(ArrowKeyRight)
endif
endif
endfunction
private function ArrowUp takes nothing returns nothing
set UpOn[GetPlayerId(GetTriggerPlayer())] = not UpOn[GetPlayerId(GetTriggerPlayer())]
endfunction
private function ArrowDown takes nothing returns nothing
set DownOn[GetPlayerId(GetTriggerPlayer())] = not DownOn[GetPlayerId(GetTriggerPlayer())]
endfunction
private function ArrowLeft takes nothing returns nothing
set LeftOn[GetPlayerId(GetTriggerPlayer())] = not LeftOn[GetPlayerId(GetTriggerPlayer())]
endfunction
private function ArrowRight takes nothing returns nothing
set RightOn[GetPlayerId(GetTriggerPlayer())] = not RightOn[GetPlayerId(GetTriggerPlayer())]
endfunction
private function KeyActions takes nothing returns nothing
local integer i = 0
local real x
local real y
local real a
loop
set x = GetUnitX(dummy<i>)
set y = GetUnitY(dummy<i>)
set a = GetUnitFacing(dummy<i>) * bj_DEGTORAD
if UpOn<i> then
set x = x + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Cos(a)
set y = y + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Sin(a)
if CheckPathability(x, y) then
call SetUnitX(dummy<i>, x)
call SetUnitY(dummy<i>, y)
endif
endif
if DownOn<i> then
set a = a - bj_PI
set x = x + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Cos(a)
set y = y + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Sin(a)
if CheckPathability(x, y) then
call SetUnitX(dummy<i>, x)
call SetUnitY(dummy<i>, y)
endif
set a = a + bj_PI
endif
if LeftOn<i> then
set a = a + (bj_PI / 2)
set x = x + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Cos(a)
set y = y + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Sin(a)
if CheckPathability(x, y) then
call SetUnitX(dummy<i>, x)
call SetUnitY(dummy<i>, y)
endif
endif
if RightOn<i> then
set a = a - (bj_PI / 2)
set x = x + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Cos(a)
set y = y + (ARROW_MOVE_SPEED * ARROW_TIMER_RATE) * Sin(a)
if CheckPathability(x, y) then
call SetUnitX(dummy<i>, x)
call SetUnitY(dummy<i>, y)
endif
endif
if GetLocalPlayer() == Player(i) then
call SetCameraField(CAMERA_FIELD_TARGET_DISTANCE, CAM_DISTANCE, 0)
call SetCameraField(CAMERA_FIELD_ZOFFSET, CAM_HEIGHT, 0)
call SetCameraField(CAMERA_FIELD_FIELD_OF_VIEW, CAM_ZOOM, 0)
endif
set i = i + 1
exitwhen i == 11
endloop
endfunction
private function Actions takes nothing returns nothing
local player p = GetTrackOwner(GetTriggeringTrackable())
local real x = GetTrackableX(GetTriggeringTrackable())
local real y = GetTrackableY(GetTriggeringTrackable())
local real z = GetTrackableZ(GetTriggeringTrackable())
local real x2 = GetUnitX(dummy[GetPlayerId(p)])
local real y2 = GetUnitY(dummy[GetPlayerId(p)])
local real z2 = 180
local real dx = x - x2
local real dy = y - y2
local real d = SquareRoot(dx * dx + dy * dy)
local real dz = z - z2
local real a = Atan2BJ(dz, d)
local real a2 = Atan2BJ(dy, dx)
if d < CAM_MIN_ADJUST_DISTANCE then
return
endif
call SetUnitFacing(dummy[GetPlayerId(p)], a2)
if GetLocalPlayer() == p then
call SetCameraField(CAMERA_FIELD_ROTATION, a2, 0.5)
endif
if a < -1 then
set a = -1
endif
if GetLocalPlayer() == p then
call SetCameraField(CAMERA_FIELD_ANGLE_OF_ATTACK, a, 1)
endif
set p = null
endfunction
private function Init takes nothing returns nothing
local timer t = CreateTimer()
call DisableTrigger(TrackTrigger)
call TriggerAddAction(TrackTrigger, function Actions)
call RectInit()
call TriggerAddAction(ArrowKeyUp, function ArrowUp)
call TriggerAddAction(ArrowKeyDown, function ArrowDown)
call TriggerAddAction(ArrowKeyLeft, function ArrowLeft)
call TriggerAddAction(ArrowKeyRight, function ArrowRight)
call DisableTrigger(ArrowKeyUp)
call DisableTrigger(ArrowKeyDown)
call DisableTrigger(ArrowKeyLeft)
call DisableTrigger(ArrowKeyRight)
call TimerStart(t, ARROW_TIMER_RATE, true, function KeyActions)
endfunction
endlibrary</i></i></i></i></i></i></i></i></i></i></i></i></i></i></i>
Screenshots:
Coming Soon!
Pros:Mouse detection, awesome.
Cons:Lots of configuration
I would appreciate some feedback on how it runs in multiplayer, as I have been unable to test it with anybody else yet. All feedback is welcome.