bullet, objects bounce off invisible non existent object

hi again

have made a test scenario where a bunch of ships flt from waypoint to waypoint and uses bullet for the thrust.

however for some reason the ships all bounce off a non-existent shape that i didn’t create.

my code is quite a hacked bundle of information, so if its bad sorry. still help would be appreciate.

__author__ = 'fam'

# space vessels that journey from one spehere to another
# no bullet to start with
import direct.directbase.DirectStart
from panda3d.core import *
from direct.gui.DirectGui import *
from panda3d.core import Vec3, Vec4
from direct.interval.IntervalGlobal import *
from panda3d.core import Quat
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
from direct.showbase.InputStateGlobal import inputState # get keyboard & mouse inputs

from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletSphereShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletDebugNode
from panda3d.core import BitMask32

import random
import time

class Fleet():
    fleet_list = []

    def __init__(self, bulletworld,size = 5):
        #print ("making fleet")
        self.fleet_size = size
        self.bullet_world = bulletworld
        self.make_fleet()
        self.target_list = []
        self.curr_target = 0

    def random_targets(self,number = 5):
        self.numTargets = number
        for each in range(0,self.numTargets):
            self.target_list.append(random.randrange(-10,10),random.randrange(-10,10),random.randrange(-10,10) )
        print ("target list is", self.target_list)

    def make_fleet(self):
        self.tempz = []
        self.tempC = []
        numba = self.fleet_size
        tpoz = [random.randint(6,6),random.randint(-7,7),random.randint(-12,12)]
        for number in range(0,numba):
            #print ("number is", number)
            ship1 = Craft(self.bullet_world)
            t = ship1.load_ship()
            Fleet.fleet_list.append(t)
            self.tempz.append(t)
            self.tempC.append(ship1)

            self.tempz[number].setPos(tpoz[0]+(2*number), tpoz[1]+random.random()*3,tpoz[2]+random.random()*3)
            #self.tempz[number].setPos(random.randint(-6,6),random.randint(-9,7),random.randint(-8,8))
            #print (tempz)
        return self.tempz

    def get_ships(self):
        return self.tempz

    def fly_fleet(self,dt):
        for shipz in self.tempC:
            shipz.fly(dt)



