Adding object upon key press

Hi, I’m having an issue creating an object when I press space bar. My final goal is to have roaming ralph fire a projectile, but for now, I’m just trying to get ralph to create an object (that later will be a projectile) when I press space bar. my current code is

self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "select-target":0, "fire":0}

self.accept("spacebar", self.setKey, ["fire",1])
self.accept("spacebar", self.setKey, ["fire", 0])




if (self.keyMap["fire"] != 0):
            self.bear = Actor("models/osito2")
            self.bear.reparentTo(render)
            self.bear.setScale(20)
            self.bear.setPos(5,25,3.5)
            self.bear.lookAt(180,0,0)

I know this idea isn’t logically finished, but I figured if I can’t get this to happen, there’s no reason to go ahead and work on the velocity or anything else. The rest of my code if you need it, is below.

import direct.directbase.DirectStart
from panda3d.core import CollisionTraverser,CollisionNode
from panda3d.core import CollisionHandlerQueue,CollisionRay
from panda3d.core import Filename,AmbientLight,DirectionalLight
from panda3d.core import PandaNode,NodePath,Camera,TextNode
from panda3d.core import Vec3,Vec4,BitMask32
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
from direct.showbase.DirectObject import DirectObject
import random, sys, os, math

SPEED = 0.5
BULLET_LIFE = 2

# Function to put instructions on the screen.
def addInstructions(pos, msg):
    return OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                        pos=(-1.3, pos), align=TextNode.ALeft, scale = .05)

# Function to put title on the screen.
def addTitle(text):
    return OnscreenText(text=text, style=1, fg=(1,1,1,1),
                        pos=(1.3,-0.95), align=TextNode.ARight, scale = .07)

class World(DirectObject):

    def __init__(self):
        
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "select-target":0, "fire":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        # Post the instructions

        self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst5 = addInstructions(0.70, "[Down Arrow]: Ralph Runs Backwards")
        self.inst6 = addInstructions(0.65, "[S]: Select Target")
        self.inst7 = addInstructions(0.60, "[Space]: Fire Weapon")
        
        
        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)
        
        #create bear1 target
        self.bear = Actor("models/osito")
        self.bear.reparentTo(render)
        self.bear.setScale(1)
        self.bear.setPos(5,25,3.5)
        self.bear.lookAt(180,0,0)
        
        #create bear2 target
       # self.bear = Actor("models/osito2")
       # self.bear.reparentTo(render)
        #self.bear.setScale(1)
        #self.bear.setPos(5,20,3.5)
        #self.bear.lookAt(180,0,0)
        
        

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["select-target",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("arrow_down-up", self.setKey, ["backward",0])
        self.accept("s-up", self.setKey, ["select-target",0])
        self.accept("spacebar", self.setKey, ["fire",1])
        self.accept("spacebar", self.setKey, ["fire", 0])
        

        taskMgr.add(self.move,"moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        
        base.disableMouse()
        #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+5,2)
        
        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
    
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    

  

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.
        if (self.keyMap["select-target"]!=0):
            self.ralph.lookAt(self.bear)
            self.ralph.setH(self.ralph.getH()-180)
            
        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["backward"]!=0):
            self.ralph.setY(self.ralph, 10 * globalClock.getDt())
            
        if (self.keyMap["fire"] != 0):
            self.bear = Actor("models/osito2")
            self.bear.reparentTo(render)
            self.bear.setScale(20)
            self.bear.setPos(5,25,3.5)
            self.bear.lookAt(180,0,0)
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        
        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)
       
       
       
       
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(self.ralph, 0, 30, 8)
        base.camera.setHpr(0,180,180)
        
        
        
        return task.cont


w = World()
run()

Hmm… What problem are you seeing? Is there an error? Does it crash? Is there simply no apparent object?

Offhand I don’t see any significant problems. Are you sure that the position that you’re setting for your object is somewhere that you can see, and that the model is valid?

The object is not appearing. I’m sure the location is somewhere that is visible, because I already placed that object in those coordinates, and I tried making the object 10 times the size, just in case (and 20 times the size). I’m getting no error, and no crashes. The object just doesn’t show when I hit the space bar. I would get an error message if the model wasn’t valid, correct? I’ll try a different model made to be a projectile just in case, but other than that, I’ve done all the trouble shooting I know how to do.

