Bullet firing

I’m trying to create a way to load and fire bullets in the same direction as my ship is pointing. how would i go about doing that? use a ray that’s attached to my ship? and if so how would i go about doing that? here’s my code with a very buggy y axis only bullet firing.

import direct.directbase.DirectStart
from pandac.PandaModules import *
from direct.gui.OnscreenText import OnscreenText
from pandac.PandaModules import WindowProperties
from pandac.PandaModules import CollisionTraverser, CollisionHandlerEvent
from pandac.PandaModules import CollisionNode, CollisionSphere
from direct.showbase.ShowBase import ShowBase 
import sys

#this class has colisions with pushers and regular colliders

class Game(ShowBase, object):
    
    speed = .1 # controls the speed of the ship
    FORWARD = Vec3(0, 2, 0) # sets direction and speed of forward direction
    STOP = Vec3(0, 0, 0)# sets the speed and direction of stop
    walk = STOP # makes walk = stop
    collision = False #True if somthing is colliding
    
    def __init__(self):
        base.disableMouse() # disables the default mouse camera controls
        base.accept( "escape" , sys.exit) # quits when escape is pressed
        self.collisionsHandler()#This should be before ANY node loading/setting
        self.addWinProps()
        self.addlight() # load the light
        self.loadShip() #calls up the function to load the ship
        self.loadAI()
        self.loadWorld()
        self.createControls()
        self.setCamera()
        self.shoot()
        taskMgr.add(self.updateShipPos, 'update position')
        taskMgr.add(self.mouseUpdate, 'update mouse')
        
    def collisionsHandler(self):
        
        # Initialize the traverser.
        base.cTrav = CollisionTraverser()
        
        # Initialize the handler.
        self.pusher = CollisionHandlerPusher()
        self.pusher.addInPattern('into-%in')
        self.pusher.addOutPattern('outof-%in')
        
        # Make a variable to store the unique collision string count.
        self.collCount = 0
        
    def addCollision(self, model):
        # Setup a collision solid for this model.
        pushColl = self.initCollisionSphere(model, .7, False)#List variable for pusher
        pushaColl = pushColl[0]#Non-list varible for the pusher 

        # Add this object to the traverser.
        
        # Accept the events sent by the collisions.
        self.accept('into-' + pushColl[1], self.collideIn)
        self.accept('outof-' + pushColl[1], self.collideOut)

        self.pusher.addCollider(pushaColl, model, base.drive.node())
        base.cTrav.addCollider(pushaColl, self.pusher)

        print(pushColl[1])

    def collideIn(self, collEntry):
        print("FUUUUUUU- FUCKING EXPLOSION")
        self.collision = True
        
    def collideOut(self, collEntry):
        print("D: OH SHIT WE DIED")
        self.collision = False
        
    def initCollisionSphere(self, obj, sizeMult, show=False):
        # Get the size of the object for the collision sphere.
        bounds = obj.getChild(0).getBounds()
        center = bounds.getCenter()
        radius = bounds.getRadius() * sizeMult
        
        # Create a collision sphere and name it something understandable.
        collSphereStr = 'CollisionHull' + str(self.collCount) + "_" + obj.getName()
        self.collCount += 1
        cNode = CollisionNode(collSphereStr)
        cNode.addSolid(CollisionSphere(center, radius))
        
        cNodepath = obj.attachNewNode(cNode)
        if show:
            cNodepath.show()#Shows the collision model
            
        print collSphereStr
        
        # Return a tuple with the collision node and its corrsponding string so
        # that the bitmask can be set.
        return (cNodepath, collSphereStr)
        
    def addlight(self): #create the light
        #create a directional light to give a sense of 3d ness
        dlight = DirectionalLight('dlight')
        dlight.setColor(VBase4(0.8, 0.8, 0.8, 1))
        dlight.setShadowCaster(True)
        dlnp = render.attachNewNode(dlight)
        dlnp.setHpr(0, -60, 0)
        render.setLight(dlnp)
        render.setShaderAuto()
        
    def addWinProps(self):
        #defines the windows properties aka title and hide cursor etc
        props = WindowProperties()
        props.setCursorHidden(True)
        props.setTitle('Space Fighter')
        base.win.requestProperties(props)
        
    def loadShip(self): # just loads the ship model
        self.ship = loader.loadModel('ship')
        self.ship.reparentTo(render)
        self.ship.setTwoSided(True)
        self.ship.setScale(.5)
        self.addCollision(self.ship)#adds a collision/pusher to the ship model
        
    def loadAI(self):
        self.ai = loader.loadModel('ai')
        self.ai.reparentTo(render)
        self.ai.setTwoSided(True)
        self.ai.setScale (.5)
        self.addCollision(self.ai)#adds a collision/pusher to the ai model
        
    def shoot(self):
        self.accept('mouse1', self.loadAmmo)
        
    def loadAmmo(self):
        self.ammo = loader.loadModel('bullet')
        self.ammo.setScale(.2)
        self.ammo.reparentTo(render)
        self.ammo.setPos(self.ship.getPos())
        taskMgr.add(self.updateAmmoPos, 'move ammo')
        
    def loadWorld(self): # loads world
        self.world = loader.loadModel('level')
        self.world.reparentTo(render)
        self.world.setPos(-1, 30, 3)
        self.world.setScale(80)
        #self.addCollision(self.world)#adds a collision/pusher to the world model. commented out            cause 'you dont need world collisions' :P
        
    def setCamera(self): # sets the camera lense
        place = base.cam.node().getLens()
        place.setFov(70)
        base.cam.node().setLens(place)
        base.camera.reparentTo(self.ship)
        base.camera.setY(-30)
        base.camera.setZ(5)
        
    def mouseUpdate(self,task): # updates the mouse and changes ships P and H accordingly
        md = base.win.getPointer(0)
        x = md.getX()
        y = md.getY()
        if base.win.movePointer(0, base.win.getXSize()/2, base.win.getYSize()/2):
            self.ship.setP(self.ship.getP() -  (y - base.win.getYSize()/2)*0.1)
            self.ship.setH(self.ship.getH() - (x - base.win.getXSize()/2)*0.1)
        return task.cont
        
    def createControls(self): # changes the value of walk to either STOP or Forward depending on the keypress
        base.accept( "w" , self.__setattr__,["walk",self.FORWARD])
        base.accept( "w-up" , self.__setattr__,["walk",self.STOP] )
        
    def updateShipPos(self,task): # task to move the ship and camera
        self.ship.setPos(self.ship,self.walk*self.speed)
        return task.cont
        
    def updateAmmoPos(self, task):
        ammoPosX = self.ammo.getH()
        ammoPosY = self.ammo.getP()
        ammoPosZ = self.ammo.getR()
        self.ammo.setPos(self.ammo, ammoPosX, ammoPosY+.1, ammoPosZ)
        

        return task.cont
        
Game()
run()

Try adding the following lines of code to loadAmmo after self.ammo.setPos(self.ship.getPos()) so that the bullet is oriented exactly the way the ship is.

self.ammo.setH(self.ship.getH())
self.ammo.setR(self.ship.getR())
self.ammo.setP(self.ship.getP())

And update the bullet in the same way you update the ship, removing the other code

self.ammo.setPos(self.ammo, speed)

You might want to take a look at the Asteroids sample.

orientation = ship.getHpr()
bullet.setHpr(orientation)

to move bullet forward one unit per frame

bullet.setY(bullet,1)

you probably want to move bullet forward dependant on frametime, this will move bullet forward 100 units(lets pretend its meters) per second

bullet.setY(bullet,100*frametime)

This means if you are running your game at 60 FPS, frametime is 1/60 = 0.0167, so bullet will move 1.67 units forward in one frame if game is running at 60 FPS

I started writing some sample few months ago, but didnt have time to cotinue improving it, you might find some interesting stuff there
dl.dropbox.com/u/14000546/src.7z