class Craft():
    ship_list = []
    arrived_count = 0
    targetPos = [(10,0,5),(-10,0,10),(14,5,15)]
    target_count = 0
    target_iter = 0
    mask1 = BitMask32.allOn()
    mask2 = BitMask32.allOff()
    mask3 = BitMask32.bit(2)
    mask4 = BitMask32.bit(5)
    mask5 = BitMask32(0x3)

    craft_types = ["rocket1","spacestation","cruiser"]

    def __init__(self,bulletworld):
        self.bulletWorld = bulletworld
        #print ("making ships")
        self.type = 0 #default is rocket1
        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1
        self.accel_rate = 1
        self.decel_rate = 5
        self.max_speed = 2
        self.turn_rate = random.randint(2,7)
        self.health = 100
        self.speedNow = 0.0
        self.curr_waypoint = 0
        self.waypoints = [(10,0,0),(-12,-4,-5),(14,5,6)]

        #[(random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5)),(random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5)),(2+random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5))]
        setupTarget = self.makeTarget()


        self.cruise_speed = self.max_speed/.75
        self.ID = len(Craft.ship_list)
        self.armour=150
        self.flyable = True
        self.startCount = 0
        self.hasArrived = 0
        #print ("ship ID is " , self.ID)


    def setType(self,type):
        self.type = type


    def setPosition(self,x,y,z):
        self.ship_root.setPos(x,y,z)

    def makeTarget(self):
        self.target =  render.attachNewNode('target' + str(len(Craft.ship_list)))
        self.target_mesh = loader.loadModel('box')
        self.target_mesh.reparentTo(self.target)
        #self.target.setPos(Craft.targetPos[Craft.target_count][0],Craft.targetPos[Craft.target_count][1],Craft.targetPos[Craft.target_count][2])
        self.target.setPos(self.waypoints[self.curr_waypoint][0],self.waypoints[self.curr_waypoint][1],self.waypoints[self.curr_waypoint][2])
        print ("traget ", Craft.targetPos[0])
        Craft.target_count += 1
        self.target.setRenderModeWireframe()
        if Craft.target_count >2:
            Craft.target_count = 0
        return self.target

    def moveTarget(self,x,y,z):
        self.target.setPos(x,y,z)





    def load_ship(self):
        print ("drawing ship", len(Craft.ship_list))
        print ("")
        shape =  BulletBoxShape(Vec3(0.5,0.5,0.5))
        self.ship_root = render.attachNewNode(BulletRigidBodyNode('shipNode'+str(len(Craft.ship_list))))
        self.ship = loader.loadModel(Craft.craft_types[0])
        self.ship_root.node().setMass(1)
        self.ship_root.node().addShape(shape)
        Craft.ship_list.append(self.ship_root)
        self.ship.reparentTo(self.ship_root)
        #self.ship_root.setPos(0,0,0)
        self.ship.setHpr(180,0,0)
        self.ship_root.setScale(0.1*self.sizescale)
        self.bulletWorld.attachRigidBody(self.ship_root.node())
        self.ship_root.setCollideMask(Craft.mask2)




        return self.ship_root


    def loadParticleConfig(self, file):
        #Start of the code from steam.ptf
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(file))
        #Sets particles to birth relative to the teapot, but to render at toplevel
        self.p.start(self.t)
        self.p.setPos(3.000, 0.000, 2.250)

    def load_cruiser(self):
        print ("drawing cruiser", len(Craft.ship_list))
        print ("")
        shape =  BulletBoxShape(Vec3(0.5,0.5,0.5))
        self.ship_root = render.attachNewNode(BulletRigidBodyNode('cruiserNode'+str(len(Craft.ship_list))))
        self.ship = loader.loadModel(Craft.craft_types[2])
        self.ship_root.node().setMass(10)
        self.ship_root.node().addShape(shape)


        Craft.ship_list.append(self.ship_root)
        self.ship.reparentTo(self.ship_root)
        #self.ship_root.setPos(0,0,0)
        self.ship.setHpr(180,0,0)
        self.ship_root.setScale(2*self.sizescale)
        self.bulletWorld.attachRigidBody(self.ship_root.node())
        self.ship_root.setHpr(random.randint(0,220),0,0)
        return self.ship_root



    def fly(self,dt):
        #check angle
        self.dt = dt
        angleBase = self.ship_root.getHpr()
        angleTarget = self.pointAt(self.ship_root,self.target)
        angleDiff = angleBase - angleTarget
        total_angle = angleDiff[0]+angleDiff[1]
        dist = self.get_distance(self.ship_root,self.target)

        tForce = 3.0

        if self.startCount == 0:
            self.startCount = time.clock()
            self.pos1 = self.ship_root.getPos()
        if time.clock() - self.startCount >=  1:
            self.pos2 = self.ship_root.getPos()
            timePast = time.clock() - self.startCount
            calcDist = self.pos2 - self.pos1
            distL = calcDist.length()
            self.speedNow = distL/timePast
            #print ("at dist", dist, "for ship ID" , self.ID, "current speed is" , self.speedNow , "over", timePast)
            self.startCount = 0

        if dist >=7:
                tForce = 10.0
        elif dist <6 and dist > 4:
            tForce = 5.0
        elif dist <= 2 and self.speedNow > 0:
            tForce = 1
        elif dist<=1:
            self.hasArrived = 1
            Craft.arrived_count += 1
            self.curr_waypoint += 1
            self.ship.setColor(1,0,0)
            #self.target.setPos(Craft.targetPos[Craft.target_iter][0],Craft.targetPos[Craft.target_iter][1],Craft.targetPos[Craft.target_iter][2])
            if self.curr_waypoint >len(self.waypoints):
                self.curr_waypoint = 0


        tForce = self.speed_limiter(tForce)

        if self.hasArrived == 1:
            self.change_target()

        if abs(total_angle) > 5:
            qAngle = self.quat_by_quat(self.ship_root,self.target)
            self.turn_towards(self.ship_root,qAngle,self.turn_rate)
        elif abs(total_angle) <= 30: # pointing in general direction so start moving
            self.move_fowards(self.ship_root,self.target,tForce)

        self.obst = self.check_obstacles(10)
       # print ("obstacle is selfobst ", self.obst)

        self.safe_dist = self.max_speed

    def speed_limiter(self,tforce):
        if self.speedNow >= self.max_speed:
            self.ship_root.node().setLinearVelocity(self.max_speed)
            return 0
        else:
            return tforce

    def change_target(self):
        self.target.setPos(Craft.targetPos[Craft.target_iter][0],Craft.targetPos[Craft.target_iter][1],Craft.targetPos[Craft.target_iter][2])
        self.hasArrived = 0



    def take_evasive(self,enemypos):
        print ("enemy ahead at", enemypos)


    def check_safe_distance(self,base,target):
        #in a nutshell get the pos where the ship will be in vec * time
        # time to deceltime = dist/decel_speed
        time_decel = target.getPos()/self.decel_rate


    def intercept_pos(self,base,target,speed):
        temp_pos = target.getPos()
        temp_dir = target.getHpr()
        temp_speed = speed
        dist = self.get_distance(base,target)
        bullets_speed = 1.0
        temp_time = dist/bullets_speed
        temp_vec = render.getRelativeVector(node,Vec3(0,1,0))
        projected_pos = temp_vec * temp_time
        return projected_pos



    def check_obstacles(self,dist = 50):
        pFrom = self.ship_root.getPos()
        pTo = pFrom + Vec3(0,1,0)*dist

        result = self.bulletWorld.rayTestClosest(pFrom, pTo)

        if result.hasHit() == True:
            obstacle = result.getNode()
            obstaclePos = result.getHitPos()
            print ("for ship ID", self.ID," obstacle is ", obstacle, "at ",obstaclePos)
            tPos = (self.ship_root.getPos() - obstaclePos).length()

            return obstacle

    def get_distance(self,base,target):
        target_vec = base.getPos() - target.getPos()
        distance = target_vec.length()
        return distance

    def get_dist_vec3(self,base,target):
        target_vec = base - target
        distance = target_vec.length
        return distance

    def quat_by_quat(self,base,obj2):
        #takes 2 objects
        # gets pos and quat of obj1
        # get required quat to point at obj2
        #return difference
        obj1 = base
        quat1 = obj1.getQuat()
        pos1 = obj1.getPos()
        obj1Dir = quat1.getForward()
        obj1Dir.normalize()
        #v = obj1Dir
        vec2obj2 = obj2.getPos() - pos1
        vec2obj2.normalize()
        angleTowards = self.pointAt(base,obj2)
        #print ("quat1 and asngeltwards" , quat1, angleTowards)
        angleinQuat = Quat()
        angleinQuat.setHpr(Vec3(angleTowards))
        #print ("angle in quat is ", angleinQuat)
        #qSubq =  quat1 - angleinQuat
        #print ("angle to turn is ",qSubq)
        #obj1.setQuat(angleinQuat)
        return angleinQuat

    def pointAt(self, base,target):
        self.tempNode = render.attachNewNode('tempNode')
        self.tempNode.setPos(base.getPos())
        self.tempNode.setHpr(base.getHpr())
        self.tempNode.lookAt(target)
        tempVec = self.tempNode.getHpr()
        #print ("tempVec is", tempVec)
        return tempVec

    def turn_towards(self,base,angle,turnspeed):
        myInterval1 = base.hprInterval(turnspeed, angle)
        seq = Parallel(myInterval1)
        seq.start()

    def calc_speed(self):
        """returns a point in time. do it twice to work out speed"""
        tPos = self.ship_root.getPos()
        timeSlice = time.clock()
        return tPos, timeSlice


    def move_fowards(self,base,target,forceT = 5.0):
        force =  Vec3(0, 0, 0) # Forward
        torque = Vec3(0, 0 ,0)
        target_vec = base.getPos() - target.getPos()
        #distance = target_vec.length()
        #curVec = render.getRelativeVector(base,Vec3(0,1,0))
        force.setY(forceT)
        base.node().setActive(True)
        torque = render.getRelativeVector(base,torque)
        base.node().applyTorque(torque)
        force = render.getRelativeVector(base, force)
        #print ("force is", force , " for ID" , base)
        base.node().applyCentralForce(force)


    def decel(self):
        curSpeed = self.speedNow
        decelRate = -2


