Panda3D Arena FPS Sample Program Submission

Based on the recent discussion here Contribution ideas - more GAME samples! I have created a compact FPS sample program using Bullet Physics, .gltf exports, blend2bam Actor animation exports, Hardware Skinning with customized simplepbr shaders, a first-person camera handler, a movement timing system, an animated handgun model, and more.

Please discuss enhancements and changes to this sample program here. I am willing to take it further based on suggestions, or if you feel capable go ahead and start hacking on it. The amount of detail and logic in this sample program may be deceptive. It’s not exactly simple.

Full code and assets here:

Features:

  • First person camera handling system
  • Interactive target dot reticule system
  • Gamepad support
  • Armature with “walking” and “death” animations
  • Bloom, HDR, Exposure, Gamma, Volumetric Lighting, Blur/Sharpen, and Ambient Occlusion support via CommonFilters
  • Working blend2bam Actor exporting script
  • Physically based shaders via panda3d-simplepbr
  • Hardware Skinning support via customized Actor shaders
  • Animated handgun model
  • Bullet Physics integration of environment, characters, and collision cubes
  • Advanced timing logic in Panda3D
  • Basic weapon loading and animation
  • State machine based onscreen text updating
  • Toggle based flashlight with shadow casting
  • Modern .gltf and .bam based modeling
  • Very basic NPC movement system
  • Jumping and slope physics support

Included Full Assets:

  • Handgun model with Blender file
  • Adult male model with Blender file and .bam animation exports
  • Arena model with Blender file
  • Cube model for randomly colored physics cubes

Game Goal:

  • Neutralize the NPC by shooting the head hitbox
  • Receive success message

Requirements:

  • Panda3D
  • panda3d-gltf

New picture as of the last major update:
skinpad_update
Additional pics:



Example of default Volumetric Lighting settings:


Older dev pics:

6 Likes

Very cool Simulan! I went ahead and pulled the repo, and tested things out as I’ve been looking to hack on some very similar types of things for Panda. Until now I’ve been tweaking ‘Roaming Ralph’ to work out bugs.

First off, thanks for doing this. Being new to Panda myself, just reading your code really helped me get ideas on some ways to do things that would have probably taken me hours/days/weeks of trial and error to try to figure out on my own. This is a great example of how sample code like this can really help other folks new to Panda really get up to speed quickly.

I also like how you’ve already gone above/beyond, and decided to add support for things I didn’t even know existed till I saw your code (simplepbr, gltf support). Maybe experienced Panda3d folks know about these things but I had no clue! Another great reason to have such nice (up to date) samples, the cumulative experience of experienced Panda3d users’ knowledge gets condensed into some working code that others can learn from.

Anyhow, thanks for all your efforts here. I’d definitely like to read through this code much more deeply and see if I can help flesh things out more.

I’ve been play-testing this a bit, and lots of ideas came to mind on things I’d like to try my hand at.

  • It only took a few seconds of google-ing, but for total newbies like myself a blurb in the README on what to ‘pip install’ might help others. Once I did that, ran perfectly

  • Definitely would like to take a bunch of free media assets I have lying around and see if I can get it to work with your foundation, I have a lot of animated character, textures, meshes for the level and the like. Also the physics library you started with (bullet) I know is super capable - so some objects to collide with might help to show it’s capability.

  • I few bugs that popped up for me: - the NPC seems to dart around super quickly, then dash to a far wall and fall through the floor and disappear. I couldn’t really catch it. I’m sure super easy to tweak, but just to mention. Also colliding with the walls seems to teleport my camera on top of the wall immediately, collision definitely works but my guess is collision response just needs a little configuration. Other minor little things, like movement was hard to perceive without a floor texture or some obstacles, but this is likely by design - for a first version this is a really great foundation.

Thanks again for this. I’ll drop a blurb if/when I can get any useful results building off of what you’ve started!!

Thanks,

-Sal

2 Likes

Very neat! And thank you for contributing this! :slight_smile:

I do have a question: Why are you creating multiple DirectObjects? Why not just implement the various events in the “app” class?

Great, but you forgot to mention the dependency gltf

Traceback (most recent call last):
  File "main.py", line 54, in <module>
    import gltf
ModuleNotFoundError: No module named 'gltf'

In view of the fact that I’m a bore, I think it’s worth noting that this example is related to python. It is impossible to repeat this in C++.

I have another message .

:display:gsg:glgsg(warning): Shader created-shader produced the following warnings:
WARNING: Too many temp register is used in Fragment shader, it may cause slow execution.