In that case, I suggest – if you haven’t done this already – a sprinkling of “print” statements: one at the start of the “move” method, to make sure that it is, in fact, being called; one just above “if (self.keyMap[“fire”] != 0):”, to check that it’s getting that far; and one just after that same line, to check that it’s getting into that section of code. What you have the print statements print is up to you, but I recommend that they each be different, in order to differentiate them; 1, 2 and 3, respectively, should work well.

What we look at after that depends on how far your code is actually getting.

[edit] Ah, wait! I believe that I may see the problem!

I took another look through your code, and spotted the following:

        self.accept("spacebar", self.setKey, ["fire",1])
        self.accept("spacebar", self.setKey, ["fire", 0])

Note that you’re accepting the same event – the space-bar being pressed – for both setting and unsetting the “fire” key. What I think is happening is that two events are being fired when you press the space-bar: first, one that effectively runs ‘self.keyMap[“fire”] = 1’, followed immediately by one that effectively runs ‘self.keyMap[“fire”] = 0’, undoing the effect of the previous event.

That makes sense, but when I removed the self.accept(“spacebar”, self.setKey, [“fire”, 0]) completely from the code, I think that should have fixed it, and it didn’t.

Well, I would expect that to result in your object spawning every frame until you end the program, since the ‘self.keyMap[“fire”]’ is presumably never set to 0 (indeed, unless you want repeated firing – in which case you may want a timer in the bullet-spawning code – you might want to set ‘self.keyMap[“fire”]’ to 0 after spawning your object; in fact, I recommend doing so while performing this test, against repeated spawning having some untoward effect).

I recommend that you restore the “accept” call that you say that you just removed, but have it accept “spacebar-up”, so that your “fire” key variable is set to 0 when the space-bar is released – look at the other “accept” calls for comparison.

The reason why it didn’t trigger is because the event is called “space”, not “spacebar”.

If you simply want to create an object once whenever you press the space bar, forget about the setKey and KeyMap stuff. That’s just for remembering which key is currently pressed so that something can be done every frame. You should do something like:

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

Then, create a method spawn_object in which you create the object, instead of in a task. You also will want to append the object you create to a list instead of assigning it to self.bear, since you’re otherwise overwriting the only reference to the old Actor object.

You’ll probably also want to give it a unique position every time, otherwise you’re creating them in the exact same position and won’t be able to see the second one (since it’s right over the first one).

Thanks for the responses, they both helped me understand what’s going on a bit more. I’ve changed the code, and I’m still getting no errors, and the codes not working as expected. I’ve set my projectile to spawn where ralph is located when space is pressed. Nothing is showing, and I’ve tested the model, and know it’s not transparent, and I’ve also tried setting its scale to something huge so in case it’s spawning somewhere odd, i could see it, but no luck.

with this code:

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



def fire(self):
        pos = self.ralph.getPos
        projectile = loader.loadModel("models/projectile1")
        projectile.setScale(20)
        projectile.setPos(pos)

Once again, the full updated code in case it helps.

import direct.directbase.DirectStart
from panda3d.core import CollisionTraverser,CollisionNode
from panda3d.core import CollisionHandlerQueue,CollisionRay
from panda3d.core import Filename,AmbientLight,DirectionalLight
from panda3d.core import PandaNode,NodePath,Camera,TextNode
from panda3d.core import Vec3,Vec4,BitMask32
from direct.gui.OnscreenText import OnscreenText
from direct.actor.Actor import Actor
from direct.showbase.DirectObject import DirectObject
import random, sys, os, math

SPEED = 0.5
BULLET_LIFE = 2

# Function to put instructions on the screen.
def addInstructions(pos, msg):
    return OnscreenText(text=msg, style=1, fg=(1,1,1,1),
                        pos=(-1.3, pos), align=TextNode.ALeft, scale = .05)

# Function to put title on the screen.
def addTitle(text):
    return OnscreenText(text=text, style=1, fg=(1,1,1,1),
                        pos=(1.3,-0.95), align=TextNode.ARight, scale = .07)