class Solar_body():
    body_list = []
    def __init__(self):
        print ("making planets")
        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1
        self.planetsScales = [1,2]
        newSys = self.gen_system()

    def gen_system(self,planetNum= 4):
        self.num_planets = planetNum
        #newSun = self.make_sun()
        for each in range(0,self.num_planets):
            chanceMoon = random.random()
            hasMoon = False
            if chanceMoon >0.4:
                hasMoon = True
            tempX=random.randint(10*each,20*each)
            tempSize = random.randrange(self.planetsScales[0],self.planetsScales[1])
            newPlanet = self.loadPlanets(tempX,tempSize,hasMoon)
            Solar_body.body_list.append(newPlanet)


    def make_sun(self,size=3):
        self.sun = loader.loadModel('planet_sphere')
        self.sun_tex = loader.loadTexture("models/sun_1k_tex.jpg")
        self.sun.setTexture(self.sun_tex, 1)
        self.sun.reparentTo(render)
        self.sun.setScale(size * self.sizescale)


    def loadPlanets(self,posi,scale,hasMoon):
        planet_pos = posi
        planet_scale = scale
        self.orbit_root_planet = render.attachNewNode('orbit_planet' + str(len(Solar_body.body_list)))
        self.planet1 = loader.loadModel("models/planet_sphere")
        self.p1_tex = loader.loadTexture("models/mercury_1k_tex.jpg")
        self.planet1.setTexture(self.p1_tex, 1)
        self.planet1.reparentTo(self.orbit_root_planet)
        self.planet1.setPos( planet_pos * self.orbitscale, 0, 0)
        self.planet1.setScale(planet_scale * self.sizescale)

        if hasMoon == True:
            print ("has moon")
            self.orbit_root_moon = self.orbit_root_planet.attachNewNode('orbit_planet' + str(len(Solar_body.body_list)))
            self.moon = loader.loadModel("models/asteroid")
            self.moon_tex = loader.loadTexture("models/moon_1k_tex.jpg")
            self.moon.setTexture(self.p1_tex, 1)
            self.moon.reparentTo(self.orbit_root_moon)
            self.moon.setPos( random.randrange(-3,3), -3, -5)
            self.moon.setScale((planet_scale/2) * self.sizescale)


        return self.orbit_root_planet





class World(DirectObject):

    AI_list = []

    def __init__(self):
        base.setBackgroundColor(0.31,0.351,0.453)
        base.disableMouse()
        camera.setPos(0,60,5)
        camera.lookAt(5,5,0)
        self.ship_list = []

        base.enableParticles()
        base.wireframeOn()

        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1

        self.accept('escape',self.doExit)
        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('back', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('up', 'q')
        inputState.watchWithModifiers('down', 'z')
        inputState.watchWithModifiers('mouseTorque', 'mouse3')
        inputState.watchWithModifiers('slow','space')
        inputState.watchWithModifiers('accelerate','lshift')
        inputState.watchWithModifiers('pickIt','mouse1')


        taskMgr.add(self.gameLoop, "gameLoop")
        self.all_fleets = []
        self.startBullet()

        self.setLight()

        planets = Solar_body()

        fl1 = Fleet(self.world,5)
        cruiser1 = Craft(self.world)

        #self.fleet1 = Craft()
        #self.fleet1.create_fleet(4)
        #print ("fl1 is", fl1)

        #print ("all fleets are", self.all_fleets)
        World.AI_list.append(fl1)





    def turn_debug_on(self):
        debugNode = BulletDebugNode('Debug')
        debugNode.showWireframe(True)
        debugNode.showConstraints(True)
        debugNode.showBoundingBoxes(True)
        debugNode.showNormals(True)
        debugNP = render.attachNewNode(debugNode)
        #self.world.setDebugNode(debugNP.node())
        debugNP.show()
        self.world.setDebugNode(debugNP.node())

    def startBullet(self):
        print ("starting bullet")
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0,0,0))
        self.turn_debug_on()



    def doExit():
        sys.Exit(1)

    def gameLoop(self,task):
        dt = globalClock.getDt()

        self.processInput(dt)
        #frameTime = globalClock.getFrameTime()
        self.world.doPhysics(dt, 100, 1./500.)
        self.think_AI(dt)
        return Task.cont

    def think_AI(self,dt):
        num_ai = len(World.AI_list)
        for each in range(0,num_ai):

            temp = World.AI_list[each].get_ships()
            print ("temp ships is ",temp)
            World.AI_list[each].fly_fleet(dt)






    def processInput(self,dt):
        moveto=[]
        force =  Vec3(0, 0, 0) # Forward
        torque = Vec3(0, 0 , 0)

        if inputState.isSet('forward'):
            force.setY(1.0)

        if inputState.isSet('back'):
            force.setY(-1.0)

        if inputState.isSet('right'):
            force.setX(-1.0)

        if inputState.isSet('left'):
            force.setX(1.0)

        if inputState.isSet('up'):
            torque.setX(0.5)

        if inputState.isSet('down'):
            torque.setX(-0.5)

        if inputState.isSet('slow'):
            #print ("camera pos is", self.camX, self.camY , self.camZ)
            #angle_change = self.player.node().getAngularVelocity()
            #current_speed = self.player.node().getLinearVelocity()
            pass

        if inputState.isSet('mouseTorque'):
            if base.mouseWatcherNode.hasMouse():
                pTorque = base.mouseWatcherNode.getMouse()

                #print ("torqe X = ", torqX)
                #print ("torq Z is ", torqZ)
                #spaceS = self.make_space_station(moveto[0],moveto[1],0)
                #spaceS.setPos(moveto[0],moveto[1],0)

        if inputState.isSet('accelerate'):
            force *= 5

        if inputState.isSet('pickIt'):
            pass
            #y=self.pick_object()

            #self.player.node().setActive(True)

            #torque = render.getRelativeVector(self.player, torque)
            #self.player.node().applyTorque(torque)
            #force = render.getRelativeVector(self.player, force)
            #self.player.node().applyCentralForce(force)
            #self.player.node().applyTorque(torque)






    def setLight(self):
        plight = PointLight('plight')
        plight.setColor(VBase4(.58,.58,.485,1))
        plnp = render.attachNewNode(plight)
        plnp.setPos(0,0,0)
        render.setLight(plnp)
        plight.setShadowCaster(False, 512, 512)

        self.slight = Spotlight('slight')
        self.slight.setColor(VBase4(0.87, 0.7, 0.7, 1))
        lens = PerspectiveLens()
        self.slight.setLens(lens)

        self.slnp = render.attachNewNode(self.slight)
        self.slnp.setPos(20,3,50)
        self.slnp.lookAt(1,1,1)
        render.setLight(self.slnp)

        # Use a 512x512 resolution shadow map
        self.slight.setShadowCaster(True, 512, 512)
        # Enable the shader generator for the receiving nodes
        render.setShaderAuto()

w = World()
run()

You can turn on debug rendering (BulletDebugNode) and check what you are actually colliding with.

thanks for taking the time to reply ennox. appreciate it. i do have debug rendering on, i turn it on when bullet starts (line 499).

it’s a bit long to read through i understand, persumably this must be an issue with bullet. I’ll start the project again and see if i can avoid the issue tthis time. no point having ships that can fly further than a few of their own length before bouncing off something.

funny thing is that it worked fine for a while.

If you can’t see any obstacles in the debug renderer then there are no obstacles. Maybe your ships get deactivated for some reason (linear velocity too slow?).

thanks again man. to me it seems like they are like toys being jerked on a string if they get too far, perhaps all their physics are being calaucltaed as a bundle?

