Camera control. I'm going bald...
Blitz3D Forums/Blitz3D Programming/Camera control. I'm going bald...
| ||
... With all the hair-pulling this conundrum's induced in me. =P Okay, so, I'm trying to figure out 3rd person camera control. The player moves freely through the levels, and the camera rotates smoothly around the player. The current control system uses the 200/3/5/8 arrow keys. Now, here's the deal: I've found a lot of movement & camera tracking examples, but all of them use the same system: Up to move forward, while Left & Right TURN the player entity left & right. I need a standard, console-style, free-range control system, like you might get in Spyro, Dr. Muto, Mario64, all that. I found a Mario64 demo in the codearcs, but it still used that same L/R turn method. Basically, I need the following system: -Up makes the player move away from the camera -Down makes the player turn 180 & move towards the camera -Left & Right make the player turn 90/-90 & move to the left or right screen edge, with the camera following -WASD control the camera itself, allowing it to move around the player Of course, no matter what way the player's facing, the camera is always moving to get behind the player. This means that, for instance, if you hold down Left, the player will travel to the left, but also in a curve, eventually ending up where they started from. I've looked everywhere; the codearcs, forums, tutorial section, I've even done advanced searches. Nothing. Any ideas? I REALLY need some help, since I've now tried everything I can think of. Thanks! |
| ||
did u try: ? it doesnt work. but u get the idea :) good luck on ur project! :) ~DS~ |
| ||
Thanks DSW; yeah, I've tried that, I've tried pivot methods, I've tried AlignToVector()... I'm out of ideas by now. T_T Thanks anyway! |
| ||
Try creating a pivot and making the player chase the pivot with a bit of slack, same philosphy as a chasecam. You'll have two chases going on...the player chasing the pivot and the camera chasing the player. |
| ||
Tried that. My last method used two pivots, one for the camera, and one for its target position. The camera's target was a child of the player's mesh entity, and positioned at 0,5,-13 relative to it. The camera was always pointing at the player, while the camera's pivot was always pointing at, and moving towards, the camera's target position. That method worked fine for following the player, but when it came to actually turning the player, things got crazy. It always made the camera come too close to the player, thus causing the player to turn too tightly... I dunno. I'm totally lost by now. |
| ||
Here's the closest I got to achieving my goal: You can see for yourself how it won't work. I used the wheel code from Mark Sibly's "driver.bb" demo, in the B3D samples. The terrain heightmap and texture are from the same demo. This demo from Stevie G is pretty close to what I need: The only problem here is that the camera stays statically in whatever position it's placed by the user. In other words, if you turn in this demo, the camera doesn't move back behind you as I need it to. |
| ||
U mean like a Shadow of the Colossus cam? |
| ||
Erm... Maybe? Heh, I've never played Shadow of the Colossus. Some games that I know of that use this common (I think) camera system are: -Jak & Daxter, Jak II & III -Spyro 1, 2 & 3 -Sly Cooper -Dr. Muto That's all I can think of off the top of my head right now, but I know there are others; a lot of free-roaming console games use it. |
| ||
I changed the SuperCam function I found on blitch just a tiny bit... It follow and turns like you would want it to. For the first three parameters you need a Camera Pivot for the camera (not parented) Point is the thing you follow, the entity Function Camera_Follow(camera,camera_pivot,point,camera_speed#,distance#,height#,xrot#,tilt#) Local cx#,cy#,cz# Local TempYaw# = EntityYaw(camera) TFormPoint 0,height#,-distance#,point,0 cx = (TFormedX() - EntityX(camera)) * camera_speed# cy = (TFormedY() - EntityY(camera)) * camera_speed# cz = (TFormedZ() - EntityZ(camera)) * camera_speed# TranslateEntity camera_pivot,cx,cy,cz PositionEntity camera,EntityX(camera_pivot,1),EntityY(camera_pivot,1),EntityZ(camera_pivot,1),1 TurnEntity camera,0,DeltaYaw(camera,point)*.3,0 RotateEntity camera,xrot#,EntityYaw(camera),tilt# End Function and to move your Point/entity in the right direction after you turn it you can use this TFormVector 0,0,.1,Point,0 X# = X + TFormedX() Z# = Z + TFormedZ() TranslateEntity Point,X,0,Z,1 I kind of know what the TFormVector does, it's just harder to explain it than it is to use it. You input how far you want to go, into the x,y,z parameters. The numbers that you get in the TFormedX,Y,Z commands, depends on which way you are facing. It splits the numbers between each TFormed command to make you move in a certain direction when you use TranslateEntity. |
| ||
Thanks GIA... I'm not sure exactly where to put this in my program, but I'll try to figure it out & give it a try! |
| ||
you put it under wend end and u call it in while not keyhit(1) graphics3d 800,600,0,2 piv=createpivot() cam=createcamera(piv) OR cam=createcamera() piv=createpivot(cam) point=0.1 ;? speed# = .1 distance# = .1;? height# = .4 xrot# = entitypitch(cam) tilt# = .1 while not keyhit(1) Camera_Follow(cam,piv,point,camera_speed#,distance#,height#,xrot#,tilt#) updateworld() renderworld() flip wend end Function Camera_Follow(camera,camera_pivot,point,camera_speed#,distance#,height#,xrot#,tilt#) Local cx#,cy#,cz# Local TempYaw# = EntityYaw(camera) TFormPoint 0,height#,-distance#,point,0 cx = (TFormedX() - EntityX(camera)) * camera_speed# cy = (TFormedY() - EntityY(camera)) * camera_speed# cz = (TFormedZ() - EntityZ(camera)) * camera_speed# TranslateEntity camera_pivot,cx,cy,cz PositionEntity camera,EntityX(camera_pivot,1),EntityY(camera_pivot,1),EntityZ(camera_pivot,1),1 TurnEntity camera,0,DeltaYaw(camera,point)*.3,0 RotateEntity camera,xrot#,EntityYaw(camera),tilt# End Function hope this helps :) ~DS~ |
| ||
Not sure if this is what you meant, but I wrote this yesterday based on your explaination: |
| ||
Geez, Warner, you actually wrote a whole program for me?! Thank you SO MUCH! Anyway, that's almost it, except for one thing: the cone doesn't keep turning. In other words, when you hit, for instance, Left, the cone turns to the left. But if you keep holding Left, the cone doesn't keep turning; instead, it keeps moving in the same direction, until the camera is behind it, making it look like it's moving forward (which should only happen when Up is pressed.) |
| ||
I know what you want. It's also throughout various N64 games. I guess it just needs a bit more of a technical description: you want the player to move left or right but in relation to the camera's rotation. Front or Back will always be towards\away from camera (not just positive Z, negative Z), and Left and Right will always be related to the camera's Local X axis, and not only will he turn in that direction but also walk in it. So, for knowing the direction you'd have to go when the user presses Left, you'd use something like... Speed#=2.0 TFormVector -Speed,0,0,Camera,0 ;We are using "-Speed" because the user is pressing LEFT. MoveEntity Player,TFormedX(),TFormedY(),TFormedZ() RotateEntity Player,EntityPitch(Player,True),EntityYaw(Camera,True)-90,EntityRoll(Player,True) ;The above should turn the player in the left direction in relation to the camera, albeit a little ;snappy. You'd need to give it a smoothing factor for it to be smoothier. ;(something like (EntityYaw(Camera,True)-EntityYaw(Player,True)*0.1-90) In this system, if the player keeps the Left key pressed down, for example, the character would constantly be walking in a complete circle counter-clockwise. The camera would be sitting in the middle of this circle [not that it is relevant, but the radius of this circle would be the distance of the player to the camera]. |
| ||
Hmmmm... *strokes chin where beard would be* This might be just what I'm looking for, Kryzon; I'll try this ASAP! Thanks!!! |
| ||
Great! I'm just not sure about the RotateEntity part, you'll have to work a bit there. But for the rest, i'm positive it's the same effect as in console games: he's walking using the camera as reference, as "origin". You'll also have to incorporate one of those camera schemes that are around the code archives (also in the Castle sample). Also, you'll need different TFormVector checks for each of the KeyDowns (Up,Down,Left,Right - like, for down, for example, you'd use TFormVector 0,0,-Speed,Camera,0, going on the negative Z using the camera as reference), as I only showed how you'd do it using the Left key. (I remember playing some N64 games, and when you were moving your character forward and then turned the camera around him using the C-Buttons, for example, he'd go forward but on another direction - you could even control his direction just by moving him forward constantly and then turning the camera to where you wanted him to go) Good luck, and make sure to inform us of your success! |
| ||
Oh, believe me, when this game's done, everyone here'll be the first to know! It's not a marketable game, just a fan work, but still... ^_^ |
| ||
can u release source? ^^ that would be awesome! :) |
| ||
I'd like an example of this camera code when its fixed. my camera is freakin out again. *sigh* |
| ||
Okay, I'll try & cobble together a more usable version; right now it's customized specifically for me. |
| ||
heres what im useing;--camera physics-- PositionEntity cam_piv,EntityX(player),EntityY(player),EntityZ(player) PositionEntity cam,EntityX(cam_piv),EntityY(cam_piv),EntityZ(cam_piv) RotateEntity cam,0,EntityYaw(cam_piv),0 MoveEntity cam,0,5,-20 tmp_yaw=EntityYaw(cam_piv) tmp_yaw2=EntityYaw(player) If tmp_yaw<0 Then tmp_yaw=tmp_yaw+360 If tmp_yaw2<0 Then tmp_yaw2=tmp_yaw2+360 If cam_active=True Then If tmp_yaw2<tmp_yaw-180 Then TurnEntity cam_piv,0,1,0 ElseIf tmp_yaw2>tmp_yaw+180 Then TurnEntity cam_piv,0,-1,0 ElseIf tmp_yaw2>tmp_yaw Then TurnEntity cam_piv,0,1,0 ElseIf tmp_yaw2<tmp_yaw Then TurnEntity cam_piv,0,-1,0 End If End If it needs a little work but it works how you want apart from the player does not turn smoothly |
| ||
Did u get the code yet? |
| ||
I'm working on it, just hold tight... AAAGH, so much to DOOO... O_o |
| ||
Lol, dont worry. I know how u feel. I have loads to do too. and very little time ~DS~ |
| ||
Here ya go buddy! I put in as many comments as I could to make it well-documented. You said you learn best by hands-on experience with full code, so this is a working demo that you can run as soon as you download it. The important, reusable parts in this code are the part that creates the main camera & its pivot, and the two functions, UpdateCamera() and UpdatePlayer(). It's not perfect by any means... You'll notice this particularly when you press & hold Down, as the player will move toward the camera, but at a slight angle, and vibrating. I'm still not sure why. Anyway, hope this helps! |
| ||
Thanks mate! :) In return, I added jump and gravity + collision Graphics3D 800,600,0,2 Collisions 1,2,2,3 Global Gravity#,Jump# SeedRnd MilliSecs() Global Player = CreateSphere();Placeholder mesh for the player PositionEntity Player,0,1,0 EntityRadius Player,.1 EntityType Player,1 Global Speed# Global PlayerTex = CreateTexture(64,64);The player's texture ;Just some basic graphics so you can see which way the player's ;facing. The front is blue, the back is black, plus some red lines ;to show the axes. SetBuffer TextureBuffer(PlayerTex) Color 0,0,255 Rect 0,0,64,64 Color 0,0,0 Rect 16,0,32,64 Color 255,0,0 Line 0,0,0,63 Line 15,0,15,63 Line 31,0,31,63 Line 47,0,47,63 Line 0,31,63,31 EntityTexture Player,PlayerTex ;!IMPORTANT - The main camera & its pivot MUST be created like this, ;!or it won't work. ;------------------------------------------------------------------- ;The main camera's pivot. This does all the movement & turning, NOT ;the main camera; the camera itself stays in place, relative to this ;pivot. ;This must be a child of the Player's main entity. REMEMBER that ;this means that the pivot's position & rotation is relative to the ;player, NOT to the 3D world. Global MainCameraPivot = CreatePivot(Player) ;This isn't necessary, it's just to give a nice pan-rotate effect ;when the program starts. RotateEntity MainCameraPivot,0,180,0 ;------------------------------------------------------------------- ;The main camera itself, done for the primary rendering of the game. ;This must be a child of MainCameraPivot. Global MainCamera = CreateCamera(MainCameraPivot) CameraViewport MainCamera,0,0,GraphicsWidth(),GraphicsHeight() ;You can change these coordinates to change the angle & distance of ;the main camera. REMEMBER, the coordinates are relative to ;MainCameraPivot, NOT to the 3D world! PositionEntity MainCamera,0,5,-13 CameraClsColor MainCamera,0,0,255;Nicer than plain ol' black. ;) ;------------------------------------------------------------------- Global Light = CreateLight() Global Ground = CreatePlane();Self-explanatory EntityRadius Ground,.1 EntityType Ground,2 PositionEntity Ground,0,-1,0 Global GroundTex = CreateTexture(64,64) ;A grid so you can see the orientation of the ground SetBuffer TextureBuffer(GroundTex) Color 0,128,255 Rect 0,0,64,64,0 ScaleTexture GroundTex,2,2 EntityTexture Ground,GroundTex ;... And now for something completely different ;Some random scenery to give you an idea of your speed & such For i = 0 To 100 Local CurrentBall = CreateSphere() PositionEntity CurrentBall,Rand(-100,100),Rand(3,10),Rand(-100,100) Next SetBuffer BackBuffer() While Not KeyHit(1) If EntityCollided( Player, 2 );Player is on the ground, so reset gravity. Gravity = 0 ;Remember, it's no good letting the player jump in midair - they have to be able to jump ;only when they're on the ground. If KeyHit(57);Spacebar Jump = 2;Makes the player jump by moving upwards 2 units per update. EndIf Else;Player is in the air, so start the fall. ;2 units is a nice top speed for gravity. Remember, you can change .04 as needed to change the ;speed of acceleration. Also remember, gravity moves you DOWN, so it has to be a negative ;number. If Gravity > -2 Then Gravity = Gravity - .04 EndIf ;This decreases the power of the jump, allowing the player to fall back down. ;You can change .04 to other values to make the jumps longer or shorter. If Jump > 0 Then Jump = Jump - .04 ;Finally, we move the player up and down according to the power of the jump and the power of gravity. TranslateEntity Player, 0, Jump + Gravity, 0 Cls UpdateCamera UpdatePlayer UpdateWorld RenderWorld Flip Wend End Function UpdateCamera() ;If A or D are pressed, then the player is moving the camera ;manually, so the main camera's pivot (NOT the camera itself) turns ;right or left, respectively. The camera, being a child of its ;pivot, follows automatically. ;If neither A or D are pressed, however, then the camera's pivot ;attempts to re-center itself behind the player by moving its Yaw ;back to 0. If KeyDown(30);A TurnEntity MainCameraPivot,0,-2,0 ElseIf KeyDown(32);D TurnEntity MainCameraPivot,0,2,0 Else;Re-center the camera, but smoothly ;Here's the deal with the "If Not KeyDown()" thing. When the player ;presses Down, the player's entity must move straight towards the ;camera. If, at this point, the camera's pivot still tried to re- ;center itself, the player would turn while moving, which isn't ;supposed to happen. The If statement is here so that, if Down is ;the only key pressed, the camera's pivot doesn't try to re-center. If Not KeyDown(208) ;If the pivot's Yaw is more than 5 degrees above or below 0, it ;turns by 3 degrees. If it's closer to 0 than 5 degrees, though, ;it turns by a tenth of the remaining degrees, giving a smooth ;"deceleration" effect. If EntityYaw(MainCameraPivot) > 5 TurnEntity MainCameraPivot,0,-3,0 ElseIf EntityYaw(MainCameraPivot) < -5 TurnEntity MainCameraPivot,0,3,0 Else TurnEntity MainCameraPivot,0,-EntityYaw(MainCameraPivot) / 10,0 EndIf Else If KeyDown(203) Or KeyDown(205) If EntityYaw(MainCameraPivot) > 5 TurnEntity MainCameraPivot,0,-3,0 ElseIf EntityYaw(MainCameraPivot) < -5 TurnEntity MainCameraPivot,0,3,0 Else TurnEntity MainCameraPivot,0,-EntityYaw(MainCameraPivot) / 10,0 EndIf EndIf EndIf EndIf PointEntity MainCamera,Player;Self-explanatory End Function Function UpdatePlayer() ;Harder to explain. It was a pain to come up with in the first place, ;and I've forgotten most of the theory behind it by now, not that I ;could've really put it into words beforehand; it's all in my head. ;Suffice it to say, IT WORKS. :) If KeyDown(200);Up If KeyDown(203) If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) + 45 Then TurnEntity Player,0,5,0 If EntityYaw(Player) > EntityYaw(MainCameraPivot,True) + 45 Then TurnEntity Player,0,-5,0 TurnEntity MainCameraPivot,0,(-45 - EntityYaw(MainCameraPivot)) / 10,0 ElseIf KeyDown(205) If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) - 45 Then TurnEntity Player,0,5,0 If EntityYaw(Player) > EntityYaw(MainCameraPivot,True) - 45 Then TurnEntity Player,0,-5,0 TurnEntity MainCameraPivot,0,(45 - EntityYaw(MainCameraPivot)) / 10,0 EndIf If Speed < .5 Then Speed = Speed + .005 ElseIf KeyDown(208);Down If KeyDown(203) If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) + 130 TurnEntity Player,0,10,0 ElseIf EntityYaw(Player) > EntityYaw(MainCameraPivot,True) + 140 TurnEntity Player,0,-10,0 Else TurnEntity Player,0,(EntityYaw(MainCameraPivot,True) + 135) - EntityYaw(Player),0 EndIf TurnEntity MainCameraPivot,0,(-135 - EntityYaw(MainCameraPivot)) / 4,0 If Speed < .5 Then Speed = Speed + .005 ElseIf KeyDown(205) If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) - 130 TurnEntity Player,0,10,0 ElseIf EntityYaw(Player) > EntityYaw(MainCameraPivot,True) - 140 TurnEntity Player,0,-10,0 Else TurnEntity Player,0,(EntityYaw(MainCameraPivot,True) - 135) - EntityYaw(Player),0 EndIf TurnEntity MainCameraPivot,0,(135 - EntityYaw(MainCameraPivot)) / 4,0 If Speed < .5 Then Speed = Speed + .005 Else If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) - 175 TurnEntity Player,0,10,0 TurnEntity MainCameraPivot,0,-10,0 ElseIf EntityYaw(Player) > EntityYaw(MainCameraPivot,True) + 175 TurnEntity Player,0,-10,0 TurnEntity MainCameraPivot,0,10,0 Else RotateEntity Player,EntityPitch(Player),EntityYaw(MainCameraPivot,True) - 180,EntityRoll(Player) RotateEntity MainCameraPivot,0,180,0 EndIf If Speed < .5 Then Speed = Speed + .005 EndIf Else If KeyDown(203);Left If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) + 85 TurnEntity Player,0,10,0 ElseIf EntityYaw(Player) > EntityYaw(MainCameraPivot,True) + 95 TurnEntity Player,0,-10,0 Else TurnEntity Player,0,(EntityYaw(MainCameraPivot,True) + 90) - EntityYaw(Player),0 EndIf TurnEntity MainCameraPivot,0,(-90 - EntityYaw(MainCameraPivot)) / 4,0 If Speed < .5 Then Speed = Speed + .005 ElseIf KeyDown(205);Right If EntityYaw(Player) < EntityYaw(MainCameraPivot,True) - 85 TurnEntity Player,0,10,0 ElseIf EntityYaw(Player) > EntityYaw(MainCameraPivot,True) - 95 TurnEntity Player,0,-10,0 Else TurnEntity Player,0,(EntityYaw(MainCameraPivot,True) - 90) - EntityYaw(Player),0 EndIf TurnEntity MainCameraPivot,0,(90 - EntityYaw(MainCameraPivot)) / 4,0 If Speed < .5 Then Speed = Speed + .005 Else ;Decelerate if no keys are pressed If Speed > 0 Then Speed = Speed * 0.9 EndIf EndIf MoveEntity Player,0,0,Speed End Function If anyone can help perfect the camera, as well as jump so when you press jump, you can ONLY press it one time, otherwise, the player wont jump, as well as the player sticking half way under ground when on ground screw up, please feel free! :) Thanks! ~DS~ |
| ||
...as well as the player sticking half way under ground when on ground screw up, please feel free! :) It's 'cuz your use of EntityRadius is far too small! The player's sphere has a radius of 1, but you gave it a collision radius of 0.1. Just remove the EntityRadius line & it'll work fine. Oh, one thing DSW, just as a favor to the forums... When you've got a big(ish) piece of code like this... Basically anything over about 2-4KB... Don't use the CODE tag, use CODEBOX instead; this really inflated the size of the thread. Anyway, glad my code helps! |
| ||
o woops. i didnt realize that! >< Sorry guys! :P As for perfecting camera, if anyone has any ideas then PLEASE do contribute to the community! :) ANY help is GREATLY appreciated! Thanks! ~DS~ |
| ||
also, u have to have entityradius=.9 cuz w/o it, ur player cant move forward at all. Thanks! ~DS~ |
| ||
That's odd... What version of B3D are you using, DSW? I tried it on V1.100, without the EntityRadius line, and it worked fine... |
| ||
Try jumping. PS. I use the highest version of blitz |
| ||
Warning, glitch in jump code. If you press jump then in the middle jumping press jump again it will make it jump twice. its only supposed to jump once. |
| ||
Did anyone figure out how to fix the glitch? |
| ||
That's a logic problem.If KeyHit(57) And Jump = False Then Jump = True [...] Endif |
| ||
Just to add onto this thread, I adapted this code for using a character made by Psionic (drawf), plus I had added the pitch camera control, so you can look above and below around the character May be useful to some people..... maybe ;-) |