class World(DirectObject):

    def __init__(self):
        
        self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "cam-left":0, "select-target":0, "fire":0}
        base.win.setClearColor(Vec4(0,0,0,1))

        # Post the instructions

        self.title = addTitle("Panda3D Tutorial: Roaming Ralph (Walking on Uneven Terrain)")
        self.inst1 = addInstructions(0.95, "[ESC]: Quit")
        self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left")
        self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right")
        self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward")
        self.inst5 = addInstructions(0.70, "[Down Arrow]: Ralph Runs Backwards")
        self.inst6 = addInstructions(0.65, "[S]: Select Target")
        self.inst7 = addInstructions(0.60, "[Space]: Fire Weapon")
        
        
        # Set up the environment
        #
        # This environment model contains collision meshes.  If you look
        # in the egg file, you will see the following:
        #
        #    <Collide> { Polyset keep descend }
        #
        # This tag causes the following mesh to be converted to a collision
        # mesh -- a mesh which is optimized for collision, not rendering.
        # It also keeps the original mesh, so there are now two copies ---
        # one optimized for rendering, one for collisions.  

        self.environ = loader.loadModel("models/world")      
        self.environ.reparentTo(render)
        self.environ.setPos(0,0,0)
        
        # Create the main character, Ralph

        ralphStartPos = self.environ.find("**/start_point").getPos()
        self.ralph = Actor("models/ralph",
                                 {"run":"models/ralph-run",
                                  "walk":"models/ralph-walk"})
        self.ralph.reparentTo(render)
        self.ralph.setScale(.2)
        self.ralph.setPos(ralphStartPos)
        
        #create bear1 target
        self.bear = Actor("models/osito")
        self.bear.reparentTo(render)
        self.bear.setScale(1)
        self.bear.setPos(5,25,3.5)
        self.bear.lookAt(180,0,0)
        
        #create bear2 target
       # self.bear = Actor("models/osito2")
       # self.bear.reparentTo(render)
        #self.bear.setScale(1)
        #self.bear.setPos(5,20,3.5)
        #self.bear.lookAt(180,0,0)
        
        

        # Create a floater object.  We use the "floater" as a temporary
        # variable in a variety of calculations.
        
        self.floater = NodePath(PandaNode("floater"))
        self.floater.reparentTo(render)

        # Accept the control keys for movement and rotation

        self.accept("escape", sys.exit)
        self.accept("arrow_left", self.setKey, ["left",1])
        self.accept("arrow_right", self.setKey, ["right",1])
        self.accept("arrow_up", self.setKey, ["forward",1])
        self.accept("arrow_down", self.setKey, ["backward",1])
        self.accept("a", self.setKey, ["cam-left",1])
        self.accept("s", self.setKey, ["select-target",1])
        self.accept("arrow_left-up", self.setKey, ["left",0])
        self.accept("arrow_right-up", self.setKey, ["right",0])
        self.accept("arrow_up-up", self.setKey, ["forward",0])
        self.accept("arrow_down-up", self.setKey, ["backward",0])
        self.accept("s-up", self.setKey, ["select-target",0])
        #self.accept("spacebar", self.setKey, ["fire",1])
        #self.accept("spacebar", self.setKey, ["fire", 0])
        self.accept("space", self.fire)

        taskMgr.add(self.move,"moveTask")

        # Game state variables
        self.isMoving = False

        # Set up the camera
        
        base.disableMouse()
        #base.camera.setPos(self.ralph.getX(),self.ralph.getY()+5,2)
        
        # We will detect the height of the terrain by creating a collision
        # ray and casting it downward toward the terrain.  One ray will
        # start above ralph's head, and the other will start above the camera.
        # A ray may hit the terrain, or it may hit a rock or a tree.  If it
        # hits the terrain, we can detect the height.  If it hits anything
        # else, we rule that the move is illegal.

        self.cTrav = CollisionTraverser()

        self.ralphGroundRay = CollisionRay()
        self.ralphGroundRay.setOrigin(0,0,1000)
        self.ralphGroundRay.setDirection(0,0,-1)
        self.ralphGroundCol = CollisionNode('ralphRay')
        self.ralphGroundCol.addSolid(self.ralphGroundRay)
        self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol)
        self.ralphGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler)

        self.camGroundRay = CollisionRay()
        self.camGroundRay.setOrigin(0,0,1000)
        self.camGroundRay.setDirection(0,0,-1)
        self.camGroundCol = CollisionNode('camRay')
        self.camGroundCol.addSolid(self.camGroundRay)
        self.camGroundCol.setFromCollideMask(BitMask32.bit(0))
        self.camGroundCol.setIntoCollideMask(BitMask32.allOff())
        self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol)
        self.camGroundHandler = CollisionHandlerQueue()
        self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler)

        # Uncomment this line to see the collision rays
        #self.ralphGroundColNp.show()
        #self.camGroundColNp.show()
       
        # Uncomment this line to show a visual representation of the 
        # collisions occuring
        #self.cTrav.showCollisions(render)
        
        # Create some lighting
        ambientLight = AmbientLight("ambientLight")
        ambientLight.setColor(Vec4(.3, .3, .3, 1))
        directionalLight = DirectionalLight("directionalLight")
        directionalLight.setDirection(Vec3(-5, -5, -5))
        directionalLight.setColor(Vec4(1, 1, 1, 1))
        directionalLight.setSpecularColor(Vec4(1, 1, 1, 1))
        render.setLight(render.attachNewNode(ambientLight))
        render.setLight(render.attachNewNode(directionalLight))
    
    #Records the state of the arrow keys
    def setKey(self, key, value):
        self.keyMap[key] = value
    
    def fire(self):
        pos = self.ralph.getPos()
        projectile = loader.loadModel("models/projectile1")
        projectile.setScale(20)
        projectile.setPos(pos)
  

    # Accepts arrow keys to move either the player or the menu cursor,
    # Also deals with grid checking and collision detection
    def move(self, task):

        # save ralph's initial position so that we can restore it,
        # in case he falls off the map or runs into something.

        startpos = self.ralph.getPos()

        # If a move-key is pressed, move ralph in the specified direction.
        if (self.keyMap["select-target"]!=0):
            self.ralph.lookAt(self.bear)
            self.ralph.setH(self.ralph.getH()-180)
            
        if (self.keyMap["left"]!=0):
            self.ralph.setH(self.ralph.getH() + 300 * globalClock.getDt())
        if (self.keyMap["right"]!=0):
            self.ralph.setH(self.ralph.getH() - 300 * globalClock.getDt())
        if (self.keyMap["forward"]!=0):
            self.ralph.setY(self.ralph, -25 * globalClock.getDt())
        if (self.keyMap["backward"]!=0):
            self.ralph.setY(self.ralph, 10 * globalClock.getDt())
            
        #if (self.keyMap["fire"] != 0):
        #    self.bear = Actor("models/osito2")
        #    self.bear.reparentTo(render)
        #    self.bear.setScale(20)
        #    self.bear.setPos(5,25,3.5)
        #    self.bear.lookAt(180,0,0)
        
        # If ralph is moving, loop the run animation.
        # If he is standing still, stop the animation.

        if (self.keyMap["forward"]!=0) or (self.keyMap["left"]!=0) or (self.keyMap["right"]!=0) or (self.keyMap["backward"]!=0):
            if self.isMoving is False:
                self.ralph.loop("run")
                self.isMoving = True
        else:
            if self.isMoving:
                self.ralph.stop()
                self.ralph.pose("walk",5)
                self.isMoving = False

        
        # Now check for collisions.

        self.cTrav.traverse(render)

        # Adjust ralph's Z coordinate.  If ralph's ray hit terrain,
        # update his Z. If it hit anything else, or didn't hit anything, put
        # him back where he was last frame.

        entries = []
        for i in range(self.ralphGroundHandler.getNumEntries()):
            entry = self.ralphGroundHandler.getEntry(i)
            entries.append(entry)
        entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(),
                                     x.getSurfacePoint(render).getZ()))
        if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"):
            self.ralph.setZ(entries[0].getSurfacePoint(render).getZ())
        else:
            self.ralph.setPos(startpos)
       
       
       
       
        base.camera.reparentTo(self.ralph)
        base.camera.setPos(self.ralph, 0, 30, 8)
        base.camera.setHpr(0,180,180)
        
        
        
        return task.cont


w = World()
run()

You forgot to reparent the new projectile to the scene graph. Try this

def fire(self):
        pos = self.ralph.getPos()
        print "firing projectile at", pos
        projectile = loader.loadModel("models/projectile1")
        projectile.reparentTo(render)
        projectile.setPos(pos)
        print "the projectile is now at",projectile.getPos()

If there’s no printing to the output window, you’re not calling the event right. If there is, the prints should help you see what’s going wrong.

Beautiful, thanks to everybody, it’s working now. Now I can move on to making the projectile fire where I want it too. Thanks again, I appreciate all the help.