the bounce is huge, like a ball off a floor (which does not exist) but not to worry i will do another prigram.

thanks

Hmm… hard to find out was is going on. The code you pasted above does not run standalone, so I can see myself.

my apologies. i had references to some custom models in there as well as the textures and sphere shapes from the panda solarsystem tutorial models and textures.

have removed planets reference and replaced ships with boxes.

__author__ = 'fam'

# space vessels that journey from one spehere to another
# no bullet to start with
import direct.directbase.DirectStart
from panda3d.core import *
from direct.gui.DirectGui import *
from panda3d.core import Vec3, Vec4
from direct.interval.IntervalGlobal import *
from panda3d.core import Quat
from direct.task import Task
from direct.showbase.DirectObject import DirectObject
from direct.showbase.InputStateGlobal import inputState # get keyboard & mouse inputs

from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletSphereShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletDebugNode
from panda3d.core import BitMask32

import random
import time

class Fleet():
    fleet_list = []

    def __init__(self, bulletworld,size = 5):
        #print ("making fleet")
        self.fleet_size = size
        self.bullet_world = bulletworld
        self.make_fleet()
        self.target_list = []
        self.curr_target = 0

    def random_targets(self,number = 5):
        self.numTargets = number
        for each in range(0,self.numTargets):
            self.target_list.append(random.randrange(-10,10),random.randrange(-10,10),random.randrange(-10,10) )
        print ("target list is", self.target_list)

    def make_fleet(self):
        self.tempz = []
        self.tempC = []
        numba = self.fleet_size
        tpoz = [random.randint(6,6),random.randint(-7,7),random.randint(-12,12)]
        for number in range(0,numba):
            #print ("number is", number)
            ship1 = Craft(self.bullet_world)
            t = ship1.load_ship()
            Fleet.fleet_list.append(t)
            self.tempz.append(t)
            self.tempC.append(ship1)

            self.tempz[number].setPos(tpoz[0]+(2*number), tpoz[1]+random.random()*3,tpoz[2]+random.random()*3)
            #self.tempz[number].setPos(random.randint(-6,6),random.randint(-9,7),random.randint(-8,8))
            #print (tempz)
        return self.tempz

    def get_ships(self):
        return self.tempz

    def fly_fleet(self,dt):
        for shipz in self.tempC:
            shipz.fly(dt)