As for the example, it’s a good idea to sort the rendering of the character and weapons so that you don’t visually pass through walls.

Great work :slight_smile: !

As a minor nitpick, one thing I’d like to suggest is to only use the snake_case variant of the Panda method names, since there was talk of deprecating the use of the camelCase names at some point.

1 Like

You can change the NPC movement speed by changing the increments which are applied to the position, making the NPC slow or fast. I made it fast by default to give some challenge to the player in shooting the head. The NPC movement implementation is bad, but this is because I didn’t want to go way above an entry level user’s head with AI techniques. I have written code that avoids all above floor collision meshes but it is rather more sophisticated than I’d want an entry level user to deal with.

Yep, there are some bugs and suboptimal choices in this sample program. All fixable I believe.

Thanks for the supportive comment and feel free to share your demos with the community. It’s nice to have another seasoned dev here, even if your specialty is the big name engines. I have used Unreal 4 to some extent for VR development so I’m about as familiar with it as you are Panda3D.

Ah, I didn’t even think about that. You’re right, that should be updated.

1 Like

Thanks, I added that to the post.

The multiple DirectObjects are now just under one called “beep” in arena.py .

I made a quick “fix” for this, which is to make the npc_1 movements more normalized. It should at least take longer to escape the arena this way.

The real solution is to add some ray testing logic to the character, or do something like apply Bullet forces to the character node. Either of these is getting into complexity I don’t think is appropriate, but I’m open to solutions other people may suggest. I think the existing NPC timer could be used to apply Bullet forces equally as well, which may prevent most cases of the NPC passing through the arena wall. After all I’m manually applying a graph transformation on the character with the Task system even though it’s being actively collision modeled, which may not be the best (general) solution.

One fairly simple way to implement future collision detection is to have, I believe, a Bullet Ghost node Box some multiple the size of the NPC character, and check wall intersections on that. This would require some more logic to implement, but might be fairly compact code-wise.

The updated NPC timer cycle:

        # npc movement timer
        def npc_1_move_gen():
            while not self.npc_1_is_dead:
                m_incs = []
                for x in range(0, 2):
                    m_incs.append(random.uniform(0.03, 0.08))
                
                print('NPC_1 movement increments this cycle: ' + str(m_incs))
                self.npc_1_move_increment[0] = m_incs[0]
                self.npc_1_move_increment[1] = m_incs[1]
                time.sleep(3)
                self.npc_1_move_increment[0] = m_incs[0]
                self.npc_1_move_increment[1] = m_incs[1]
                time.sleep(3)
                self.npc_1_move_increment[0] = (-1 * m_incs[0]) * 2
                self.npc_1_move_increment[1] = (-1 * m_incs[1]) * 2
                time.sleep(3)
                self.npc_1_move_increment[0] = 0
                self.npc_1_move_increment[1] = 0

Added

hardware-animated-vertices #t

to load_prc_file_data.

Fair enough!

For the record, you don’t need a separate DirectObject at all: “ShowBase” inherits from “DirectObject”, and thus you can register your events with your “app” class. Something like this:

class Game(ShowBase):
    def __init__(self):
        ShowBase.__init__(self)

        self.accept("space", self.someMethod)

I would suggest, in place of “sleep”-timers, that you apply a delta-time value to your movements. That should normalise for potentially-variable frame-rates, at the least!

If the NPCs still move too fast–or if the frame-rate drops too low–then you can perhaps implement either sub-division of physics updates or “continuous collision detection”.

The variable frame rate issue is limited to some extent with calling clock-frame-rate 60 in the prc file. But yes, enhancing the NPC handler is important.

CCD was already enabled upon the first posting, at least on some objects.

Fair enough, on all points. I’ll confess that I didn’t read the sample closely!

(In part perhaps because it uses a style that I personally don’t find intuitive, but that’s me.)

I hope we can somehow combine these different styles in a productive way, but I do not yet see a truly idiomatic way of writing Panda3D. I similarly have a difficult time reading your examples, and I apologize for a lack of communication in that regard.

No no, there’s no lack of communication! Different people have different styles, and that’s okay!

(And I apologise if I made it seem that there was a problem with your communication! ^^; )

Rather, I would like to have samples of both our styles (and perhaps others besides). Let users pick whichever suits them best!

1 Like

Here’s what happens without syncing the video.

1 Like

260+ frames per second, nice. The flashlight seems to be horribly slow with the shadow casting enabled, unfortunately.

This is if you do not turn on the flashlight :slightly_smiling_face: