Universal Camera Function
For those that have been on the forums for a while you might remember I released a few camera functions back in the day, they were ok but really pretty simple. Keeping with that theme, this camera routine is simple as well, but can be changed easily to provide pretty much any type of camera style you want. Its a little different than just using a function this time round however.
This routine includes 3 parts, the handleCamera function, the setupCamera function, and a TYPE declaration for the camera. Instead of placing parameters in the handleCamera function, you just change the cam's data by way of changing the camera's type information (eg camera.dist# = -100). I find its easier and more effective this way.
So, here's the code;
Camera Type Declaration
TYPE camStat
obj
nxa#,nya#,nza#
nx#,ny#,nz#
dist#,height#
xLoops,yLoops,zLoops
xaLoops, yaLoops, zaLoops
ENDTYPE
GLOBAL camera AS camStat
Camera Setup Function;
FUNCTION setupCamera(obj,dist#,height#,xLoops,yLoops,zLoops,xaLoops,yaLoops,zaLoops)
camera.obj = obj
camera.dist# = dist#
camera.height# = height#
camera.xaLoops = xaLoops
camera.yaLoops = yaLoops
camera.zaLoops = zaLoops
camera.xLoops = xLoops
camera.yLoops = yLoops
camera.zLoops = zLoops
ENDFUNCTION
The parameters are pretty self explanatory, other than the loops ones. Those loops parameters specify how many loops it should take the computer to get the cam's coordinate to it's destination. The x/y/zLoops are for the cam's position, and the xa/ya/zaLoops are for it's angle. Increasing this value will make the travel/turn time longer, decreasing it will make it faster. Setting it to 0 or 1 will make it automatic with no smoothing at all.
Camera Handle Function;
FUNCTION handleCamera()
`Store the camera's destination location
ox# = OBJECT POSITION X(camera.obj)
oy# = OBJECT POSITION Y(camera.obj)
oz# = OBJECT POSITION Z(camera.obj)
`Store the camera's destination angle
oxa# = OBJECT ANGLE X(camera.obj)
oya# = OBJECT ANGLE Y(camera.obj)
oza# = OBJECT ANGLE Z(camera.obj)
`Calculate the camera's new location
camera.nx# = CURVEVALUE(ox#,camera.nx#,camera.xLoops)
camera.ny# = CURVEVALUE(oy#,camera.ny#,camera.yLoops)
camera.nz# = CURVEVALUE(oz#,camera.nz#,camera.zLoops)
`Calculate the camera's new angle
camera.nxa# = CURVEANGLE(oxa#,camera.nxa#,camera.xaLoops)
camera.nya# = CURVEANGLE(oya#,camera.nya#,camera.yaLoops)
camera.nza# = CURVEANGLE(oza#,camera.nza#,camera.zaLoops)
`Orient the camera to it's new angle/location
POSITION CAMERA camera.nx#,camera.ny#+camera.height#,camera.nz#
ROTATE CAMERA camera.nxa#,camera.nya#,camera.nza#
MOVE CAMERA -camera.dist#
ENDFUNCTION
--------------
Using it
Right, using it is pretty simple, other than all of the annoying parameters you need to specify. I think I could get a better point across by just throwing a demo out there, rather than using a bunch of paragraphs, so here's a demo showing how to achieve various common views with the system;
`App setup
SYNC ON:SYNC RATE 0:AUTOCAM OFF:HIDE MOUSE
`Make media
MAKE OBJECT CUBE 1,10
MAKE MATRIX 1,1000,1000,10,10
POSITION MATRIX 1,-500,0,-500
`Declare Cam type
TYPE camStat
obj
nxa#,nya#,nza#
nx#,ny#,nz#
dist#,height#
xLoops,yLoops,zLoops
xaLoops, yaLoops, zaLoops
ENDTYPE
GLOBAL camera AS camStat
`Setup cam as third person
setupCamera(1,50,20,100,10,100,100,100,100)
`main loop
DO
`Object movement
MOVE OBJECT 1, 0.5*(UPKEY()-DOWNKEY())
YROTATE OBJECT 1, WRAPVALUE(OBJECT ANGLE Y(1)-(0.5*(LEFTKEY()-RIGHTKEY())))
`Check for camera mode selection
IF SCANCODE()>1 AND SCANCODE() <=4 THEN key = SCANCODE()-1
`First person camera
IF key = 1
setupCamera(1,0,10,0,0,0,0,0,0)
ENDIF
`Second person camera
IF key = 2
setupCamera(1,0,100,10,10,10,0,0,0)
ENDIF
`Third person camera
IF key = 3
setupCamera(1,50,20,100,10,100,100,100,100)
ENDIF
`handle cam
handleCamera()
`rerotate cam if not in second person mode
IF key = 2 THEN XROTATE CAMERA 90
`text junk
TEXT 0,0,"Universal Camera Routine - by RUCCUS"
TEXT 0,15,"[1] : First Person"
TEXT 0,30,"[2] : Second Person (above)"
TEXT 0,45,"[3] : Third Person"
`refresh screen
SYNC
`repeat
LOOP
`setup cam function
FUNCTION setupCamera(obj,dist#,height#,xLoops,yLoops,zLoops,xaLoops,yaLoops,zaLoops)
camera.obj = obj
camera.dist# = dist#
camera.height# = height#
camera.xaLoops = xaLoops
camera.yaLoops = yaLoops
camera.zaLoops = zaLoops
camera.xLoops = xLoops
camera.yLoops = yLoops
camera.zLoops = zLoops
ENDFUNCTION
`handle cam function
FUNCTION handleCamera()
`Store the camera's destination location
ox# = OBJECT POSITION X(camera.obj)
oy# = OBJECT POSITION Y(camera.obj)
oz# = OBJECT POSITION Z(camera.obj)
`Store the camera's destination angle
oxa# = OBJECT ANGLE X(camera.obj)
oya# = OBJECT ANGLE Y(camera.obj)
oza# = OBJECT ANGLE Z(camera.obj)
`Calculate the camera's new location
camera.nx# = CURVEVALUE(ox#,camera.nx#,camera.xLoops)
camera.ny# = CURVEVALUE(oy#,camera.ny#,camera.yLoops)
camera.nz# = CURVEVALUE(oz#,camera.nz#,camera.zLoops)
`Calculate the camera's new angle
camera.nxa# = CURVEANGLE(oxa#,camera.nxa#,camera.xaLoops)
camera.nya# = CURVEANGLE(oya#,camera.nya#,camera.yaLoops)
camera.nza# = CURVEANGLE(oza#,camera.nza#,camera.zaLoops)
`Orient the camera to it's new angle/location
POSITION CAMERA camera.nx#,camera.ny#+camera.height#,camera.nz#
ROTATE CAMERA camera.nxa#,camera.nya#,camera.nza#
MOVE CAMERA -camera.dist#
ENDFUNCTION
-------
Collision
I know, I said collision in the title, and Ill explain how to get cam collision going, I just didnt put it in the function since theres a lot of ways one could handle collision, and the method used usually depends on the programmer's preference. For example, Id use sparky's dll (which is how im going to explain it), but someone else might not like plugins and shoot for DBP's raycasting, whereas someone else might not use either thinking it may slow their game down too much.
Collision is, however, pretty simple. I wont provide code right now (I will later, but cmon, its christmas morning), but the theory along with my massive collision post stickied in the newcommer's forum should be enough for the time being.
For starters, you need to check if the cam runs into anything as it's moving backwards, and if it does, you need to move the camera closer to the player object to compensate. How do you do that with sparkys? Easy! Just make an invisible sphere, position it at the cam's location, and perform sliding collision on that sphere using the collision rays' starting points being the player's position, and the ending points being the cam's new position.
After that's handled, you'd want to make sure the camera doesnt get covered up by the player model, performing a simple distance check with the player object, you could make the player's object invisible or ghosted if the camera goes too close to the player.
The last collision check you'll need to do involves a raycasting. Send a raycast from the cam's position to the player's position (or vise versa), and if an intersection is detected, move the camera forward by the distance recorded plus a bit (a bit being however far infront of the wall you want the camera positioned). Alternitavely, you could just ghost any objects that go between the camera and the player, it may depend. For example, it might be smart to only ghost small things like other players, while keeping collision for larger things like the map.
And finally, you need to make sure the camera doesnt get stuck. Chances are it wont, but performing one last distance check to make sure the camera isnt too far away, and then repositioning behind the player if it is, is usually good enough.
Thats all for now, time to unwrap presents.
- RUC'