class Craft():
    ship_list = []
    arrived_count = 0
    targetPos = [(10,0,5),(-10,0,10),(14,5,15)]
    target_count = 0
    target_iter = 0
    mask1 = BitMask32.allOn()
    mask2 = BitMask32.allOff()
    mask3 = BitMask32.bit(2)
    mask4 = BitMask32.bit(5)
    mask5 = BitMask32(0x3)

    craft_types = ["box","box","box"]

    def __init__(self,bulletworld):
        self.bulletWorld = bulletworld
        #print ("making ships")
        self.type = 0 #default is rocket1
        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1
        self.accel_rate = 1
        self.decel_rate = 5
        self.max_speed = 2
        self.turn_rate = random.randint(2,7)
        self.health = 100
        self.speedNow = 0.0
        self.curr_waypoint = 0
        self.waypoints = [(10,0,0),(-12,-4,-5),(14,5,6)]

        #[(random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5)),(random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5)),(2+random.randrange(-10,10),random.randrange(-5,5),random.randrange(-5,5))]
        setupTarget = self.makeTarget()


        self.cruise_speed = self.max_speed/.75
        self.ID = len(Craft.ship_list)
        self.armour=150
        self.flyable = True
        self.startCount = 0
        self.hasArrived = 0
        #print ("ship ID is " , self.ID)


    def setType(self,type):
        self.type = type


    def setPosition(self,x,y,z):
        self.ship_root.setPos(x,y,z)

    def makeTarget(self):
        self.target =  render.attachNewNode('target' + str(len(Craft.ship_list)))
        self.target_mesh = loader.loadModel('box')
        self.target_mesh.reparentTo(self.target)
        #self.target.setPos(Craft.targetPos[Craft.target_count][0],Craft.targetPos[Craft.target_count][1],Craft.targetPos[Craft.target_count][2])
        self.target.setPos(self.waypoints[self.curr_waypoint][0],self.waypoints[self.curr_waypoint][1],self.waypoints[self.curr_waypoint][2])
        print ("traget ", Craft.targetPos[0])
        Craft.target_count += 1
        self.target.setRenderModeWireframe()
        if Craft.target_count >2:
            Craft.target_count = 0
        return self.target

    def moveTarget(self,x,y,z):
        self.target.setPos(x,y,z)





    def load_ship(self):
        print ("drawing ship", len(Craft.ship_list))
        print ("")
        shape =  BulletBoxShape(Vec3(0.5,0.5,0.5))
        self.ship_root = render.attachNewNode(BulletRigidBodyNode('shipNode'+str(len(Craft.ship_list))))
        self.ship = loader.loadModel(Craft.craft_types[0])
        self.ship_root.node().setMass(1)
        self.ship_root.node().addShape(shape)
        Craft.ship_list.append(self.ship_root)
        self.ship.reparentTo(self.ship_root)
        #self.ship_root.setPos(0,0,0)
        self.ship.setHpr(180,0,0)
        self.ship_root.setScale(0.1*self.sizescale)
        self.bulletWorld.attachRigidBody(self.ship_root.node())
        self.ship_root.setCollideMask(Craft.mask2)




        return self.ship_root


    def loadParticleConfig(self, file):
        #Start of the code from steam.ptf
        self.p.cleanup()
        self.p = ParticleEffect()
        self.p.loadConfig(Filename(file))
        #Sets particles to birth relative to the teapot, but to render at toplevel
        self.p.start(self.t)
        self.p.setPos(3.000, 0.000, 2.250)

    def load_cruiser(self):
        print ("drawing cruiser", len(Craft.ship_list))
        print ("")
        shape =  BulletBoxShape(Vec3(0.5,0.5,0.5))
        self.ship_root = render.attachNewNode(BulletRigidBodyNode('cruiserNode'+str(len(Craft.ship_list))))
        self.ship = loader.loadModel(Craft.craft_types[2])
        self.ship_root.node().setMass(10)
        self.ship_root.node().addShape(shape)


        Craft.ship_list.append(self.ship_root)
        self.ship.reparentTo(self.ship_root)
        #self.ship_root.setPos(0,0,0)
        self.ship.setHpr(180,0,0)
        self.ship_root.setScale(2*self.sizescale)
        self.bulletWorld.attachRigidBody(self.ship_root.node())
        self.ship_root.setHpr(random.randint(0,220),0,0)
        return self.ship_root



    def fly(self,dt):
        #check angle
        self.dt = dt
        angleBase = self.ship_root.getHpr()
        angleTarget = self.pointAt(self.ship_root,self.target)
        angleDiff = angleBase - angleTarget
        total_angle = angleDiff[0]+angleDiff[1]
        dist = self.get_distance(self.ship_root,self.target)

        tForce = 3.0

        if self.startCount == 0:
            self.startCount = time.clock()
            self.pos1 = self.ship_root.getPos()
        if time.clock() - self.startCount >=  1:
            self.pos2 = self.ship_root.getPos()
            timePast = time.clock() - self.startCount
            calcDist = self.pos2 - self.pos1
            distL = calcDist.length()
            self.speedNow = distL/timePast
            #print ("at dist", dist, "for ship ID" , self.ID, "current speed is" , self.speedNow , "over", timePast)
            self.startCount = 0

        if dist >=7:
                tForce = 10.0
        elif dist <6 and dist > 4:
            tForce = 5.0
        elif dist <= 2 and self.speedNow > 0:
            tForce = 1
        elif dist<=1:
            self.hasArrived = 1
            Craft.arrived_count += 1
            self.curr_waypoint += 1
            self.ship.setColor(1,0,0)
            #self.target.setPos(Craft.targetPos[Craft.target_iter][0],Craft.targetPos[Craft.target_iter][1],Craft.targetPos[Craft.target_iter][2])
            if self.curr_waypoint >len(self.waypoints):
                self.curr_waypoint = 0


        tForce = self.speed_limiter(tForce)

        if self.hasArrived == 1:
            self.change_target()

        if abs(total_angle) > 5:
            qAngle = self.quat_by_quat(self.ship_root,self.target)
            self.turn_towards(self.ship_root,qAngle,self.turn_rate)
        elif abs(total_angle) <= 30: # pointing in general direction so start moving
            self.move_fowards(self.ship_root,self.target,tForce)

        self.obst = self.check_obstacles(10)
       # print ("obstacle is selfobst ", self.obst)

        self.safe_dist = self.max_speed

    def speed_limiter(self,tforce):
        if self.speedNow >= self.max_speed:
            self.ship_root.node().setLinearVelocity(self.max_speed)
            return 0
        else:
            return tforce

    def change_target(self):
        self.target.setPos(Craft.targetPos[Craft.target_iter][0],Craft.targetPos[Craft.target_iter][1],Craft.targetPos[Craft.target_iter][2])
        self.hasArrived = 0



    def take_evasive(self,enemypos):
        print ("enemy ahead at", enemypos)


    def check_safe_distance(self,base,target):
        #in a nutshell get the pos where the ship will be in vec * time
        # time to deceltime = dist/decel_speed
        time_decel = target.getPos()/self.decel_rate


    def intercept_pos(self,base,target,speed):
        temp_pos = target.getPos()
        temp_dir = target.getHpr()
        temp_speed = speed
        dist = self.get_distance(base,target)
        bullets_speed = 1.0
        temp_time = dist/bullets_speed
        temp_vec = render.getRelativeVector(node,Vec3(0,1,0))
        projected_pos = temp_vec * temp_time
        return projected_pos



    def check_obstacles(self,dist = 50):
        pFrom = self.ship_root.getPos()
        pTo = pFrom + Vec3(0,1,0)*dist

        result = self.bulletWorld.rayTestClosest(pFrom, pTo)

        if result.hasHit() == True:
            obstacle = result.getNode()
            obstaclePos = result.getHitPos()
            print ("for ship ID", self.ID," obstacle is ", obstacle, "at ",obstaclePos)
            tPos = (self.ship_root.getPos() - obstaclePos).length()

            return obstacle

    def get_distance(self,base,target):
        target_vec = base.getPos() - target.getPos()
        distance = target_vec.length()
        return distance

    def get_dist_vec3(self,base,target):
        target_vec = base - target
        distance = target_vec.length
        return distance

    def quat_by_quat(self,base,obj2):
        #takes 2 objects
        # gets pos and quat of obj1
        # get required quat to point at obj2
        #return difference
        obj1 = base
        quat1 = obj1.getQuat()
        pos1 = obj1.getPos()
        obj1Dir = quat1.getForward()
        obj1Dir.normalize()
        #v = obj1Dir
        vec2obj2 = obj2.getPos() - pos1
        vec2obj2.normalize()
        angleTowards = self.pointAt(base,obj2)
        #print ("quat1 and asngeltwards" , quat1, angleTowards)
        angleinQuat = Quat()
        angleinQuat.setHpr(Vec3(angleTowards))
        #print ("angle in quat is ", angleinQuat)
        #qSubq =  quat1 - angleinQuat
        #print ("angle to turn is ",qSubq)
        #obj1.setQuat(angleinQuat)
        return angleinQuat

    def pointAt(self, base,target):
        self.tempNode = render.attachNewNode('tempNode')
        self.tempNode.setPos(base.getPos())
        self.tempNode.setHpr(base.getHpr())
        self.tempNode.lookAt(target)
        tempVec = self.tempNode.getHpr()
        #print ("tempVec is", tempVec)
        return tempVec

    def turn_towards(self,base,angle,turnspeed):
        myInterval1 = base.hprInterval(turnspeed, angle)
        seq = Parallel(myInterval1)
        seq.start()

    def calc_speed(self):
        """returns a point in time. do it twice to work out speed"""
        tPos = self.ship_root.getPos()
        timeSlice = time.clock()
        return tPos, timeSlice


    def move_fowards(self,base,target,forceT = 5.0):
        force =  Vec3(0, 0, 0) # Forward
        torque = Vec3(0, 0 ,0)
        target_vec = base.getPos() - target.getPos()
        #distance = target_vec.length()
        #curVec = render.getRelativeVector(base,Vec3(0,1,0))
        force.setY(forceT)
        base.node().setActive(True)
        torque = render.getRelativeVector(base,torque)
        base.node().applyTorque(torque)
        force = render.getRelativeVector(base, force)
        #print ("force is", force , " for ID" , base)
        base.node().applyCentralForce(force)


    def decel(self):
        curSpeed = self.speedNow
        decelRate = -2


