Camera control. I'm going bald...

Blitz3D Forums/Blitz3D Programming/Camera control. I'm going bald...

Adam Novagen(Posted 2009) [#1]
... 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!


Guy Fawkes(Posted 2009) [#2]
did u try:



?

it doesnt work. but u get the idea :)

good luck on ur project! :)

~DS~


Adam Novagen(Posted 2009) [#3]
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!


stayne(Posted 2009) [#4]
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.


Adam Novagen(Posted 2009) [#5]
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.


Adam Novagen(Posted 2009) [#6]
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.


Guy Fawkes(Posted 2009) [#7]
U mean like a Shadow of the Colossus cam?


Adam Novagen(Posted 2009) [#8]
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.


GIB3D(Posted 2009) [#9]
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.


Adam Novagen(Posted 2009) [#10]
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!


Guy Fawkes(Posted 2009) [#11]
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~


Warner(Posted 2009) [#12]
Not sure if this is what you meant, but I wrote this yesterday based on your explaination:



Adam Novagen(Posted 2009) [#13]
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.)


Kryzon(Posted 2009) [#14]
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].


Adam Novagen(Posted 2009) [#15]
Hmmmm... *strokes chin where beard would be*

This might be just what I'm looking for, Kryzon; I'll try this ASAP! Thanks!!!


Kryzon(Posted 2009) [#16]
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!


Adam Novagen(Posted 2009) [#17]
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... ^_^


Guy Fawkes(Posted 2009) [#18]
can u release source? ^^ that would be awesome! :)


Guy Fawkes(Posted 2009) [#19]
I'd like an example of this camera code when its fixed. my camera is freakin out again. *sigh*


Adam Novagen(Posted 2009) [#20]
Okay, I'll try & cobble together a more usable version; right now it's customized specifically for me.


grindalf(Posted 2009) [#21]
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


Guy Fawkes(Posted 2009) [#22]
Did u get the code yet?


Adam Novagen(Posted 2009) [#23]
I'm working on it, just hold tight... AAAGH, so much to DOOO... O_o


Guy Fawkes(Posted 2009) [#24]
Lol, dont worry. I know how u feel. I have loads to do too. and very little time

~DS~


Adam Novagen(Posted 2009) [#25]
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!




Guy Fawkes(Posted 2009) [#26]
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~


Adam Novagen(Posted 2009) [#27]
...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!


Guy Fawkes(Posted 2009) [#28]
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~


Guy Fawkes(Posted 2009) [#29]
also, u have to have entityradius=.9

cuz w/o it, ur player cant move forward at all.

Thanks!

~DS~


Adam Novagen(Posted 2009) [#30]
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...


Guy Fawkes(Posted 2009) [#31]
Try jumping.

PS. I use the highest version of blitz


Guy Fawkes(Posted 2009) [#32]
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.


Guy Fawkes(Posted 2009) [#33]
Did anyone figure out how to fix the glitch?


Kryzon(Posted 2009) [#34]
That's a logic problem.
If KeyHit(57) And Jump = False Then
   Jump = True
   [...]
Endif 



nrasool(Posted 2009) [#35]
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 ;-)