Ursina engine trying to get a bullet to spawn from the tip of a the gun.

Started by
6 comments, last by Malonn 1 year, 2 months ago

I am having trouble getting a bullet to spawn from the tip of the gun. I'm just playing with the Ursina Engine and can't quite get it right. Here's some code (that doesn't work):

import random
import time
from direct.actor.Actor import Actor
from ursina import Audio, camera, Entity, invoke, mouse, raycast, scene, Ursina, Vec3
from ursina.prefabs.first_person_controller import FirstPersonController


class Bullet45(Entity):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.heading = Vec3(0, 0, 0)
        self.lifetime = 10
        self.speed = 10
        for key, value in kwargs.items():
            setattr(self, key, value)

    def update(self):
        print(self.position)
        trace = raycast(self.position, Vec3(0, 0, 0))
        # rt = raycast(self.rotation, Vec3(90, -10, 0))
        # self.position += self.heading * self.speed * time.dt
        # self.rotation += Vec3(0, 0.1, 0)


class Ingram(Entity):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.controller = None
        self.cooldown = False
        for key, value in kwargs.items():
            setattr(self, key, value)
        self.actor = Actor('./models/ingram/scene.gltf')
        self.actor.reparent_to(self)
        self.actor.setPlayRate(8.0, 'Cycle')
        self.actor.pose('Cycle', 0)
        rate = self.actor.getPlayRate('Cycle')
        self.dur = rate / (rate * 2.5)
        self.flash = Entity(parent=self,
                            model='./models/flash/scene.gltf',
                            enabled=False,
                            rotation=(0, 90, 0),
                            scale=0.005,
                            x=0.35)
        self.sound = Audio('./sounds/ingram/50_close.mp3',
                           autoplay=False,
                           volume=3)

    def input(self, key):
        if key == 'left mouse down':
            if not self.cooldown:
                self.cooldown = True
                self.shoot()

    def shoot(self):
        self.actor.play('Cycle')
        self.sound.play()
        self.flash.animate('rotation_z', random.randint(0, 360))
        self.flash.enable()
        x, y = self.parent.world_x, self.parent.world_y
        bullet = Bullet45(model='sphere',
                          heading=self.parent.forward,
                          position=self.parent.world_position + self.parent.forward,
                          rotation=self.parent.world_rotation,
                          scale=0.007,
                          speed=5)
        # bullet.animate_position(bullet.position + bullet.heading * 5, 1)
        invoke(self.flash.disable, delay=0.1)
        invoke(self.actor.pose, 'Cycle', 0, delay=self.dur)
        invoke(setattr, self, 'cooldown', False, delay=self.dur)


class Player(Entity):
    def __init__(self, **kwargs):
        self.controller = FirstPersonController(**kwargs)
        self.controller.mouse_sensitivity = (60, 60)
        super().__init__(parent=self.controller.camera_pivot)
        self.ingram = Ingram(parent=self,
                             controller=self.controller,
                             cooldown=False,
                             position=(0.4, -0.20, 0.8),
                             rotation=(90, -90, 0),
                             scale=2)

    # def update(self):
    #     print(self.world_position)


game = Ursina()
ground = Entity(model='plane', collider='mesh', scale=64, texture='grass', texture_scale=(4, 4))
player = Player()
# mouse.enabled = True
# mouse.locked = False

game.run()

It's mid-troubleshooting, and I have tried a bunch of stuff. Anyone have any ideas what I should do?

Advertisement

The first thing is - when you say “it doesn't work”, what do you mean, exactly? Nothing happens? Something happens, but it's the wrong thing?

I've never heard of the Ursina engine before (and I'm a big Python fan) so you might struggle to find people with experience of it. If you can't step into the code in a debugger, you'll want to use print statements or some other visual display to give you some output that can either confirm or deny any suspicions you have about the code, such as which bits get executed and when

I do see a few things that look wrong to me though:

  • the position of the bullet is relative to the parent of the Ingram, which I guess is the player, but that's not the gun
  • the scale is tiny so the bullet object might not be visible
  • the heading is zero-length so the bullet may never move (and might stay obscured by something else, if it appeared in a hidden position) - and you've commented out the code that moves it, anyway
  • we can't see where shoot is called, so there might be a bug there

Hey, thanks for the reply. Sorry for the lack of clarity in my question.

What I mean by doesn't work is that the bullet spawns off position from the gun tip. Plus, as you move, it can spawn even more off position.

Sorry about the code, was in the middle of a bunch of debugging, and really isn't even what I have ATM, but the above code is the closest I could get. It's an evolving thing.

The bullet cannot have the camera as parent, else it will move with the player controls. Scale is good—the original model is big. Heading is a relative vector to the camera and the z position. All handled by Ursina.

You sorta need to play with Ursina to really know what's what; you know that, of course. Side note: it's a neat game engine mostly written in Python. But, it's only been out for 2 or 3 years, and not widely adopted (like you said).

I'm really studying the docs (not well documented docs—nothing like official Python docs), and have a few ideas. I'll post back if I have any success.

Thanks again. I just wasn't sure, being a game dev site, if anyone had any experience with Ursina.

I wasn't saying the bullet should have the camera as parent, so I'm not sure what you're replying to there. But it does get its initial position from the Ingram's parent, so if that's wrong, that's where the problem probably is. The “gun's tip” isn't defined in the code above so it's not possible to know whether what's there could ever be right or not. It looks to me like it should always spawn 1 unit in front of the player.

I've just worked out what's happening with the heading - the whole ‘overwrite things with setattr’ pattern is powerful but dirty. Not the problem here though.

I don't know, man. I misunderstood you, I guess. No offense intended.

I have an idea though. Spawn a dummy entity with the gun as parent, then spawn a bullet with the world position of that dummy. Then move position.

I'm about to fire it up; get on down the road and see if I get to my destination.

By the by: should I not use setattr? I'm not what you'd call a highly experienced coder. I'd love to hear a pro's take on setattr…

Kylotan said:
I've never heard of the Ursina engine before (and I'm a big Python fan) so you might struggle to find people with experience of it.

It's an offshoot of the Panda3D engine, if I'm not much mistaken. I think that it aims for ease-of-use?

As to the problem, not being familiar with the changes that Ursina makes to Panda, it's hard for me to weigh in with confidence (for example, it's not clear to me what “parent” is in the case of an Ursina “Entity”, or what space that parent's “forward” vector is defined to be in).

That said, presuming that the node-hierarchy is much like Panda's, and presuming that the forward-vector being used is in world-space, then the idea of using a dummy Entity (or just a dummy-node, if available) attached to the muzzle of the game seems like it should work.

MWAHAHAHAHAHAHA!!!

My Twitter Account: @EbornIan

Yeah, it builds on the Panda3D engine. And, yep, it's made to be easy to use and get working (just don't expect CryEngine-level results). One guy made a sweet replica of Minecraft with it though.

Entity is a subclass of NodePath. So, an entity's parent is set via NodePath (I forget the method name).

But, tested and confirmed. I have it working now with a dummy Entity, and the bullet spawning from the dummy's world position. Works good enough for what it is.

This topic is closed to new replies.

Advertisement