class Solar_body():
    body_list = []
    def __init__(self):
        print ("making planets")
        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1
        self.planetsScales = [1,2]
        newSys = self.gen_system()

    def gen_system(self,planetNum= 4):
        self.num_planets = planetNum
        #newSun = self.make_sun()
        for each in range(0,self.num_planets):
            chanceMoon = random.random()
            hasMoon = False
            if chanceMoon >0.4:
                hasMoon = True
            tempX=random.randint(10*each,20*each)
            tempSize = random.randrange(self.planetsScales[0],self.planetsScales[1])
            newPlanet = self.loadPlanets(tempX,tempSize,hasMoon)
            Solar_body.body_list.append(newPlanet)


    def make_sun(self,size=3):
        self.sun = loader.loadModel('planet_sphere')
        self.sun_tex = loader.loadTexture("models/sun_1k_tex.jpg")
        self.sun.setTexture(self.sun_tex, 1)
        self.sun.reparentTo(render)
        self.sun.setScale(size * self.sizescale)


    def loadPlanets(self,posi,scale,hasMoon):
        planet_pos = posi
        planet_scale = scale
        self.orbit_root_planet = render.attachNewNode('orbit_planet' + str(len(Solar_body.body_list)))
        self.planet1 = loader.loadModel("models/planet_sphere")
        self.p1_tex = loader.loadTexture("models/mercury_1k_tex.jpg")
        self.planet1.setTexture(self.p1_tex, 1)
        self.planet1.reparentTo(self.orbit_root_planet)
        self.planet1.setPos( planet_pos * self.orbitscale, 0, 0)
        self.planet1.setScale(planet_scale * self.sizescale)

        if hasMoon == True:
            print ("has moon")
            self.orbit_root_moon = self.orbit_root_planet.attachNewNode('orbit_planet' + str(len(Solar_body.body_list)))
            self.moon = loader.loadModel("models/asteroid")
            self.moon_tex = loader.loadTexture("models/moon_1k_tex.jpg")
            self.moon.setTexture(self.p1_tex, 1)
            self.moon.reparentTo(self.orbit_root_moon)
            self.moon.setPos( random.randrange(-3,3), -3, -5)
            self.moon.setScale((planet_scale/2) * self.sizescale)


        return self.orbit_root_planet





