Asking for some help: About 3rd person camera movement

Hey all!

I’m quite new in the bge, and would be glad if you could help me out with some information concerning setting up camera for a 3rd person view.

Currently I have a script that is used both for 1st and 3rd person view.

The problem is that when in 3rd person view, I can get my camera view behind objects, walls, etc.

So I set up a ray pointing backwards from my character, and ending in just the same spot where my camera has it’s start point when in 3rd person view. I also connected a script to it, that should make the camera go into the position where the ray hits anything.

I don’t know if there is a problem with my script, or something else is the case, so please help me out if you can.

PS. My script:

import bge
from bge import render

scene = bge.logic.getCurrentScene()

#_sensor
ray = bge.logic.getCurrentController().sensors[“ray_backwards”]

#_object
Camera = scene.objects[“Camera”]

#_getting_position_Where_the_ray_hits_anything
x = ray.hitPosition[0]
y = ray.hitPosition[1]
z = ray.hitPosition[2]

#_setting_camera_position_to_where_the_ray_hits_anything
Camera.applyPosition(x, y, z)

Just found another ridiculous thing with an other script:

######################
import bge
from bge import render

scene = bge.logic.getCurrentScene()

def main():

#_setting mouse movement speed
rotSpeedX = 0.005
rotSpeedY = 0.005

xMentenMehetE = 1 

#_sensor
mouse = bge.logic.getCurrentController().sensors["mouse"]

#_objects
ketrec = scene.objects["ketrec"]
empty = scene.objects["empty"]
karakter = scene.objects["karakter"]

#_getting mouse look
x = (render.getWindowWidth() / 2 - mouse.position[0])
if xMentenMehetE == 1:
    y = (render.getWindowHeight() / 2 - mouse.position[1])

#_applying rotation
ketrec.applyRotation((0 , 0, int(x) * rotSpeedX), False)
if xMentenMehetE == 1:
    empty.applyRotation((int(y) * rotSpeedY, 0, 0), True)
if xMentenMehetE == 0:
    empty.applyRotation((int(y) * rotSpeedY, 0, 0), True)
    

#_resetting mouse position
render.setMousePosition(int(render.getWindowWidth() / 2), int(render.getWindowHeight() / 2))

main()
##########################

So: This works just fine, when I set “xMentenMehetE” to 1. But when I set it to 0, and start the game engine, the character starts to rotate with an increasing intensivity for every pixel my mouse is moved to the right or to the left. (Eg. if I move my mouse 5 pixels right, it spins with a constant speed, and if I move my mouse back 5 pixels (so to the left) it stops spinning - this is the same to the left side too).

PS. I am learning programming in a university, (C++ currently), but never saw any “if” statements do such crazy things before in any programming languages.

PS. First I made an “else:” branch for the 2nd expression, but that made just the same thing. :frowning:

the idea seem good(nevermind) but what happen if the ray not hit anything?

i guess should be at least one “if” to manage this exception


if ray.positive:camera.worldPosition = ray.hitPosition # what already do
else : camera.worldPosition = someEmpty.worldPosition

not there error in the consolle ?(windows->toggle consolle)

Please use code tags. Otherwise your snippet appears syntactical incorrect.

I suggest as MarcoIT did to use worldPosition rather then applyPosition() (but do not use this one line “if:” statement as it is hard to read).


if raySensor.positive:
  camera.worldPosition = raySensor.hitPosition
...

Your second script is not understandable to me as it uses some language I do not understand (e.g. “xMentenMehetE”) . So I can’ guess what the author wants to say.

The “If” statements are not crazy but show some unusual use of data type. I would use a boolean value rather then a cryptic number:


if isCondition:
  doSomething()

Thank you!

It now works well using “worldPosition”, though I don’t really need the “else” branch in that “if” statement, since at start my camera is positioned right where the ray ends.

I also had to learn that a true boolean value is written like “True”, instead of “true” in python, thats why I wrote 1 as the value of that thing (“xMentenMehetE”). ^^

BTW, the ‘thing’: “xMentenMehetE” is in hungarian, and means something like: “shouldTheObjectBeRotatedOnTheXAxis” - chosen the shorter version. :smiley:

PS. Am a bit emberassed - This was why my object started spinning :smiley:

if xMentenMehetE == 1:
y = (render.getWindowHeight() / 2 - mouse.position[1])

xMentenMehetE ??
Camera.applyPosition ?
? from where come this script??

[“code”] …code here… ["/code"]

clean the >>>""<<<

I am quite new to both python and bge - and the applyPosition was only my idea (tought it may exist :D)

BTW, do you have any Idea why this stops my script from working? :

############################################################

