3rd Person POV for Game Ursina

3.3k Views Asked by At

I am trying to make an rpg-style game with ursina. I want to have the camera always follow the back of the character. I tried using camera.look_at(player) but I couldn't get the camera to rotate to the back of the character when it rotated.

app = Ursina()

class character(Entity):
    def __init__(self):
        super().__init__(
            model = load_model('cube'),
            color = color.red,
            position = (-0, -3, -8)
        )

player = character()

print(player.forward)

print(player.forward)
camera.look_at(player)
player.rotation_y =180
def update():
    if held_keys['a']:
        player.rotation_y -= 2
    if held_keys['d']:
        player.rotation_y += 2


app.run()```
4

There are 4 best solutions below

7
On BEST ANSWER

You may want to change the origin. Also using parents. I'll explain what this means in a moment.

To change the origin (the point at which an entity is moved and rotated) to a point behind it.

e.g.

from ursina import *  # import urisna

app = Ursina()   # make app

player = Entity(model='cube',   # this creates an entity of a cube
                origin = (0, 0, -2)) #now you have a origin behind the entity

app.run()   #run app

But what about the camera, I hear you ask!

I'd recommend the ursina.prefabs.first_person_controller

It may be designed for 1st person control, but you can use it for your purpose.

# start by doing the normal thing
from ursina import *

# but also import the first person prefab
from ursina.prefabs.first_person_controller import FirstPersonController

app = Ursina()

# create camera and player graphic
cam = FirstPersonController()

player = Entity(model='cube',
                origin = (0, 0, -2),
                parent = cam)

# run
app.run()

You will need to create a floor entity.

That is ALL YOU NEED for the 3rd person controller. The parents and origins ensure that. It has built in WASD and Arrow Key control, with mouse control too.

@Cyber-Yosh recently asked a question for this post on how to use it without the 1st person controller. Here's how. I have commented on the changes.

from ursina import * # import as usual
app = Ursina()       # create app as usual

window.fps_counter.enabled = False # this is just to remove the fps counter

box = Entity(model='cube',         # create cube as before (you can make your own class)
             origin=(0,0.7,-5),    # set origin to behind the player and above a little
             parent=camera,        # make it orientate around the camera
             color=color.red,      # change the color
             texture='shore')      # choose a nice texture

def update():                      # define the auto-called update function
    if held_keys['a']:
        camera.rotation_y -= 10 * time.dt # the time.dt thing makes it adapt to the fps so its smooth
    elif held_keys['d']:
        camera.rotation_y += 10 * time.dt

Sky() # just a textured sky to make sure you can see that you are both rotating
app.run() # run

You'll notice that I've not created a class (adapting this for it is easy enough), but I did not use load_model. This is because even if you are using your own model, you don't need to use load_model. Simply put the name of the file (without the file extension) as a string. This works, I've tried it.

If you have any more questions, don't hesitate to ask. I am more than happy to help. If this worked, be sure to upvote and approve.

1
On

Parent the camera to the player and move it back. That way it will rotate along with the player entity.

camera.parent = player
camera.z = -10
0
On

I have a better solution, because when using the FirstPersonController, the physics are applied to the controller and not to the player, my solution is to create a camera:

camera= EditorCamera()

this will create a camera that will allow us to see the game, the next thing we must do is we must create the player and the floor:

terrain_width= 50
player= Entity(model="cube", color= color.orange)
player.x= 0

floor= Entity(model="plane", texture="grass", scale= terrain_width)

Now that this is done, we will stick the camera to the player, and adjust some parameters to see the player from above-back:

camera.parent= player
camera.y= 5
camera.z= -10
camera.rotation_x= 9.15

now we can make our player move and we will see that the camera also moves:

def input(key):
           
           if key == "a":
                  player.x-= 1
    
           if key == "d":
                  player.x+= 1
    
           if key == "w":
                  player.z+= 1
    
           if key == "s":
                  player.z-= 1

this would be the complete code:

from ursina import *

app= Ursina()

camera= EditorCamera()

terrain_width= 50
player= Entity(model="cube", color= color.orange)
player.x= 0
    
floor= Entity(model="plane", texture="grass", scale= terrain_width)

camera.parent= player
camera.y= 5
camera.z= -10
camera.rotation_x= 9.15

def input(key):
               
    if key == "a":
       player.x-= 1
        
    if key == "d":
       player.x+= 1
        
    if key == "w":
       player.z+= 1
        
    if key == "s":
       player.z-= 1

app.run()

I hope this will be useful to you :)

0
On

If anyone wants to use FirstPersonController, I found out how to move the camera away from the player, while keeping all physics interactions!

After creating the FirstPersonController, modify the position of its camera_pivot (default is (0,2,0)).

player = FirstPersonController(model="cube", color=color.orange, origin_y=-.5,z=-10)

# the default camera_pivot is (0,2,0)
player.camera_pivot.z = -3.5  # move the camera behind the player model
player.camera_pivot.y = 2.5  # move the camera a little higher

Full example (q to quit)

from ursina import *
from ursina.prefabs.first_person_controller import FirstPersonController
from ursina.shaders import lit_with_shadows_shader

app = Ursina()

Entity.default_shader = lit_with_shadows_shader

ground = Entity(model='plane', collider='box', scale=64, color=color.green)
player = FirstPersonController(model="cube", color=color.orange, origin_y=-.5,z=-10)

# the default camera_pivot is (0,2,0)
player.camera_pivot.z = -3.5  # move the camera behind the player model
player.camera_pivot.y = 2.5  # move the camera a little higher

# setting collider and making it visible for debugging
player.collider = BoxCollider(player, Vec3(0,1,0), Vec3(1,2,1))
player.collider.visible=True

# adding some objects to collide with
for i in range(16):
    Entity(model='cube', origin_y=-.5, scale=2, texture='brick', texture_scale=(1,2),
        x=random.uniform(-8,8),
        z=random.uniform(-8,8) + 8,
        collider='box',
        scale_y = random.uniform(2,3),
        color=color.hsv(0, 0, random.uniform(.9, 1))
    )

sun = DirectionalLight()
sun.look_at(Vec3(1,-1,-1))
Sky()

def input(key):
    if key == 'q':
        exit()
    
app.run()