4

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()```
Cyber-Yosh
  • 57
  • 1
  • 6
  • Please supply the expected [minimal, reproducible example](https://stackoverflow.com/help/minimal-reproducible-example) (MRE). We should be able to copy and paste a contiguous block of your code, execute that file, and reproduce your problem along with tracing output for the problem points. This lets us test our suggestions against your test data and desired output. "if you need more code" is already answered by the posting guidelines. – Prune Apr 20 '21 at 15:38
  • Please repeat [how to ask](https://stackoverflow.com/help/how-to-ask), from the [intro tour](https://stackoverflow.com/tour) – Prune Apr 20 '21 at 15:39
  • I'm sorry, I have now changed it to provide all the necessary code. – Cyber-Yosh Apr 20 '21 at 17:08

4 Answers4

5

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.

SamTheProgrammer
  • 1,051
  • 1
  • 10
  • 28
  • I tried using the origin to get the camera to rotate around the player, but I can't get it to go around the player. I tried rotating an entity around another entity, but I couldn't replicate it with the camera. – Cyber-Yosh May 01 '21 at 14:24
  • Have you tried the method above? @Cyber-Yosh – SamTheProgrammer May 01 '21 at 16:00
  • 1
    I don't really want to use the first person controller due to some of it's limitations, also I'm hoping to learn more about the engine with this – Cyber-Yosh May 01 '21 at 16:06
  • Ok. In answer to your 1st question, you need to use `parents`. This allows it to be in line with the camera once you've moved the origin (the point from which it's moved). A parent is the entity at which it orientated around. In the update() function, add line which sets the y rotation of the entity to the camera. I'll post a self-answered question in the next hour on this and leave a link here. @Cyber-Yosh – SamTheProgrammer May 02 '21 at 13:08
  • I can actually add it to the end of this post. @Cyber-Yosh Doing it now. – SamTheProgrammer May 02 '21 at 13:17
  • @Cyber-Yosh I have made the edits. Please see above. It does not use the `FirstPersonController` and I have tested it extensively. I hope it is what you were looking for. – SamTheProgrammer May 02 '21 at 13:47
  • 1
    Ok thank you, I had already tried to use camera.parent = player, but that got in they way of some of the other things I tried to do. – Cyber-Yosh May 02 '21 at 16:09
2

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()
1

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
pokepetter
  • 1,383
  • 5
  • 8
0

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 :)

JPhay0001
  • 1
  • 3