if empty.rotation_euler.x > 90 and empty.rotation_euler.x < 180: #_looking upwards
lookingUp = True
if empty.rotation_euler.x < 90 and empty.rotation_euler.x > 0: #_looking downwards
lookingUp = False

############################################################

The value of “lookingUp” would be used (along with an other boolean value which shows whether the mouse position is moving upwards or downwards) to stop the camera from looking too much up/down:

############################################################

if aroundX >= cap: #_if not capped => can look anywhere
empty.applyRotation((int(y) * rotSpeedY, 0, 0), True)

elif lookUp == True and downMove == True: #_if looking upwards
empty.applyRotation((int(y) * rotSpeedY, 0, 0), True)

elif lookUp == False and downMove == False: #_if looking downwards
empty.applyRotation((int(y) * rotSpeedY, 0, 0), True)

############################################################

This part is surely OK - I tested it by setting both “lookUP” and “downMove” to ‘True’, then to ‘False’.
“downMove” is true when the mouse is moving downwards, and false when it is moving upwards - still working on it too. :smiley:

This way I try making something like a constraint around the x axis - which I wasn’t able getting otherwise. :frowning:

I solved the 2nd issue by checking the aroundX number got this way:

object = logic.getCurrentController().owner
aroundX = object.worldOrientation.to_euler().x

And then setting a variable called “capped” to true when it is at the cap I set up and the mouse moves in the right direction.

I am really thanksful for the solution for placing the camera on the right spot of the ray whenever it hits anything, but there is still a problem with it: When the- character (the camera is looking at) is close enough to a wall it can happen, that I can look behind it (, since the camera is wider than the ray).

I tought about making two rays, one at each side of the camera, and setting up the position according to that, counting the right place.
Maybe it will still not be enough, and I wil have to make 4 rays, one to each of the 4 vertices of the camera’s front side.

So, is there any easier way than this to set this thing up?

I wrote the 4-rays method:

BEGIN>>>

import bge
from bge import render

scene = bge.logic.getCurrentScene()

#--------------------------------------------------------------------------------------------------------------------------------------#
def oneTrue(r1, dir1):

#_OBJECTS:
camera = scene.objects["Camera"]
empty = scene.objects["empty"]




#_APPLYING POSITION:
camera.worldPosition = r1.hitPosition
camera.localPosition.x += dir1[0]
camera.localPosition.z += dir1[1]

#--------------------------------------------------------------------------------------------------------------------------------------#
def twoTrue(r1, dir1, r2, dir2):

#_OBJECTS:
camera = scene.objects["Camera"]
empty = scene.objects["empty"]




#_APPLYING ROTATION:
if r1.hitPosition.y &lt;= r2.hitPosition.y:
    camera.worldPosition = r1.hitPosition
    camera.localPosition.x += dir1[0]
    camera.localPosition.z += dir1[1]
else:
    camera.worldPosition = r2.hitPosition
    camera.localPosition.x += dir2[0]
    camera.localPosition.z += dir2[1]

#--------------------------------------------------------------------------------------------------------------------------------------#
def threeTrue(r1, dir1, r2, dir2, r3, dir3):

#_OBJECTS:
camera = scene.objects["Camera"]
empty = scene.objects["empty"]




#_APPLYING ROTATION:
if (r1.hitPosition &lt;= r2.hitPosition) and (r1.hitPosition &lt;= r3.hitPosition):
    camera.worldPosition = r1.hitPosition
    camera.localPosition.x += dir1[0]
    camera.localPosition.z += dir1[1]
elif (r2.hitPosition &lt;= r3.hitPosition):
    camera.worldPosition = r2.hitPosition
    camera.localPosition.x += dir2[0]
    camera.localPosition.z += dir2[1]
else:
    camera.worldPosition = r3.hitPosition
    camera.localPosition.x += dir3[0]
    camera.localPosition.z += dir3[1]

#--------------------------------------------------------------------------------------------------------------------------------------#
def fourTrue(r1, dir1, r2, dir2, r3, dir3, r4, dir4):

#_OBJECTS:
camera = scene.objects["Camera"]
empty = scene.objects["empty"]




#_APPLYING ROTATION:
if (r1.hitPosition &lt;= r2.hitPosition) and (r1.hitPosition &lt;= r2.hitPosition) and (r1.hitPosition &lt;= r4.hitPosition):
    camera.worldPosition = r1.hitPosition
    camera.localPosition.x += dir1[0]
    camera.localPosition.z += dir1[1]
elif (r2.hitPosition &lt;= r3.hitPosition) and (r2.hitPosition &lt;= r4.hitPosition):
    camera.worldPosition = r2.hitPosition
    camera.localPosition.x += dir2[0]
    camera.localPosition.z += dir2[1]