class World(DirectObject):

    AI_list = []

    def __init__(self):
        base.setBackgroundColor(0.31,0.351,0.453)
        base.disableMouse()
        camera.setPos(0,60,5)
        camera.lookAt(5,5,0)
        self.ship_list = []

        base.enableParticles()
        base.wireframeOn()

        self.timeScale = 1
        self.sizescale = 1
        self.orbitscale = 1

        self.accept('escape',self.doExit)
        inputState.watchWithModifiers('forward', 'w')
        inputState.watchWithModifiers('left', 'a')
        inputState.watchWithModifiers('back', 's')
        inputState.watchWithModifiers('right', 'd')
        inputState.watchWithModifiers('up', 'q')
        inputState.watchWithModifiers('down', 'z')
        inputState.watchWithModifiers('mouseTorque', 'mouse3')
        inputState.watchWithModifiers('slow','space')
        inputState.watchWithModifiers('accelerate','lshift')
        inputState.watchWithModifiers('pickIt','mouse1')


        taskMgr.add(self.gameLoop, "gameLoop")
        self.all_fleets = []
        self.startBullet()

        self.setLight()

        #planets = Solar_body()

        fl1 = Fleet(self.world,5)
        cruiser1 = Craft(self.world)

        #self.fleet1 = Craft()
        #self.fleet1.create_fleet(4)
        #print ("fl1 is", fl1)

        #print ("all fleets are", self.all_fleets)
        World.AI_list.append(fl1)





    def turn_debug_on(self):
        debugNode = BulletDebugNode('Debug')
        debugNode.showWireframe(True)
        debugNode.showConstraints(True)
        debugNode.showBoundingBoxes(True)
        debugNode.showNormals(True)
        debugNP = render.attachNewNode(debugNode)
        #self.world.setDebugNode(debugNP.node())
        debugNP.show()
        self.world.setDebugNode(debugNP.node())

    def startBullet(self):
        print ("starting bullet")
        self.world = BulletWorld()
        self.world.setGravity(Vec3(0,0,0))
        self.turn_debug_on()



    def doExit():
        sys.Exit(1)

    def gameLoop(self,task):
        dt = globalClock.getDt()

        self.processInput(dt)
        #frameTime = globalClock.getFrameTime()
        self.world.doPhysics(dt, 100, 1./500.)
        self.think_AI(dt)
        return Task.cont

    def think_AI(self,dt):
        num_ai = len(World.AI_list)
        for each in range(0,num_ai):

            temp = World.AI_list[each].get_ships()
            print ("temp ships is ",temp)
            World.AI_list[each].fly_fleet(dt)






    def processInput(self,dt):
        moveto=[]
        force =  Vec3(0, 0, 0) # Forward
        torque = Vec3(0, 0 , 0)

        if inputState.isSet('forward'):
            force.setY(1.0)

        if inputState.isSet('back'):
            force.setY(-1.0)

        if inputState.isSet('right'):
            force.setX(-1.0)

        if inputState.isSet('left'):
            force.setX(1.0)

        if inputState.isSet('up'):
            torque.setX(0.5)

        if inputState.isSet('down'):
            torque.setX(-0.5)

        if inputState.isSet('slow'):
            #print ("camera pos is", self.camX, self.camY , self.camZ)
            #angle_change = self.player.node().getAngularVelocity()
            #current_speed = self.player.node().getLinearVelocity()
            pass

        if inputState.isSet('mouseTorque'):
            if base.mouseWatcherNode.hasMouse():
                pTorque = base.mouseWatcherNode.getMouse()

                #print ("torqe X = ", torqX)
                #print ("torq Z is ", torqZ)
                #spaceS = self.make_space_station(moveto[0],moveto[1],0)
                #spaceS.setPos(moveto[0],moveto[1],0)

        if inputState.isSet('accelerate'):
            force *= 5

        if inputState.isSet('pickIt'):
            pass
            #y=self.pick_object()

            #self.player.node().setActive(True)

            #torque = render.getRelativeVector(self.player, torque)
            #self.player.node().applyTorque(torque)
            #force = render.getRelativeVector(self.player, force)
            #self.player.node().applyCentralForce(force)
            #self.player.node().applyTorque(torque)






    def setLight(self):
        plight = PointLight('plight')
        plight.setColor(VBase4(.58,.58,.485,1))
        plnp = render.attachNewNode(plight)
        plnp.setPos(0,0,0)
        render.setLight(plnp)
        plight.setShadowCaster(False, 512, 512)

        self.slight = Spotlight('slight')
        self.slight.setColor(VBase4(0.87, 0.7, 0.7, 1))
        lens = PerspectiveLens()
        self.slight.setLens(lens)

        self.slnp = render.attachNewNode(self.slight)
        self.slnp.setPos(20,3,50)
        self.slnp.lookAt(1,1,1)
        render.setLight(self.slnp)

        # Use a 512x512 resolution shadow map
        self.slight.setShadowCaster(True, 512, 512)
        # Enable the shader generator for the receiving nodes
        render.setShaderAuto()

w = World()
run()