What's the correct way to attach a BulletCharacterControllerNode to an Actor?

:wave:

I am trying to attach a BulletCharacterControllerNode to an animated Actor to implement physics. I am using this link as a guide: Bullet Character Controller — Panda3D Manual .

I have a similar cube in my scene and the physics seem to work (it falls to the floor etc. and bounces some). Also the Actor that I am loading collides with the cube when moving and the cube moves (sort of). I think something is off with my collision settings though.

Note that I do have debug node enabled as shown in the screenshot, although it seems strange that the cube’s collision doesn’t match the cube itself.

I seem to have to keep two variables to control everything for the soldier… self.soldier for the Actor/mesh-animations and then self.player for physics/moving the character. I think maybe my code is off though.

self.soldier = Actor('assets/soldier.bam')
self.soldier.loop('Idle')
self.soldier_heading = 0
self.soldier.enable_blend()
self.turn_rate = 1.5
self.soldier.reparent_to(self.render)
...
...

shape = BulletCapsuleShape(1.75, 0.4, ZUp)
player_node = BulletCharacterControllerNode(shape, 0.4, 'Soldier')
self.player = self.soldier.attach_new_node(player_node)
self.player.set_collide_mask(BitMask32.all_on())
self.player.set_pos(Vec3(0, 0, .01))
...
...

self.world = BulletWorld()
self.world.set_gravity(Vec3(0, 0, -9.81))
self.world.attach_character(self.player.node())

What’s the correct way to attach a BulletCharacterControllerNode to an Actor? I am almost certain that I am not doing it correctly :smiley:

1 Like

Here is how I do it in my Arena FPS Sample Program. Two small differences from your use case may be that this is a first-person character setup for a character controller (yours looks perhaps third-person), and I’m using complexpbr for hardware skinning (and rendering).

        # initialize player character physics the Bullet way
        shape_1 = BulletCapsuleShape(0.75, 0.5, ZUp)
        player_node = BulletCharacterControllerNode(shape_1, 0.1, 'Player')  # (shape, mass, player name)
        player_np = self.render.attach_new_node(player_node)
        player_np.set_pos(-20, -10, 30)
        player_np.set_collide_mask(BitMask32.allOn())
        self.world.attach_character(player_np.node())
        self.player = player_np

        # reparent player character to render node
        fp_character = actor_data.player_character
        fp_character.reparent_to(self.render)
        fp_character.set_scale(1)
        # set the complexpbr actor skinning
        complexpbr.skin(fp_character)

        self.camera.reparent_to(self.player)
        # reparent character to FPS cam
        fp_character.reparent_to(self.player)
        fp_character.set_pos(0, 0, -0.95)
        # self.camera.set_x(self.player, 1)
        self.camera.set_y(self.player, 0.03)
        self.camera.set_z(self.player, 0.5)

…where actor_data.player_character looks like this in a separate .py file:

# this is the file actor_data.py
from direct.actor.Actor import Actor

player_character = Actor("models/npc_1.bam",
              {"walking": "models/npc_1_ArmatureAction.bam", "death": "models/npc_1_death.bam"})
1 Like

Okay thanks… seems like it works better after changing it to self.soldier.reparent_to(self.player), instead of the way I had it like self.player = self.soldier.attach_new_node(player_node). I changed it similar to how you have fp_character.reparent_to(self.player). Thanks again!

1 Like

Happy to assist – setting up Bullet stuff can be a little tricky. Let us know if you have other questions!

1 Like