elif (r3.hitPosition &lt;= r4.hitPosition):
    camera.worldPosition = r3.hitPosition
    camera.localPosition.x += dir3[0]
    camera.localPosition.z += dir3[1]
else:
    camera.worldPosition = r4.hitPosition
    camera.localPosition.x += dir4[0]
    camera.localPosition.z += dir4[1]

#OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO#
def main():

#_SENSORS:
ray1 = scene.objects["hátra_ray1_alapja"].getCurrentController().sensors["ray_backwards1"]
ray2 = scene.objects["hátra_ray2_alapja"].getCurrentController().sensors["ray_backwards2"]
ray3 = scene.objects["hátra_ray3_alapja"].getCurrentController().sensors["ray_backwards3"]
ray4 = scene.objects["hátra_ray4_alapja"].getCurrentController().sensors["ray_backwards4"]




#_OBJECTS:
camera = scene.objects["Camera"]
empty = scene.objects["empty"]




#_SETTING RAY DIRECTION: (the difference from "Camera's" position as [x, z] coordinates
dir1 = [-0.6, 0.4]
dir2 = [0.6, 0.4]
dir3 = [-0.6, -0.4]
dir4 = [0.6, -0.4]



#_SETTING RAY ACTIVITY:
r1 = False
r2 = False
r3 = False
r4 = False
if ray1.positive:
    r1 = True
if ray2.positive:
    r2 = True
if ray3.positive:
    r3 = True
if ray4.positive:
    r4 = True




#_APPLYING POSITION:
if r1 and not (r2 and r3 and r4):       #_active rays: 1
    oneTrue(ray1, dir1)
elif r2 and not (r1 and r3 and r4):       #_active rays: 2
    oneTrue(ray2, dir2)
elif r3 and not (r1 and r2 and r4):       #_active rays: 3
    oneTrue(ray3, dir3)
elif r4 and not (r1 and r2 and r3):       #_active rays: 4
    oneTrue(ray4, dir4)
elif r1 and r2 and not (r3 and r4):       #_active rays: 1, 2
    twoTrue(ray1, dir1, ray2, dir2)
elif r1 and r3 and not (r2 and r4):       #_active rays: 1, 3
    twoTrue(ray1, dir1, ray3, dir3)
elif r1 and r4 and not (r2 and r3):       #_active rays: 1, 4
    twoTrue(ray1, dir1, ray4, dir4)
elif r2 and r3 and not (r1 and r4):       #_active rays: 2, 3
    twoTrue(ray2, dir2, ray3, dir3)
elif r2 and r4 and not (r1 and r3):       #_active rays: 2, 4
    twoTrue(ray2, dir2, ray3, dir3)
elif r3 and r4 and not (r1 and r2):       #_active rays: 3, 4
    twoTrue(ray3, dir3, ray4, dir4)
elif r1 and r2 and r3 and not r4:                     #_active rays: 1, 2, 3
    threeTrue(ray1, dir1, ray2, dir2, ray3, dir3)
elif r1 and r2 and r4 and not r3:                     #_active rays: 1, 2, 4
    threeTrue(ray1, dir1, ray2, dir2, ray4, dir4)
elif r1 and r3 and r4 and not r2:                     #_active rays: 1, 3, 4
    threeTrue(ray1, dir1, ray3, dir3, ray4, dir4)
elif r2 and r3 and r4 and not r1:                     #_active rays: 2, 3, 4
    threeTrue(ray2, dir2, ray3, dir3, ray4, dir4)
elif r1 and r2 and r3 and r4:                                     #_active rays: 1, 2, 3, 4
    fourTrue(ray1, dir1, ray2, dir2, ray3, dir3, ray4, dir4)
else:
    camera.worldPosition = empty.worldPosition
    camera.localPosition -= ray1.range

main()

<<<END

But I have a problem:

#_SENSORS:
ray1 = scene.objects["hátra_ray1_alapja"].getCurrentController().sensors["ray_backwards1"]
ray2 = scene.objects["hátra_ray2_alapja"].getCurrentController().sensors["ray_backwards2"]
ray3 = scene.objects["hátra_ray3_alapja"].getCurrentController().sensors["ray_backwards3"]
ray4 = scene.objects["hátra_ray4_alapja"].getCurrentController().sensors["ray_backwards4"]

This just doesn’t work, since those are KX_GameObject-s. If I write it as “bge.logic”, instead of eg. “scene.objects[“hátra_ray1_alapja”]” then it doesn’t work, since those are different objects having those rays in their logics.

So what should I do in order to obtain a sensor in a script that is under an other object’s logic?