Exemplo n.º 1
0
    def draw_box(self, box):
        line_collection = LineNodePath(parent=render, thickness=1.0, colorVec=Vec4(1, 0, 0, 1))
        pos = box.get_position()
        lengths = box.get_lengths()

        x = pos[0]
        y = pos[1]
        z = pos[2]

        half_width = lengths[0] / 2
        half_length = lengths[1] / 2
        half_height = lengths[2] / 2

        lines = [
            # Bottom Face
            ((x - half_width, y - half_length, z - half_height), (x + half_width, y - half_length, z - half_height)),
            ((x + half_width, y - half_length, z - half_height), (x + half_width, y + half_length, z - half_height)),
            ((x + half_width, y + half_length, z - half_height), (x - half_width, y + half_length, z - half_height)),
            ((x - half_width, y + half_length, z - half_height), (x - half_width, y - half_length, z - half_height)),
            # Top Face
            ((x - half_width, y - half_length, z + half_height), (x + half_width, y - half_length, z + half_height)),
            ((x + half_width, y - half_length, z + half_height), (x + half_width, y + half_length, z + half_height)),
            ((x + half_width, y + half_length, z + half_height), (x - half_width, y + half_length, z + half_height)),
            ((x - half_width, y + half_length, z + half_height), (x - half_width, y - half_length, z + half_height)),
            # Vertical Lines
            ((x - half_width, y - half_length, z - half_height), (x - half_width, y - half_length, z + half_height)),
            ((x + half_width, y - half_length, z - half_height), (x + half_width, y - half_length, z + half_height)),
            ((x + half_width, y + half_length, z - half_height), (x + half_width, y + half_length, z + half_height)),
            ((x - half_width, y + half_length, z - half_height), (x - half_width, y + half_length, z + half_height)),
        ]

        line_collection.drawLines(lines)
        line_collection.create()
Exemplo n.º 2
0
    def createPitchLineOld(self,points=[0.5,0.25,-0.25,-0.5],
                            tick=0.00,colour=None):
        """ create a line to hint at the pitch of the aircraft on the hud """
        if colour is None:
            colour = self.colour

        l = LineNodePath(aspect2d,'pitchline',4,Vec4(colour[0],colour[1],
                                                       colour[2],colour[3]))

        plist = []
        for p in points:
            plist.append((p,0.0,0.0))
        plist.insert(0,(points[0],0.0,tick))
        plist.append((points[3],0.0,tick))

        linelist = []
        linelist = [[plist[p],plist[p+1]] for p in range(len(plist)-1)]
        linelist.pop(2)
        l.drawLines(linelist)
        l.create()

        # These lines are drawn from scratch rather than using a graphic file

        format = GeomVertexFormat.getV3()
        vdata = GeomVertexData("vertices",format,Geom.UHStatic)

        # create vertices to add to use in creating lines
        vertexWriter=GeomVertexWriter(vdata,"vertex")
        # here we define enough positions to create two separated lines
        for p in points:
            vertexWriter.addData3f(p,0.0,0.0)
        # and another two positions for the 'ticks' at the line ends
        vertexWriter.addData3f(points[0],0.0,tick)
        vertexWriter.addData3f(points[3],0.0,tick)

        # create the primitives
        line = GeomLines(Geom.UHStatic)
        line.addVertices(4,0) # the tick part
        line.addVertices(0,1) # part of the horizontal line
        line.closePrimitive()
        line2 = GeomLines(Geom.UHStatic)
        line2.addVertices(2,3) # other part of the horizontal line
        line2.addVertices(3,5) # second tick
        line2.closePrimitive()

        # add the lines to a geom object
        lineGeom = Geom(vdata)
        lineGeom.addPrimitive(line)
        lineGeom.addPrimitive(line2)

        # create the node..
        lineGN=GeomNode("splitline")
        lineGN.addGeom(lineGeom)

        # and parent the node to aspect2d
        lineNP = aspect2d.attachNewNode(lineGN)
        return lineNP
Exemplo n.º 3
0
    def draw_axis(self, root, origin):
        PX = origin[0]
        PY = origin[1]
        PZ = origin[2]

        lengthX = PX + 1.5
        lengthY = PY + 1.5
        lengthZ = PZ + 1.5
        q1 = PX + .5
        q2 = -q1

        arrowLENGHT = PX + .2

        arrowXx1 = PY + .08
        arrowXx2 = PY - .08
        arrowXz2 = PX + 1.3

        arrowYx1 = PX + .08
        arrowYx2 = PX - .08
        arrowYz2 = PY + 1.3

        arrowZx1 = PX + .08
        arrowZx2 = PX - .08
        arrowZz2 = PZ + 1.3

        PIVarX = LineNodePath(root, 'pivotX', 3, Vec4(1, 0, 0, 1))
        PIVarY = LineNodePath(root, 'pivotY', 3, Vec4(0, 1, 1, 1))
        PIVarZ = LineNodePath(root, 'pivotZ', 3, Vec4(1, 1, 0, 1))

        PIVOThandler = LineNodePath(root, 'handler', 2, Vec4(1, 0, 1, 1))

        PIVarX.reparentTo(PIVOThandler)
        PIVarY.reparentTo(PIVOThandler)
        PIVarZ.reparentTo(PIVOThandler)

        arrowX1 = (lengthX, PY, PZ)
        arrowX2 = (arrowXz2, arrowXx1, PZ)
        arrowX3 = (arrowXz2, arrowXx2, PZ)

        arrowY1 = (PX, lengthY, PZ)
        arrowY2 = (arrowYx1, arrowYz2, PZ)
        arrowY3 = (arrowYx2, arrowYz2, PZ)

        arrowZ1 = (PX, PY, lengthZ)
        arrowZ2 = (arrowZx1, PY, arrowZz2)
        arrowZ3 = (arrowZx2, PY, arrowZz2)

        PIVarX.drawLines([[(PX, PY, PZ), (lengthX, PY, PZ)], [arrowX1, arrowX2], [arrowX1, arrowX3]])
        PIVarY.drawLines([[(PX, PY, PZ), (PX, lengthY, PZ)], [arrowY1, arrowY2], [arrowY1, arrowY3]])
        PIVarZ.drawLines([[(PX, PY, PZ), (PX, PY, lengthZ)], [arrowZ1, arrowZ2], [arrowZ1, arrowZ3]])

        PIVOThandler.drawLines([[(PX, PY, PZ), (PX + 0.5, PY, PZ)], [(PX + .5, PY, PZ), (PX, PY + .5, PZ)],
                                [(PX, PY + .5, PZ), (PX, PY, PZ)]])

        PIVarX.create()
        PIVarY.create()
        PIVarZ.create()
        PIVOThandler.create()

        return PIVOThandler
Exemplo n.º 4
0
    def grid(self):
        raws1unit = 20
        rawsfithunit = 10
        d = 0
        X1 = 10
        X2 = -10
        Y1 = 10
        Y2 = -10

        linesX = LineNodePath(render, 'quad', 2, Vec4(.3, .3, .3, .3))
        linesXX = LineNodePath(render, 'quad', 1, Vec4(.3, .3, .3, .3))
        axis = LineNodePath(render, 'axis', 4, Vec4(.2, .2, .2, .2))
        quad = LineNodePath(render, 'quad', 4, Vec4(.2, .2, .2, .2))

        x1 = (0, Y2, 0)
        x2 = (0, Y1, 0)

        x3 = (X2, 0, 0)
        x4 = (X1, 0, 0)
        axis.drawLines([[x1, x2], [x3, x4]])
        axis.create()

        q1 = (X1, Y1, 0)
        q2 = (X1, Y2, 0)

        q3 = (q2)
        q4 = (X2, Y2, 0)

        q5 = (q4)
        q6 = (X2, Y1, 0)

        q7 = (q6)
        q8 = (X1, Y1, 0)

        quad.drawLines([[q1, q2], [q3, q4], [q5, q6], [q7, q8]])
        quad.create()

        for l in range(raws1unit - 1):
            d += 1
            l1 = (X2 + d, Y1, 0)
            l2 = (X2 + d, Y2, 0)

            l3 = (X2, Y1 - d, 0)
            l4 = (X1, Y1 - d, 0)

            linesX.drawLines([[l1, l2], [l3, l4]])
            linesX.create()

        for l in range(rawsfithunit):
            d -= .2
            lx1 = (X2 + 1 + d, Y1, 0)
            lx2 = (X2 + 1 + d, Y2, 0)

            lx3 = (X2, Y1 - 1 - d, 0)
            lx4 = (X1, Y1 - 1 - d, 0)

            linesXX.drawLines([[lx1, lx2], [lx3, lx4]])
            linesXX.create()
Exemplo n.º 5
0
    def draw_box(self, box):
        line_collection = LineNodePath(parent=render,
                                       thickness=1.0,
                                       colorVec=Vec4(1, 0, 0, 1))
        pos = box.get_position()
        lengths = box.get_lengths()

        x = pos[0]
        y = pos[1]
        z = pos[2]

        half_width = lengths[0] / 2
        half_length = lengths[1] / 2
        half_height = lengths[2] / 2

        lines = [
            # Bottom Face
            ((x - half_width, y - half_length, z - half_height),
             (x + half_width, y - half_length, z - half_height)),
            ((x + half_width, y - half_length, z - half_height),
             (x + half_width, y + half_length, z - half_height)),
            ((x + half_width, y + half_length, z - half_height),
             (x - half_width, y + half_length, z - half_height)),
            ((x - half_width, y + half_length, z - half_height),
             (x - half_width, y - half_length, z - half_height)),
            # Top Face
            ((x - half_width, y - half_length, z + half_height),
             (x + half_width, y - half_length, z + half_height)),
            ((x + half_width, y - half_length, z + half_height),
             (x + half_width, y + half_length, z + half_height)),
            ((x + half_width, y + half_length, z + half_height),
             (x - half_width, y + half_length, z + half_height)),
            ((x - half_width, y + half_length, z + half_height),
             (x - half_width, y - half_length, z + half_height)),
            # Vertical Lines
            ((x - half_width, y - half_length, z - half_height),
             (x - half_width, y - half_length, z + half_height)),
            ((x + half_width, y - half_length, z - half_height),
             (x + half_width, y - half_length, z + half_height)),
            ((x + half_width, y + half_length, z - half_height),
             (x + half_width, y + half_length, z + half_height)),
            ((x - half_width, y + half_length, z - half_height),
             (x - half_width, y + half_length, z + half_height)),
        ]

        line_collection.drawLines(lines)
        line_collection.create()
Exemplo n.º 6
0
    def createPitchLine(self, points=[0.5, 0.25, -0.25, -0.5], tick=0.00, colour=None):
        """ create a line to hint at the pitch of the aircraft on the hud """
        if colour is None:
            colour = self.colour

        pline = LineNodePath(aspect2d, "pitchline", 1, Vec4(colour[0], colour[1], colour[2], colour[3]))

        plist = []
        for p in points:
            plist.append((p, 0.0, 0.0))
        plist.insert(0, (points[0], 0.0, tick))
        plist.append((points[3], 0.0, tick))

        linelist = []
        linelist = [[plist[p], plist[p + 1]] for p in range(len(plist) - 1)]
        linelist.pop(2)

        pline.drawLines(linelist)
        pline.create()
        return pline
Exemplo n.º 7
0
    def createCentreMark(self, colour=None):
        """ create a line to hint at the pitch of the aircraft on the hud """
        if colour is None:
            colour = self.colour

        cmline = LineNodePath(aspect2d, "centremark", 1, Vec4(colour[0], colour[1], colour[2], colour[3]))

        plist = []
        plist.append((0.15, 0.0, 0.0))
        plist.append((0.10, 0.0, 0.0))
        plist.append((0.05, 0.0, -0.025))
        plist.append((0.00, 0.0, 0.025))
        plist.append((-0.05, 0.0, -0.025))
        plist.append((-0.10, 0.0, 0.0))
        plist.append((-0.15, 0.0, 0.0))

        linelist = []
        linelist = [[plist[p], plist[p + 1]] for p in range(len(plist) - 1)]
        cmline.drawLines(linelist)
        cmline.create()
        return cmline
Exemplo n.º 8
0
 def _build_cursor(self, shape="sphere"):
     if shape == "sphere":
         cursor = self._load("sphere.bam")
     elif shape == "cross":
         cursor = LineNodePath()
         lines = [[Point3(-0.5, 0, 0), Point3(0.5, 0, 0)],
                  [Point3(0, 0, -0.5), Point3(0, 0, 0.5)]]
         cursor.drawLines(lines)
         cursor.setThickness(1)
         cursor.create()
         # cursor = NodePath("cross")
         # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
         #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
         #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
         # for k, v in S.iteritems():
         #     m = self._load(k)
         #     m.setName(k)
         #     m.setPos(*v[0])
         #     m.setScale(*v[1])
         #     m.reparentTo(cursor)
     #BP()
     return cursor
Exemplo n.º 9
0
    def drawGrid(self):
        raws1unit = 20
        rawsHALFunit = 100

        X1 = 10
        X2 = -10
        Y1 = 10
        Y2 = -10

        linesX = LineNodePath(render, "lines1", 2, Vec4(0.3, 0.3, 0.3, 0))
        linesXXX = LineNodePath(render, "lines1", 0.4, Vec4(0.35, 0.35, 0.35, 0))
        axis = LineNodePath(render, "axis", 4, Vec4(0.2, 0.2, 0.2, 0))
        quad = LineNodePath(render, "quad", 4, Vec4(0.2, 0.2, 0.2, 0))

        x1 = (0, Y2, 0)
        x2 = (0, Y1, 0)

        x3 = (X2, 0, 0)
        x4 = (X1, 0, 0)

        axis.drawLines([[x1, x2], [x3, x4]])
        axis.create()

        q1 = (X1, Y1, 0)
        q2 = (X1, Y2, 0)

        q3 = q2
        q4 = (X2, Y2, 0)

        q5 = q4
        q6 = (X2, Y1, 0)

        q7 = q6
        q8 = (X1, Y1, 0)

        quad.drawLines([[q1, q2], [q3, q4], [q5, q6], [q7, q8]])
        quad.create()

        gfOutput = [1]

        d = 0
        for l in range(raws1unit - 1):
            lO = len(gfOutput)
            lO1 = lO - 1
            global field
            field1 = gfOutput[lO1]
            field = float(field1)
            print field
            d += field
            l1 = (X2 + d, Y1, 0)
            l2 = (X2 + d, Y2, 0)

            l3 = (X2, Y1 - d, 0)
            l4 = (X1, Y1 - d, 0)

            linesX.drawLines([[l1, l2], [l3, l4]])
        linesX.create()
Exemplo n.º 10
0
    def draw_grid(self):
        raws1unit = 20
        rawsHALFunit = 100

        X1 = 10
        X2 = -10
        Y1 = 10
        Y2 = -10

        linesX = LineNodePath(self.render, 'lines1', 2, Vec4(.3, .3, .3, 0))
        linesXXX = LineNodePath(self.render, 'lines1', .4, Vec4(.35, .35, .35, 0))
        axis = LineNodePath(self.render, 'axis', 4, Vec4(.2, .2, .2, 0))
        quad = LineNodePath(self.render, 'quad', 4, Vec4(.2, .2, .2, 0))

        x1 = (0, Y2, 0)
        x2 = (0, Y1, 0)

        x3 = (X2, 0, 0)
        x4 = (X1, 0, 0)

        axis.drawLines([[x1, x2], [x3, x4]])
        axis.create()

        q1 = (X1, Y1, 0)
        q2 = (X1, Y2, 0)

        q3 = (q2)
        q4 = (X2, Y2, 0)

        q5 = (q4)
        q6 = (X2, Y1, 0)

        q7 = (q6)
        q8 = (X1, Y1, 0)

        quad.drawLines([[q1, q2], [q3, q4], [q5, q6], [q7, q8]])
        quad.create()

        gfOutput = [1]

        d = 0
        for l in range(raws1unit - 1):
            lO = len(gfOutput)
            lO1 = lO - 1
            global field
            field1 = gfOutput[lO1]
            field = float(field1)
            print(field)
            d += field
            l1 = (X2 + d, Y1, 0)
            l2 = (X2 + d, Y2, 0)

            l3 = (X2, Y1 - d, 0)
            l4 = (X1, Y1 - d, 0)

            linesX.drawLines([[l1, l2], [l3, l4]])
        linesX.create()
Exemplo n.º 11
0
 def _build_cursor(self, shape="sphere"):
     if shape == "sphere":
         cursor = self._load("sphere.bam")
     elif shape == "cross":
         cursor = LineNodePath()
         lines = [[Point3(-0.5, 0, 0),
                   Point3(0.5, 0, 0)],
                  [Point3(0, 0, -0.5),
                   Point3(0, 0, 0.5)]]
         cursor.drawLines(lines)
         cursor.setThickness(1)
         cursor.create()
         # cursor = NodePath("cross")
         # S = {"cylinderX.bam": ((0., 0., 0.), (1., 0.1, 0.1)),
         #      "cylinderY.bam": ((0., 0., 0.), (0.1, 1., 0.1)),
         #      "cylinderZ.bam": ((0., 0., 0.), (0.1, 0.1, 1.))}
         # for k, v in S.iteritems():
         #     m = self._load(k)
         #     m.setName(k)
         #     m.setPos(*v[0])
         #     m.setScale(*v[1])
         #     m.reparentTo(cursor)
     #BP()
     return cursor
Exemplo n.º 12
0
class Rocket (Body):

    family = "rocket"
    species = "generic"
    longdes = _("generic")
    shortdes = _("G/RCK")
    cpitdes = {}
    against = []
    mass = 150.0
    diameter = 0.140
    maxg = 20.0
    vmaxalt = 12000.0
    minspeed = 470.0
    minspeed1 = 470.0
    maxspeed = 650.0
    maxspeed1 = 850.0
    maxthracc = 300.0
    maxthracc1 = 400.0
    maxvdracc = 2.0
    maxvdracc1 = 1.0
    maxflighttime = 20.0
    minlaunchdist = 1000.0
    hitforce = 5.0
    expforce = 50.0
    seeker = "ir"
    flightmodes = ["intercept"]
    maxoffbore = radians(10.0)
    locktime = 2.0
    decoyresist = 0.7
    rcs = 0.00010
    hitboxdata = [(Point3(0.0, 0.0, 0.0), 1.0)]
    modelpath = None
    texture = None
    normalmap = None
    glowmap = "models/weapons/_glowmap.png"
    glossmap = "models/weapons/_glossmap.png"
    modelscale = 1.0
    modeloffset = Point3()
    modelrot = Vec3()
    engsoundname = None
    engvol = 0.3
    launchvol = 0.5
    expvol = 0.8

    _seekers_local = set(("ir", "tv", "intv", "arh"))
    _seekers_remote = set(("sarh", "salh", "radio", "wire"))
    _seekers_none = set((None,))
    _seekers_all = _seekers_local.union(_seekers_remote).union(_seekers_none)

    _flightmodes_all = set(("transfer", "intercept", "inertial"))

    def __init__ (self, world, name, side,
                  pos=None, hpr=None, speed=None, dropvel=None,
                  target=None, offset=None,
                  extvis=True):

        if pos is None:
            pos = Vec3()
        if hpr is None:
            hpr = Vec3()
        if speed is None:
            d1, maxspeed = self.limspeeds(pos[2])
            speed = maxspeed

        if False: # no point checking in every instance...
            if self.seeker not in Rocket._seekers_all:
                raise StandardError(
                    "Unknown seeker type '%s' for '%s'." %
                    (self.seeker, self.species))
            unknown = set(self.flightmodes).difference(Rocket._flightmodes_all)
            if unknown:
                raise StandardError(
                    "Unknown flight mode '%s' for '%s'." %
                    (unknown.pop(), self.species))

        if dropvel is not None:
            vel = hprtovec(hpr) * speed + dropvel
        else:
            vel = speed

        Body.__init__(self,
            world=world,
            family=self.family, species=self.species,
            hitforce=self.hitforce,
            modeldata=AutoProps(
                path=self.modelpath,
                texture=self.texture, normalmap=self.normalmap,
                glowmap=self.glowmap, glossmap=self.glossmap,
                scale=self.modelscale,
                offset=self.modeloffset, rot=self.modelrot),
            amblit=True, dirlit=True, pntlit=1, fogblend=True,
            ltrefl=(self.glossmap is not None),
            name=name, side=side,
            pos=pos, hpr=hpr, vel=vel)

        self.ming = -self.maxg

        if self.engsoundname:
            self.engine_sound = Sound3D(
                path=("audio/sounds/%s.ogg" % self.engsoundname),
                parent=self, limnum="hum", volume=self.engvol, loop=True)
            self.engine_sound.play()
        if 1:
            lnchsnd = Sound3D(
                "audio/sounds/%s.ogg" % "missile-launch",
                parent=self, volume=self.launchvol, fadetime=0.1)
            lnchsnd.play()

        self.target = target
        self.offset = offset
        self.must_hit_expforce = 0.0
        self.proximity_fuze_active = True
        self._last_target = target

        self.path = None
        self.pspeed = None

        self._targeted_offset = (self.offset or
                                 (self.target and self.target.center) or
                                 Point3())
        self._effective_offset = self._targeted_offset

        self._actdist = min(0.5 * self.minlaunchdist, 1000.0)
        self._active = False
        self._armdist = self.minlaunchdist
        self._armed = False

        self._state_info_text = None
        self._wait_time_state_info = 0.0

        self._prev_path = None
        self._path_pos = 0.0

        self.exhaust_trails = []

        if side == "bstar":
            trcol = rgba(127, 0, 0, 1)
        elif side == "nato":
            trcol = rgba(0, 0, 127, 1)
        else:
            trcol = rgba(0, 127, 0, 1)
        self._trace = None
        if world.show_traces:
            self._trace = LineNodePath(parent=self.world.node,
                                       thickness=1.0, colorVec=trcol)
            self._trace_segs = []
            self._trace_lens = []
            self._trace_len = 0.0
            self._trace_maxlen = 5000.0
            self._trace_prevpos = pos
            self._trace_frameskip = 5
            self._trace_accuframe = 0

        self._flightdist = 0.0
        self._flighttime = 0.0

        self._updperiod_decoy = 0.053
        self._updwait_decoy = 0.0
        self._dtime_decoy_process = 0.0
        self._eliminated_decoys = set()
        self._tracked_decoy = None

        self._no_target_selfdest_time = 1.0
        self._no_target_time = 0.0

        test_expforce = max(self.expforce * 0.9, self.expforce - 1.0)
        self._prox_dist = explosion_reach(test_expforce)
        self.proximity_fuzed = False # debug
        self.target_hit = False # debug

        if extvis:
            bx, by, bz = self.bbox
            bbox = Vec3(bx, by * 500.0, bz)
            EnhancedVisual(parent=self, bbox=bbox)

        self._fudge_player_manoeuver = True
        if self._fudge_player_manoeuver:
            self._plmanv_done_1 = False
            self._plmanv_done_2 = False

        base.taskMgr.add(self._loop, "rocket-loop-%s" % self.name)


    def _loop (self, task):

        if not self.alive:
            return task.done
        if self.target and not self.target.alive:
            self.target = None

        # Keep track of last known and alive target.
        # Needed e.g. to apply force explosion damage.
        if self.target and self.target.alive:
            self._last_target = self.target
        elif self._last_target and not self._last_target.alive:
            self._last_target = None

        dt = self.world.dt
        pos = self.pos()
        vel = self.vel()

        if self.world.below_surface(pos):
            posg = self.world.intersect_surface(pos - vel * dt, pos)
            self.explode(pos=posg)
            return task.done

        if self._flighttime >= self.maxflighttime:
            self.explode()
            return task.done

        if not self._active and (self._flightdist >= self._actdist or
                                 self.must_hit_expforce > 0.0):
            self._active = True
            # Initial autopilot state.
            self._ap_currctl = None
            self._ap_pause = 0.0

        if not self._armed and self._flightdist >= self._armdist:
            self.set_hitboxes(hitboxdata=self.hitboxdata)
            self._armed = True

        # Update offset for decoys.
        if self.target:
            self._updwait_decoy -= dt
            self._dtime_decoy_process += dt
            if self._updwait_decoy <= 0.0:
                self._updwait_decoy += self._updperiod_decoy
                ret = self._process_decoys(self.target, self._targeted_offset,
                                           self._dtime_decoy_process)
                self._effective_offset = ret
                self._dtime_decoy_process = 0.0

        # Activate proximity fuze if near miss.
        if (self._armed and self.proximity_fuze_active and self.target and
            not self.world.in_collision(self)):
            tdir = self.target.pos(refbody=self, offset=self._targeted_offset)
            # ...not self._effective_offset.
            tdist = tdir.length()
            #print_each(1350, 1.0, "--rck-prox-check tdist=%.0f[m]" % tdist)
            if tdist < self._prox_dist or self.must_hit_expforce > 0.0:
                tdir.normalize()
                offbore = acos(clamp(tdir[1], -1.0, 1.0))
                if offbore > self.maxoffbore:
                    #print "--rck-proxfuze", tdist, degrees(offbore)
                    self.explode()
                    self.proximity_fuzed = True # debug
                    return task.done

        # Apply autopilot.
        if self._active:
            if not self.target:
                # TODO: Look for another target?
                if self.seeker not in Rocket._seekers_none:
                    self._no_target_time += dt
                    if self._no_target_time >= self._no_target_selfdest_time:
                        self.explode()
                        return task.done
            else:
                self._no_target_time = 0.0
            self._ap_pause -= dt
            if self._ap_pause <= 0.0:
                self._ap_pause = self._ap_input(dt)
                if self._ap_pause is None:
                    self.target = None
                    self._ap_pause = 2.0

        #for trail in self.exhaust_trails:
            #pass

        # Update trace (debugging).
        if self._trace is not None:
            self._trace_accuframe += 1
            if self._trace_accuframe >= self._trace_frameskip:
                self._trace_accuframe = 0
                while self._trace_len >= self._trace_maxlen and self._trace_segs:
                    tseg = self._trace_segs.pop(0)
                    tlen = self._trace_lens.pop(0)
                    self._trace_len -= tlen
                self._trace_segs.append((self._trace_prevpos, pos))
                self._trace_lens.append((pos - self._trace_prevpos).length())
                self._trace_len += self._trace_lens[-1]
                self._trace.reset()
                self._trace.drawLines(self._trace_segs)
                #self._trace.drawTo(pos)
                self._trace.create()
                self._trace_prevpos = pos

        return task.cont


    def destroy (self):

        if not self.alive:
            return

        if self._trace is not None:
            self._trace.removeNode()
        Body.destroy(self)


    def collide (self, obody, chbx, cpos):

        inert = Body.collide(self, obody, chbx, cpos, silent=True)
        if inert:
            return True

        self.target_hit = (obody is self.target) # debug

        self.explode()

        return False


    def explode (self, pos=None):

        if not self.alive:
            return

        if pos is None:
            pos = self.pos()
        if self.world.otr_altitude(pos) < 20.0:
            debrispitch = (10, 80)
        else:
            debrispitch = (-90, 90)
        exp = PolyExplosion(
            world=self.world, pos=pos,
            sizefac=1.4, timefac=0.4, amplfac=0.8,
            smgray=pycv(py=(115, 150), c=(220, 255)), smred=0, firepeak=(0.5, 0.8),
            debrispart=(3, 6),
            debrispitch=debrispitch)
        snd = Sound3D(
            "audio/sounds/%s.ogg" % "explosion-missile",
            parent=exp, volume=self.expvol, fadetime=0.1)
        snd.play()

        self.shotdown = True
        self.destroy()

        touch = []
        if self.must_hit_expforce > 0.0 and self._last_target:
            touch = [(self._last_target, self.must_hit_expforce)]
        self.world.explosion_damage(force=self.expforce, ref=self, touch=touch)


    def move (self, dt):
        # Base override.
        # Called by world at end of frame.

        if dt == 0.0:
            return

        pos = vtod(self.pos())
        alt = pos[2]
        vel = vtod(self.vel())
        vdir = unitv(vel)
        speed = vel.length()
        quat = qtod(self.quat())
        udir = quat.getUp()
        fdir = quat.getForward()
        rdir = quat.getRight()
        angvel = vtod(self.angvel())

        if self._prev_path is not self.path: # must come before next check
            self._prev_path = self.path
            self._path_pos = 0.0
        if self.path is None or self.path.length() < self._path_pos:
            tdir = vdir
            ndir = udir
            if self.path is not None:
                tdir = self.path.tangent(self.path.length())
                ndir = self.path.normal(self.path.length())
            self.path = Segment(Vec3D(), tdir * 1e5, ndir)
            self._prev_path = self.path
            self._path_pos = 0.0

        # ====================
        # Translation.

        minspeed, maxspeed = self.limspeeds(alt)
        if self.pspeed is None:
            self.pspeed = maxspeed
        self.pspeed = clamp(self.pspeed, minspeed, maxspeed)
        minacc, maxacc = self.limaccs(alt=alt, speed=speed)
        dspeed = self.pspeed - speed
        if dspeed >= 0.0:
            tacc = min(dspeed * 1.0, maxacc)
        else:
            tacc = max(dspeed * 1.0, minacc)

        s = self._path_pos
        dp = self.path.point(s)
        t = self.path.tangent(s)
        tvel = vel.dot(t)
        s1 = s + tvel * dt + tacc * (0.5 * dt**2)
        dp1 = self.path.point(s1)
        tvel1 = tvel + tacc * dt
        t1 = self.path.tangent(s1)
        vel1 = t1 * tvel1
        dpos = dp1 - dp
        #acc = (dpos - vel * dt) / (0.5 * dt**2)
        n1 = self.path.normal(s1)
        r1 = self.path.radius(s1)
        acc = t1 * tacc + n1 * (tvel1**2 / r1)
        self._path_pos = s1

        self.node.setPos(vtof(pos + dpos))
        self._prev_vel = Vec3(self._vel) # needed in base class
        self._vel = vtof(vel1) # needed in base class
        self._acc = vtof(acc) # needed in base class

        # ====================
        # Rotation.

        fdir1 = t1
        paxis = fdir.cross(fdir1)
        if paxis.length() > 1e-5:
            paxis.normalize()
            dspitch = fdir.signedAngleRad(fdir1, paxis)
        else:
            paxis = rdir
            dspitch = 0.0
        pdang = dspitch
        pdquat = QuatD()
        pdquat.setFromAxisAngleRad(pdang, paxis)

        dquat = pdquat
        quat1 = quat * dquat

        angvel1 = (paxis * pdang) / dt
        angacc = (angvel1 - angvel) / dt

        self.node.setQuat(qtof(quat1))
        self._angvel = vtof(angvel1) # needed in base class
        self._angacc = vtof(angacc) # needed in base class

        self._flighttime += dt
        self._flightdist += dpos.length()

        # print_each(105, 0.25, "--rck1", pos, speed, self._flighttime)


    def limspeeds (self, alt=None):

        if alt is None:
            alt = self.pos()[2]

        return self.limspeeds_st(self, alt)


    @staticmethod
    def limspeeds_st (clss, alt):

        minspeed0, minspeed0b = clss.minspeed, clss.minspeed1
        maxspeed0, maxspeed0b = clss.maxspeed, clss.maxspeed1

        alt0b = clss.vmaxalt
        if alt < alt0b:
            ifac = alt / alt0b
            minspeed = minspeed0 + (minspeed0b - minspeed0) * ifac
            maxspeed = maxspeed0 + (maxspeed0b - maxspeed0) * ifac
        else:
            minspeed = minspeed0b
            maxspeed = maxspeed0b

        return minspeed, maxspeed


    def limaccs (self, alt=None, speed=None):

        if alt is None:
            alt = self.pos()[2]
        if speed is None:
            speed = self.speed()

        return self.limaccs_st(self, alt, speed)


    @staticmethod
    def limaccs_st (clss, alt, speed):

        maxthracc0, maxthracc0b = clss.maxthracc, clss.maxthracc1
        maxvdracc0, maxvdracc0b = clss.maxvdracc, clss.maxvdracc1

        # Altitude influence.
        alt0b = clss.vmaxalt
        if alt < alt0b:
            afac = alt / alt0b
            maxthracc = maxthracc0 + afac * (maxthracc0b - maxthracc0)
            maxvdracc = maxvdracc0 + afac * (maxvdracc0b - maxvdracc0)
        else:
            maxthracc = maxthracc0b
            maxvdracc = maxvdracc0b

        # Speed influence.
        minspeed, maxspeed = clss.limspeeds_st(clss, alt)
        sfac = speed / maxspeed
        minacc0 = maxvdracc * -sfac
        maxacc0 = maxthracc * (1.0 - sfac)
        minacc = minacc0
        maxacc = maxacc0

        return minacc, maxacc


    def _ap_input (self, dt):

        w = self.world
        t = self.target

        #print "========== rck-ap-start (world-time=%.2f)" % (w.time)

        # Choose initial control and flight mode.
        if self._ap_currctl is None:
            if self.seeker in Rocket._seekers_local:
                self._ap_currctl = "local"
            elif self.seeker in Rocket._seekers_remote:
                self._ap_currctl = "remote"
            else: # self.seeker in Rocket._seekers_none
                self._ap_currctl = "continue"
            if "transfer" in self.flightmodes:
                self._ap_currflt = "transfer"
            elif "intercept" in self.flightmodes:
                self._ap_currflt = "intercept"
            else: # "inertial" in self.flightmodes
                self._ap_currflt = "inertial"

        pos = ptod(self.pos())
        alt = pos[2]
        vel = vtod(self.vel())
        vdir = unitv(vel)
        speed = vel.length()
        if t and t.alive:
            tpos = ptod(t.pos(offset=self._effective_offset))
            tvel = vtod(t.vel())
            tspeed = tvel.length()
            tacc = vtod(t.acc())
            tabsacc = tacc.length()
        ppitch = self.ppitch()

        minspeed, maxspeed = self.limspeeds(alt)
        maxlfac = self.maxg
        minlfac = self.ming

        if t and t.alive:
            dpos = tpos - pos
            tdist = dpos.length()
            tdir = unitv(dpos)

        # Check if still tracking and return if not.
        havectl = False
        while not havectl: # control may switch
            if t and t.alive:
                if self._ap_currctl == "local":
                    # Check if the target is still within seeker FOV.
                    cosoffbore = tdir.dot(vdir)
                    tracking = (cosoffbore > cos(self.maxoffbore) or
                                self.must_hit_expforce > 0.0)
                    if tracking:
                        havectl = True
                    else:
                        if self.seeker in Rocket._seekers_remote:
                            self._ap_currctl = "remote"
                            # FIXME: What if no transfer mode?
                            self._ap_currflt = "transfer"
                        else:
                            havectl = True
                elif self._ap_currctl == "remote":
                    # TODO: Check if parent still tracks the target.
                    tracking = True
                    havectl = True
                elif self._ap_currctl == "continue":
                    tracking = False
                    havectl = True
            else:
                self._ap_currctl == "continue"
                tracking = False
                havectl = True

        if self._fudge_player_manoeuver:
            # Check special player manoeuvring to throw off the missile.
            player = self.world.player
            if tracking and player and t is player.ac:
                outer_time = 4.0 # as for outer pip on missile tracker
                inner_time = 2.0 # as for inner pip on missile tracker
                rel_reset_time = 1.2
                lim_pitch_ang = radians(-20)
                rel_max_load = 0.8
                lim_aspect_ang = radians(45)
                assert inner_time < outer_time
                assert rel_reset_time > 1.0
                assert pi * -0.5 < lim_pitch_ang < 0.0
                assert 0.0 < rel_max_load < 1.0
                assert 0.0 < lim_aspect_ang < pi * 0.5
                intc_time = tdist / speed
                pdq = player.ac.dynstate
                if intc_time > outer_time * rel_reset_time:
                    self._plmanv_done_1 = False
                    self._plmanv_done_2 = False
                if not self._plmanv_done_1:
                    if intc_time < outer_time:
                        udir = vtof(pdq.xit)
                        pitch_ang = 0.5 * pi - acos(clamp(udir[2], -1.0, 1.0))
                        if pitch_ang < lim_pitch_ang:
                            self._plmanv_done_1 = True
                if not self._plmanv_done_2:
                    if intc_time < inner_time:
                        ndir = pdq.xin
                        aspect_ang = acos(clamp(ndir.dot(-tdir), -1.0, 1.0))
                        if aspect_ang < lim_aspect_ang:
                            nmaxv = pdq.nmaxvab if pdq.hasab else pdq.nmaxv
                            nmaxc = min(pdq.nmax, nmaxv)
                            if pdq.n > nmaxc * rel_max_load:
                                self._plmanv_done_2 = True
                if self._plmanv_done_1 and self._plmanv_done_2:
                    tracking = False
                    dbgval(1, "missile-avoid",
                           (w.time, "%.2f", "time", "s"),
                           (self.name, "%s", "name"))

        if tracking:
            # Compute location of the target at interception,
            # assuming that its acceleration is constant,
            # and that parent points in the exact direction.
            # Compute with higher precision when near enough.
            sfvel = Vec3D()
            sdvelp = speed
            sfacc = Vec3D() # or self.acc()?
            sdaccp = 0.0
            ret = intercept_time(tpos, tvel, tacc,
                                 pos, sfvel, sdvelp, sfacc, sdaccp,
                                 finetime=2.0, epstime=(dt * 0.5), maxiter=5)
            if not ret:
                ret = 0.0, tpos, vdir
            inttime, tpos1, idir = ret

            # Modify intercept according to current state and mode.
            havemod = False
            while not havemod: # mode may switch
                if self._ap_currflt == "intercept":
                    havemod = True
                    adt = dt
                    # Modify intercept to keep sufficiently within boresight.
                    if self._ap_currctl == "local":
                        safeoffbore = self.maxoffbore * 0.8
                        offbore1 = acos(clamp(idir.dot(tdir), -1.0, 1.0))
                        if offbore1 > safeoffbore:
                            a1u = unitv(tpos1 - tpos)
                            ang1 = acos(clamp(a1u.dot(-tdir), -1.0, 1.0))
                            ang2 = pi - ang1 - safeoffbore
                            tdist1c = tdist * (sin(ang1) / sin(ang2))
                            anu = unitv(tdir.cross(idir))
                            q = QuatD()
                            q.setFromAxisAngleRad(safeoffbore, anu)
                            idirc = Vec3D(q.xform(tdir))
                            tpos1c = pos + idirc * tdist1c
                            tpos1 = tpos1c
                elif self._ap_currflt == "transfer":
                    tointtime = 15.0 #!!!
                    if inttime < tointtime:
                        offbore1 = acos(clamp(unitv(tpos - pos).dot(vdir), -1.0, 1.0))
                        safeoffbore = self.maxoffbore * 0.8
                        if offbore1 < safeoffbore:
                            # FIXME: What if no intercept mode?
                            self._ap_currflt = "intercept"
                            if self.seeker in Rocket._seekers_local:
                                self._ap_currctl = "local"
                    if self._ap_currflt == "transfer": # mode not switched
                        havemod = True
                        maxadt = 1.0
                        if inttime < tointtime:
                            adt = clamp((tointtime - inttime) * 0.1, dt, maxadt)
                            # Direct towards intercept.
                            tpos1 = tpos
                        else:
                            # Climb to best altitude, in direction of intercept.
                            adt = maxadt
                            dpos1 = tpos1 - pos
                            tdir1 = unitv(dpos1)
                            #maxlfac = max(maxlfac * 0.2, min(maxlfac, 6.0))
                            maxlfac = min(maxlfac, 12.0)
                            mintrad = speed**2 / (maxlfac * w.absgravacc)
                            tralt = max(self.vmaxalt, tpos[2])
                            daltopt = tralt - alt
                            cpitch = (1.0 - (alt / tralt)**2) * (0.5 * pi)
                            if self._ap_currctl == "local":
                                # If local control in transfer, must keep in bore.
                                safeoffbore = self.maxoffbore * 0.8
                                tpitch = atan(tdir1[2] / tdir1.getXy().length())
                                cpitch = clamp(cpitch,
                                               tpitch - safeoffbore,
                                               tpitch + safeoffbore)
                            tdir1xy = unitv(Vec3D(tdir1[0], tdir1[1], 0.0))
                            dpos1mxy = tdir1xy * (daltopt / tan(cpitch))
                            dpos1m = dpos1mxy + Vec3D(0.0, 0.0, daltopt)
                            tpos1 = pos + unitv(dpos1m) * (mintrad * 10.0)
                elif self._ap_currflt == "inertial":
                    pass
            #print("--rck-ap-state  ctl=%s  flt=%s  tdist=%.0f[m]  alt=%.0f[m]  ppitch=%.1f[deg]  adt=%.3f[s]" %
                #(self._ap_currctl, self._ap_currflt, tdist, alt, degrees(ppitch), adt))
        else:
            tpos1 = pos + vdir * (speed * 1.0)
            adt = None

        # Input path.
        dpos1 = tpos1 - pos
        tdist1 = dpos1.length()
        tdir1 = unitv(dpos1)
        ndir = vdir.cross(tdir1).cross(vdir)
        if ndir.length() > 1e-5:
            ndir.normalize()
            dpos1n = dpos1.dot(ndir) or 1e-10
            maxturntime = 5.0 #!!!
            turndist = min(tdist1, maxspeed * maxturntime)
            trad = turndist**2 / (2 * dpos1n)
            lfac = (speed**2 / trad) / w.absgravacc
            if lfac > maxlfac:
                lfac = maxlfac
                trad = speed**2 / (lfac * w.absgravacc)
        else:
            ndir = vtod(self.quat().getUp())
            trad = 1e6
        if trad < 1e6:
            tang = 2 * asin(clamp(dpos1n / tdist1, -1.0, 1.0))
            path = Arc(trad, tang, Vec3D(), vdir, ndir)
            #print "--hmap1  tdist=%.1f[m]  speed=%.1f[m/s]  trad=%.1f[m]  tang=%.1f[deg]  lfac=%.1f" % (tdist, speed, trad, degrees(tang), lfac)
        else:
            path = Segment(Vec3D(), vdir * 1e5, ndir)
            # print "--hmap2"
        self.path = path

        # # Input path.
        # vdir = unitv(vel)
        # dpos = tpos - pos
        # tdist = dpos.length()
        # tdir = unitv(dpos)
        # ndir = unitv(vdir.cross(tdir).cross(vdir))
        # dposn = dpos.dot(ndir) or 1e-5
        # dpost = dpos.dot(vdir) or 1e-5
        # maxtrad = tdist**2 / (2 * dposn)
        # mrlfac = (speed**2 / maxtrad) / w.absgravacc
        # if mrlfac < maxlfac:
            # lfac1 = clamp((maxlfac * 1e3) / tdist, 2.0, maxlfac)
            # trad = speed**2 / (lfac1 * w.absgravacc)
            # tang = atan(dposn / dpost)
            # tang_p = 2 * tang
            # niter = 0
            # maxiter = 10
            # while abs(tang_p - tang) > 1e-4 and niter < maxiter:
                # tang_p = tang
                # k1 = tan(tang)
                # k2 = sqrt(1.0 + k1**2)
                # tang = atan(((dposn - trad) * k2 + trad) / (dpost * k2 - trad * k1))
                # niter += 1
            # path = Arc(trad, tang, Vec3D(), vdir, ndir)
            # print "--hmap1  maxiter=%d  iter=%d  tdist=%.1f  speed=%.1f  trad=%.1f  tang=%.1f" % (maxiter, niter, tdist, speed, trad, degrees(tang))
        # else:
            # path = Segment(Vec3D(), vdir * 1e5, ndir)
            # print "--hmap2"
        # self.path = path

        # Input speed.
        self.pspeed = maxspeed

        #print "========== rck-ap-end"
        return adt


    @staticmethod
    def check_launch_free (launcher=None):

        return True


    def exec_post_launch (self, launcher=None):

        pass


    def _process_decoys (self, target, toffset, dtime):


        target_dir = unitv(target.pos(refbody=self))
        target_offbore = acos(clamp(target_dir[1], -1.0, 1.0))
        if target_offbore < self.maxoffbore:
            target_fwd = target.quat(refbody=self).getForward()
            target_aspect = acos(clamp(target_dir.dot(target_fwd), -1.0, 1.0))
            target_weight = intl01v((target_aspect / pi)**0.5, 1.0, 0.2)
            resist_mod = target_weight**((1.0 - self.decoyresist)**0.5)
            offset = toffset
        else:
            target_weight = 0.0
            resist_mod = 1.0
            offset = self._effective_offset # last offset

        while True:
            if not self._tracked_decoy:
                num_tested = 0
                for decoy in target.decoys:
                    if decoy.alive and decoy not in self._eliminated_decoys:
                        tracked = False
                        decoy_offbore = self.offbore(decoy)
                        if decoy_offbore < self.maxoffbore:
                            num_tested += 1
                            if randunit() > self.decoyresist * resist_mod:
                                tracked = True
                        if tracked:
                            self._tracked_decoy = decoy
                            break
                        else:
                            self._eliminated_decoys.add(decoy)
            else:
                num_tested = 1

            decoy_reloffb = 0.0
            decoy_effect = 0.0
            if self._tracked_decoy:
                decoy = self._tracked_decoy
                tracked = False
                if decoy.alive:
                    decoy_offbore = self.offbore(decoy)
                    if decoy_offbore < self.maxoffbore:
                        if target_weight and decoy_offbore > target_offbore:
                            decoy_reloffb = (target_offbore / decoy_offbore)**0.5
                        else:
                            decoy_reloffb = 1.0
                        decoy_effect = (1.0 - decoy.decay()) * decoy_reloffb
                        if decoy_effect > self.decoyresist * resist_mod:
                            offset = decoy.pos(refbody=target)
                            tracked = True
                if not tracked:
                    self._tracked_decoy = None
                    self._eliminated_decoys.add(decoy)

            if self._tracked_decoy or num_tested == 0:
                break

        #vf = lambda v, d=3: "(%s)" % ", ".join(("%% .%df" % d) % e for e in v)
        #num_seen = len(self._eliminated_decoys) + int(bool(self._tracked_decoy))
        #num_tracked = int(bool(self._tracked_decoy))
        #target_dist = self.pos(refbody=target, offset=toffset).length()
        #doffset = offset - toffset
        #print ("--procdec  num_seen=%d  target_weight=%.2f  "
               #"decoy_reloffb=%.2f  decoy_effect=%.2f  "
               #"target_dist=%.0f  doffset=%s"
               #% (num_seen, target_weight, decoy_reloffb, decoy_effect,
                  #target_dist, vf(doffset)))

        return offset


    @classmethod
    def launch_limits (cls, attacker, target, offset=None):

        weapon = cls

        apos = attacker.pos()
        pdir = attacker.quat().getForward()
        tpos = target.pos(offset=offset)
        tvel = target.vel()
        tspd = tvel.length()

        # Maximum range for non-manouevring target.
        malt = 0.5 * (apos[2] + tpos[2])
        spds = weapon.limspeeds_st(weapon, malt)
        accs = weapon.limaccs_st(weapon, malt, 0.0)
        fltime = weapon.maxflighttime - 0.5 * (spds[1] / accs[1])
        tvel1 = tvel
        fltime1 = fltime * 0.90 # safety
        rmax = max_intercept_range(tpos, tvel1, apos, spds[1], fltime1)
        # - correct once for bore-keeping (overcorrection)
        tpos1 = tpos + tvel1 * fltime1
        tdir1 = unitv(tpos1 - apos)
        offbore1 = acos(clamp(tdir1.dot(pdir), -1.0, 1.0))
        if offbore1 > weapon.maxoffbore:
            tdist1 = (tpos1 - apos).length()
            dbore1 = offbore1 - weapon.maxoffbore
            tarc1 = (tdist1 / sin(dbore1)) * dbore1
            fltime2 = fltime1 * (tdist1 / tarc1)
            rmax = max_intercept_range(tpos, tvel1, apos, spds[1], fltime2)

        # Maximum range for manouevring target.
        if hasattr(target, "mass"):
            #tminmass = getattr(target, "minmass", target.mass)
            ##tspds = target.limspeeds(mass=tminmass, alt=tpos[2], withab=True)
            #taccs = target.limaccs(mass=tminmass, alt=tpos[2], speed=tspd,
                                   #climbrate=0.0, turnrate=0.0,
                                   #ppitch=radians(-30.0), withab=True)
            tdpos = tpos - apos
            tdist = tdpos.length()
            #fltime1 = min(fltime, tdist / spds[1])
            tspd1 = tspd #+ 0.5 * fltime1 * taccs[1]
            tvel1 = unitv(tdpos) * tspd1
            fltime1 = fltime * 0.75 # safety inc. manoeuvring
            rman = max_intercept_range(tpos, tvel1, apos, spds[1], fltime1)
            # - correct once for bore-keeping (overcorrection)
            tpos1 = tpos + tvel1 * fltime1
            tdir1 = unitv(tpos1 - apos)
            offbore1 = acos(clamp(tdir1.dot(pdir), -1.0, 1.0))
            if offbore1 > weapon.maxoffbore:
                tdist1 = (tpos1 - apos).length()
                dbore1 = offbore1 - weapon.maxoffbore
                tarc1 = (tdist1 / sin(dbore1)) * dbore1
                fltime2 = fltime1 * (tdist1 / tarc1)
                rman1 = max_intercept_range(tpos, tvel1, apos, spds[1], fltime2)
                rman = rman1
        else:
            rman = rmax

        # Minimum range.
        rmin = weapon.minlaunchdist

        return rmin, rman, rmax
Exemplo n.º 13
0
class World(ShowBase):

    fps_text = fps_text2 = fps_text3 = fps_text4 = None
    room_dimentions = [0, 0]
    camera_position = [290., 1609., 370, -1980, -15, 0]  # x y z h p r
    drone = None
    drone_instance = None
    markers = {}
    marker_lines = {}
    marker_lines_observed = {}
    active_keys = {}
    loop_callback = None
    joy = None
    simulation = True
    drone_started = False

    def __init__(self, width=6.78, length=5.82, simulation=True, video=True):
        ShowBase.__init__(self)

        width *= 100
        length *= 100
        self.room_dimentions = [width, length]
        self.simulation = simulation

        self.wall1 = self.wall_model(0, 0, 0, width, 0)
        self.wall2 = self.wall_model(0, 0, 0, length, 90)
        self.wall3 = self.wall_model(width, length, 0, width, 180)
        self.wall4 = self.wall_model(width, length, 0, length, -90)

        self.root_3d = self.marker_model(position=[0., 0., 0.],
                                         orientation=[90, 90, 0])

        self.drone = self.drone_model()
        self.drone_instance = Drone(simulation=simulation, video=video)

        self.lx_drone = LineNodePath(self.render2d, 'box', 2)
        self.lx_drone.reparentTo(self.drone)
        self.lx_drone.setColor(1., 0., 0., 1.)
        self.lx_drone.setTransparency(TransparencyAttrib.MAlpha)
        self.lx_drone.setAlphaScale(0.5)
        self.lx_drone.drawLines([[(0., 0., 0.), (4., 0., 0.)]])
        self.lx_drone.create()
        self.ly_drone = LineNodePath(self.render2d, 'box', 2)
        self.ly_drone.reparentTo(self.drone)
        self.ly_drone.setColor(0., 1., 0., 1.)
        self.ly_drone.setTransparency(TransparencyAttrib.MAlpha)
        self.ly_drone.setAlphaScale(0.5)
        self.ly_drone.drawLines([[(0., 0., 0.), (0., 0., 4.)]])
        self.ly_drone.create()
        self.lz_drone = LineNodePath(self.render2d, 'box', 2)
        self.lz_drone.reparentTo(self.drone)
        self.lz_drone.setColor(0., 0., 1., 1.)
        self.lz_drone.setTransparency(TransparencyAttrib.MAlpha)
        self.lz_drone.setAlphaScale(0.5)
        self.lz_drone.drawLines([[(0., 0., 0.), (0., 4., 0.)]])
        self.lz_drone.create()

        try:
            self.joy = xbox.Joystick()
            joy_ready = False
            if not self.joy.A():
                joy_ready = True
            if not joy_ready:
                raise Exception("Joy not ready!")
            else:
                print("ready")
        except:
            pass

        # Add the spinCameraTask procedure to the task manager.
        self.tick_loop = self.taskMgr.add(self.tick, "tick_loop")

        self.accept("space", self.control_drone, [" "])
        self.accept("c", self.control_drone, ["c"])
        self.accept("x", self.control_drone, ["x"])
        self.accept("w", self.control_drone, ["w"])
        self.accept("a", self.control_drone, ["a"])
        self.accept("s", self.control_drone, ["s"])
        self.accept("d", self.control_drone, ["d"])
        self.accept("q", self.control_drone, ["q"])
        self.accept("e", self.control_drone, ["e"])
        self.accept("m", self.control_drone, ["m"])
        self.accept("r", self.control_drone, ["r"])
        self.accept("f", self.control_drone, ["f"])
        self.keypress_repeat("4", self.move_camera, ["x", -1])
        self.keypress_repeat("6", self.move_camera, ["x", 1])
        self.keypress_repeat("8", self.move_camera, ["y", 1])
        self.keypress_repeat("5", self.move_camera, ["y", -1])
        self.keypress_repeat("1", self.move_camera, ["z", 1])
        self.keypress_repeat("3", self.move_camera, ["z", -1])
        self.keypress_repeat("7", self.move_camera, ["h", -1])
        self.keypress_repeat("9", self.move_camera, ["h", 1])
        self.keypress_repeat("arrow_up", self.move_camera, ["p", 1])
        self.keypress_repeat("arrow_down", self.move_camera, ["p", -1])

    def control_drone(self, key):
        if key == " ":
            if not self.drone_started:
                self.drone_started = True
                self.drone_instance.takeoff()
            else:
                self.drone_started = False
                self.drone_instance.land()
        if key == "x":
            self.drone_instance.emergency()
        elif key == "c":
            self.drone_instance.move(0., 0., 0., 0.)
        elif key == "w":
            self.drone_instance.move(0., 0.08, 0., 0.)
        elif key == "s":
            self.drone_instance.move(0., -0.08, 0., 0.)
        elif key == "d":
            self.drone_instance.move(0.08, 0., 0., 0.)
        elif key == "a":
            self.drone_instance.move(-0.08, 0., 0., 0.)
        elif key == "q":
            self.drone_instance.move(0., 0., 0., 0.3)
        elif key == "e":
            self.drone_instance.move(0., 0., 0., -0.3)
        elif key == "m":
            self.drone_instance.mtrim()
        elif key == "r":
            self.drone_instance.move(0., 0., 0.14, 0.)
        elif key == "f":
            self.drone_instance.move(0., 0., -0.15, 0.)

    def keypress_repeat(self, key, callback, parameter):
        self.accept(key, self.keypress_start, [key, callback, parameter])
        self.accept(key + "-up", self.keypress_stop, [key])

    def keypress_start(self, key, callback, parameter):
        self.active_keys[key] = [callback, parameter]

    def keypress_stop(self, key):
        self.active_keys[key] = None

    def move_camera(self, parameter):
        if parameter[0] == "x":
            self.camera_position[0] += 10 * np.cos(
                np.deg2rad(self.camera_position[3])) * parameter[1]
            self.camera_position[1] += -10 * np.sin(
                np.deg2rad(self.camera_position[3])) * parameter[1]
        if parameter[0] == "y":
            self.camera_position[0] += 10 * np.sin(
                np.deg2rad(self.camera_position[3])) * parameter[1]
            self.camera_position[1] += 10 * np.cos(
                np.deg2rad(self.camera_position[3])) * parameter[1]
        if parameter[0] == "z":
            self.camera_position[2] += 10 * parameter[1]
        if parameter[0] == "h":
            self.camera_position[3] += parameter[1]
        if parameter[0] == "p":
            self.camera_position[4] += parameter[1]

    def joy_block(self, xbox_key):
        """ blocks the xbox key until it's released """
        while xbox_key():
            pass

    def tick(self, task):

        for key in self.active_keys:
            if self.active_keys[key] is not None:
                self.active_keys[key][0](self.active_keys[key][1])

        if self.joy is not None:
            if self.joy.Back():
                self.closeWindow(self.win)
                self.userExit()
                self.shutdown()
                self.destroy()

            # takeoff:
            if self.joy.A():
                print "takeoff"
                self.drone_instance.takeoff()
                self.joy_block(self.joy.A)

            # emergency:
            if self.joy.X():
                print "emergency"
                self.drone_instance.emergency()
                self.joy_block(self.joy.X)

            # emergency:
            if self.joy.B():
                print "land"
                self.drone_instance.land()
                self.joy_block(self.joy.B)

            (roll, throttle) = self.joy.leftStick()
            (yaw, pitch) = self.joy.rightStick()
            print roll, pitch, throttle, yaw
            self.drone_instance.move(roll, pitch, throttle, yaw)

        if self.loop_callback is not None:
            self.loop_callback(self, task)

        self.camera.setPos(self.camera_position[0], self.camera_position[1],
                           self.camera_position[2])
        self.camera.setHpr(-self.camera_position[3], self.camera_position[4],
                           self.camera_position[5])

        drone_position = self.convert_position(
            self.drone_instance.get_position())
        drone_orientation = self.drone_instance.get_orientation()

        self.drone.setPos(drone_position[0], drone_position[1],
                          drone_position[2])
        self.drone.setHpr(drone_orientation[0], drone_orientation[1],
                          drone_orientation[2])

        if task.time > 0:
            if self.fps_text is not None:
                self.fps_text.destroy()
            self.fps_text = OnscreenText(text="Tick-Rate: " +
                                         str(int(task.frame / task.time)),
                                         pos=(0.05, 0.05),
                                         scale=0.05,
                                         align=TextNode.ALeft,
                                         parent=self.a2dBottomLeft)

            if self.fps_text2 is not None:
                self.fps_text2.destroy()
            self.fps_text2 = OnscreenText(text="Camera Position: " +
                                          str(self.camera_position),
                                          pos=(0.05, 0.1),
                                          scale=0.05,
                                          align=TextNode.ALeft,
                                          parent=self.a2dBottomLeft)

            if self.fps_text3 is not None:
                self.fps_text3.destroy()
            self.fps_text3 = OnscreenText(
                text="Drone Position: " +
                str(self.drone_instance.get_position()),
                pos=(0.05, 0.15),
                scale=0.05,
                align=TextNode.ALeft,
                parent=self.a2dBottomLeft)

        return Task.cont

    def drone_model(self):
        drone = self.loader.loadModel("resources/models_3d/drone")
        drone.setScale(15, 15, 10)
        drone.reparentTo(self.render)
        return drone

    def wall_model(self, x, y, z, length, orientation):
        wall = self.loader.loadModel("resources/models_3d/plane")
        wall.reparentTo(self.render)
        wall.setScale(length, 0, 290)
        wall.setPos(x, y, z)
        wall.setH(orientation)
        wall.setTransparency(TransparencyAttrib.MAlpha)
        wall.setAlphaScale(0.1)
        return wall

    def marker_model(self, position, orientation):
        marker = self.loader.loadModel("resources/models_3d/plane")
        marker.reparentTo(self.render)
        marker.setScale(21, 0, 21)
        marker.setPos(position[0], position[1], position[2])
        marker.setHpr(orientation[0], orientation[1], orientation[2])
        marker.setTransparency(TransparencyAttrib.MAlpha)
        marker.setAlphaScale(0.5)
        marker.setColor(1., 0., 0., 1.)
        return marker

    def line_model(self, r, g, b):
        line = LineNodePath(self.render2d, 'box', 2)
        line.reparentTo(self.render)
        line.setColor(r, g, b, 1.)
        line.setTransparency(TransparencyAttrib.MAlpha)
        line.setAlphaScale(0.5)
        return line

    def point_model(self, position, color):
        marker = self.loader.loadModel("resources/models_3d/sphere")
        marker.reparentTo(self.render)
        marker.setScale(5, 5, 5)
        marker.setPos(position[0], position[1], position[2])
        marker.setTransparency(TransparencyAttrib.MAlpha)
        marker.setAlphaScale(0.5)
        marker.setColor(color[0], color[1], color[2], 1.)

    def line_draw(self, line, from_position, to_position):
        line.reset()
        line.drawLines([[(from_position[0], from_position[1],
                          from_position[2]),
                         (to_position[0], to_position[1], to_position[2])]])
        line.create()

    def get_dimensions(self):
        return [self.room_dimentions[0] / 100., self.room_dimentions[1] / 100.]

    def get_drone(self):
        return self.drone_instance

    def set_markers(self, markers):
        self.markers = {}
        for key, marker in markers.iteritems():
            self.markers[key] = self.marker_model(
                self.convert_position(marker[0]), marker[1])

    def set_default_markers(self):
        dimensions = self.get_dimensions()

        self.set_markers({
            0: [[dimensions[0] / 2, 1.5, 0.01], [0, 0, 0]],
            1: [[dimensions[0] / 2, 1.5, dimensions[1] - 0.01], [0, 0, 0]],
            2: [[dimensions[0] - 0.01, 1.5, dimensions[1] / 2], [90, 0, 0]],
            3: [[0.01, 1.5, dimensions[1] / 2], [90, 0, 0]]
        })

    def get_markers(self):
        return self.markers

    def convert_position(self, position):
        return [position[0] * 100, position[2] * 100, position[1] * 100]

    def hook_init(self, callback):
        callback(self)

    def hook_loop(self, callback):
        self.loop_callback = callback
Exemplo n.º 14
0
class LabTask03(DirectObject):
  
  #define the state of the game and level
  gameState = 'INIT'
  gameLevel = 1
  cameraState = 'STARTUP'
  count = 0
  attempts = 3
  posX = -200
  posY = 20
  posZ = 30
  score = 0
  contacts = 0
  pause = False
  fire = True
  desiredCamPos = Vec3(-200,30,20)

  def __init__(self):
    self.imageObject = OnscreenImage(image = 'models/splashscreen.png', pos=(0,0,0), scale=(1.4,1,1))
    preloader = Preloader()
    self.musicLoop = loader.loadSfx("music/loop/EndlessBliss.mp3")
    self.snowmansHit = loader.loadSfx("music/effects/snowball_hit.wav")
    self.candleThrow = loader.loadSfx("music/effects/snowball_throw.wav")
    self.presentHit = loader.loadSfx("music/effects/present_hit.wav")
    self.loseSound = loader.loadSfx("music/effects/Failure-WahWah.mp3")
    self.winSound = loader.loadSfx("music/effects/Ta Da-SoundBible.com-1884170640.mp3")
    self.nextLevelSound = loader.loadSfx("music/effects/button-17.wav")
    self.loseScreen = OnscreenImage(image = 'models/losescreen.png', pos=(0,0,0), scale=(1.4,1,1))
    self.loseScreen.hide()
    self.winScreen = OnscreenImage(image = 'models/winscreen.png', pos=(0,0,0), scale=(1.4,1,1))
    self.winScreen.hide()
    self.helpScreen = OnscreenImage(image = 'models/helpscreen.jpg', pos=(0,0,0.1), scale=(1,1,0.8))
    self.helpScreen.hide()
    self.backBtn = DirectButton(text=("Back"), scale = 0.1,  pos = (0,0,-0.8), command = self.doBack)
    self.retryBtn = DirectButton(text="Retry", scale = 0.1, pos = (0,0,0), command = self.doRetry)
    self.retryBtn.hide()
    self.menuBtn = DirectButton(text="Main Menu", scale = 0.1, pos = (0,0,0), command = self.doBack)
    self.menuBtn.hide()
    self.backBtn.hide()
    base.setBackgroundColor(0.1, 0.1, 0.8, 1)
    #base.setFrameRateMeter(True)
    
    # Position the camera
    base.cam.setPos(0, 30, 20)
    base.cam.lookAt(0, 30, 0)

    # Light
    alight = AmbientLight('ambientLight')
    alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
    alightNP = render.attachNewNode(alight)

    dlight = DirectionalLight('directionalLight')
    dlight.setDirection(Vec3(1, 1, -1))
    dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
    dlightNP = render.attachNewNode(dlight)

    render.clearLight()
    render.setLight(alightNP)
    render.setLight(dlightNP)

    # Input
    self.accept('escape', self.doExit)
    self.accept('r', self.doReset)
    self.accept('f1', self.toggleWireframe)
    self.accept('f2', self.toggleTexture)
    self.accept('f3', self.toggleDebug)
    self.accept('f5', self.doScreenshot)
    self.accept('f', self.doShoot, [True])
    self.accept('p', self.doPause)

    inputState.watchWithModifiers('forward', 'w')
    inputState.watchWithModifiers('left', 'a')
    inputState.watchWithModifiers('reverse', 's')
    inputState.watchWithModifiers('right', 'd')
    inputState.watchWithModifiers('turnLeft', 'q')
    inputState.watchWithModifiers('turnRight', 'e')
    
    inputState.watchWithModifiers('moveLineUp', 'i')
    inputState.watchWithModifiers('moveLineDown','k')
    inputState.watchWithModifiers('moveLineRight','l')
    inputState.watchWithModifiers('moveLineLeft','j')
    
    self.font = loader.loadFont('models/SHOWG.TTF')
    self.font.setPixelsPerUnit(60)
    self.attemptText = OnscreenText(text='', pos = (0.9,0.8), scale = 0.07, font = self.font)
    self.levelText = OnscreenText(text='', pos=(-0.9,0.9), scale = 0.07, font = self.font )
    self.scoreText = OnscreenText(text='', pos = (0.9,0.9), scale = 0.07, font = self.font)
    self.text = OnscreenText(text = '', 
                              pos = (0, 0), scale = 0.07, font = self.font)
    self.pauseText = OnscreenText(text='P: Pause', pos= (0.9,0.7), scale = 0.05, font = self.font)
    self.pauseText.hide()
    # Task
    taskMgr.add(self.update, 'updateWorld')

    # Physics
    self.setup()

  # _____HANDLER_____
  
  def doRetry(self):
    self.loseScreen.hide()
    self.levelText.clearText()
    self.scoreText.clearText()
    self.attemptText.clearText()
    self.playGame()
    self.retryBtn.hide()
    self.cleanup()
    self.setup()
    

  def doExit(self):
    self.cleanup()
    sys.exit(1)

  def doReset(self):
    self.attempts = 3
    self.cameraState = 'STARTUP'
    base.cam.setPos(0,30,20)
    self.arrow.removeNode()
    self.scoreText.clearText()
    self.levelText.clearText()
    self.attemptText.clearText()
    self.cleanup()
    self.setup()
    
  def toggleWireframe(self):
    base.toggleWireframe()

  def toggleTexture(self):
    base.toggleTexture()

  def toggleDebug(self):
    if self.debugNP.isHidden():
      self.debugNP.show()
    else:
      self.debugNP.hide()

  def doScreenshot(self):
    base.screenshot('Bullet')
    
    
  def doShoot(self, ccd):
    if(self.fire and self.attempts > 0 and self.gameState == 'PLAY'):
      self.cameraState = 'LOOK'
      self.fire = False
      self.candleThrow.play()
      self.attempts -= 1
      #get from/to points from mouse click
      ## pMouse = base.mouseWatcherNode.getMouse()
      ## pFrom = Point3()
      ## pTo = Point3()
      ## base.camLens.extrude(pMouse, pFrom, pTo)
      
      ## pFrom = render.getRelativePoint(base.cam, pFrom)
      ## pTo = render.getRelativePoint(base.cam, pTo)
      
      # calculate initial velocity
      v = self.pTo - self.pFrom
      ratio = v.length() / 40
      v.normalize()
      v *= 70.0 * ratio
      torqueOffset = random.random() * 10
      
      #create bullet
      shape = BulletSphereShape(0.5)
      shape01 = BulletSphereShape(0.5)
      shape02 = BulletSphereShape(0.5)
      shape03 = BulletSphereShape(0.5)
      body = BulletRigidBodyNode('Candle')
      bodyNP = self.worldNP.attachNewNode(body)
      bodyNP.node().addShape(shape, TransformState.makePos(Point3(0,0,0)))
      bodyNP.node().addShape(shape01, TransformState.makePos(Point3(0,0.5,-0.5)))
      bodyNP.node().addShape(shape02,TransformState.makePos(Point3(0,1,-1)))
      bodyNP.node().addShape(shape03,TransformState.makePos(Point3(0,1.5,-1.5)))
      bodyNP.node().setMass(100)
      bodyNP.node().setFriction(1.0)
      bodyNP.node().setLinearVelocity(v)
      bodyNP.node().applyTorque(v*torqueOffset)
      bodyNP.setPos(self.pFrom)
      bodyNP.setCollideMask(BitMask32.allOn())
      
      visNP = loader.loadModel('models/projectile.X')
      visNP.setScale(0.7)
      visNP.clearModelNodes()
      visNP.reparentTo(bodyNP)
      
      #self.bird = bodyNP.node()
      
      if ccd:
          bodyNP.node().setCcdMotionThreshold(1e-7)
          bodyNP.node().setCcdSweptSphereRadius(0.5)
          
      self.world.attachRigidBody(bodyNP.node())
      
      #remove the bullet again after 1 sec
      self.bullets = bodyNP
      taskMgr.doMethodLater(5, self.removeBullet, 'removeBullet', extraArgs=[bodyNP], 
                            appendTask = True)
      
    
  def removeBullet(self, bulletNP, task):
    self.cameraState = 'STAY'
    self.fire = True
    self.world.removeRigidBody(bulletNP.node())
    bulletNP.removeNode()
    if(self.attempts <= 0 and len(self.snowmans)>0):
      self.gameState = 'LOSE'
      self.doContinue()
      
    return task.done

  # ____TASK___

  def processInput(self, dt):
    force = Vec3(0, 0, 0)
    torque = Vec3(0, 0, 0)
    #print self.pTo.getY()
    if inputState.isSet('forward'):
      if(self.pTo.getZ() < 40):
        self.pTo.addZ(0.5)
    if inputState.isSet('reverse'):
      if(self.pTo.getZ() > 0 ):
        self.pTo.addZ(-0.5)
    if inputState.isSet('left'):
      if(self.pTo.getY() < 100):
        self.pTo.addY(0.5)
        self.arrow.setScale(self.arrow.getSx(),self.arrow.getSy()-0.006,self.arrow.getSz())
    if inputState.isSet('right'):
      if(self.pTo.getY() > 60):
        self.pTo.addY(-0.5)
        self.arrow.setScale(self.arrow.getSx(),self.arrow.getSy()+0.006,self.arrow.getSz())
        
    self.arrow.lookAt(self.pTo)
    
  def processContacts(self, dt):
      for box in self.boxes:
        for snowman in self.snowmans:
          result = self.world.contactTestPair(box, snowman.node())
      
          if (result.getNumContacts() > 0):
            self.snowmansHit.play()
            self.score += 100
            self.text.setPos(0,0.7)
            self.text.setText("HIT")
            self.snowmans.remove(snowman)
            self.world.removeRigidBody(snowman.node())
            snowman.removeNode()
            if(len(self.snowmans)  <= 0):
              self.gameState = "NEXT"
              self.text.setText('Nice! Press space to continue')

              
      for box in self.boxes:
        for present in self.presents:
          result01 = self.world.contactTestPair(box,present.node())
          if(result01.getNumContacts() > 0):
            self.presents.remove(present)
            self.world.removeRigidBody(present.node())
            present.removeNode()
            self.presentHit.play()
            self.score += 500
            
  def doContinue(self):
    if(self.gameState == 'INIT'):
      self.gameState = 'MENU'
      self.text.clearText()
      self.musicLoop.setLoop(True)
      self.musicLoop.setVolume(0.5)
      self.musicLoop.play()
      self.startBtn = DirectButton(text=("Play"), scale = 0.1, pos = (0,0,0),command=self.playGame)
      self.helpBtn = DirectButton(text=("Help"), scale = 0.1, pos = (0,0,-0.2),command=self.help)
      self.exitBtn = DirectButton(text=("Exit"), scale = 0.1,  pos = (0,0,-0.4), command = self.doExit)
      return
    
    if self.gameState == 'NEXT':
      self.nextLevelSound.play()
      self.fire = True
      self.gameLevel += 1
      self.score += (self.attempts * 100)
      self.doReset()
      self.gameState = 'PLAY'
      return
    
    if self.gameState == 'LOSE':
      self.loseSound.play()
      self.arrow.removeNode()
      self.loseScreen.show()
      self.levelText.hide()
      self.attemptText.hide()
      self.scoreText.hide()
      self.text.hide()
      self.pauseText.hide()
      self.retryBtn.show()
      return
    
    if self.gameState == 'WIN':
      self.levelText.hide()
      self.attemptText.hide()
      self.scoreText.clearText()
      self.scoreText.setPos(0,0.6)
      self.scoreText.setText("%s"%self.score)
      self.winScreen.show()
      self.winSound.play()
      self.menuBtn.show()
      self.pauseText.hide()
      return
      
    
  def playGame(self):
    print "Play Game"
    self.attempts = 3
    self.score = 0
    self.gameLevel = 1
    self.gameState = 'PLAY'
    self.musicLoop.setVolume(0.3)
    self.imageObject.hide()
    self.startBtn.hide()
    self.exitBtn.hide()
    self.helpBtn.hide()
    self.cleanup()
    self.setup()
    
  def doBack(self):
    self.gameState = 'MENU'
    self.scoreText.setPos(0.9,0.9)
    self.scoreText.hide()
    self.imageObject.show()
    self.startBtn.show()
    self.exitBtn.show()
    self.helpBtn.show()
    self.helpScreen.hide()
    self.backBtn.hide()
    self.menuBtn.hide()
    self.winScreen.hide()
    
  def help(self):
    self.gameState = 'HELP'
    self.startBtn.hide()
    self.exitBtn.hide()
    self.helpBtn.hide()
    self.backBtn.show()
    self.helpScreen.show()
    return
    
  def doPause(self):
    self.pause  = not self.pause
    if(self.pause):
      self.text.setText("Pause")
    else:
      self.text.clearText()
      

  def update(self, task):

    dt = globalClock.getDt()
    if(not self.pause):
      if self.gameState == 'INIT':
        self.text.setPos(0,0)
        self.text.setText('Press space to continue')
        self.accept('space',self.doContinue)
          
      if self.gameState == 'PLAY':
        #print self.posZ
        #if(self.posX < -120):
        #  self.posX += 0.03
        #  self.posZ -= 0.02
        #elif(self.posZ < 70):
        #  self.posZ += 0.02;
        #elif(self.posZ > 70 and self.posX > -120):
        #  self.posZ -= 0.02
        #  self.posX -= 0.03
        #base.cam.setPos(self.posX, self.posZ, self.posY)
        self.levelText.setText('Level: %s'%self.gameLevel)
        self.attemptText.setText('Tries Left: %s'%self.attempts)
        self.scoreText.setText('Score: %s'%self.score)
        self.pauseText.show()
        self.processContacts(dt)
        self.world.doPhysics(dt, 20, 1.0/180.0)
        #self.drawLines()
        self.processInput(dt)
        
        if self.cameraState == 'STARTUP':
          oldPos = base.cam.getPos()
          pos = (oldPos*0.9) + (self.desiredCamPos*0.1)
          base.cam.setPos(pos)
          base.cam.lookAt(0,30,0)
        elif self.cameraState == 'STAY':
          #oldPos = base.cam.getPos()
          #currPos = (oldPos*0.9) + (self.desiredCamPos*0.1)
          #base.cam.setPos(currPos)
          base.cam.lookAt(0,30,0)
        elif self.cameraState == 'LOOK':
          base.cam.lookAt(self.bullets)
          #base.cam.setPos(-200,self.bullets.getZ(),20)
        
      if self.gameState == 'NEXT':
        self.world.doPhysics(dt, 20, 1.0/180.0)
        

      ## self.raycast()
    
    return task.cont
      
  def raycast(self):
    # Raycast for closest hit
    tsFrom = TransformState.makePos(Point3(0,0,0))
    tsTo = TransformState.makePos(Point3(10,0,0))
    shape = BulletSphereShape(0.5)
    penetration = 1.0
    result = self.world.sweepTestClosest(shape, tsFrom, tsTo, penetration)
    if result.hasHit():
        torque = Vec3(10,0,0)
        force = Vec3(0,0,100)
        
        ## for hit in result.getHits():
            ## hit.getNode().applyTorque(torque)
            ## hit.getNode().applyCentralForce(force)
        result.getNode().applyTorque(torque)
        result.getNode().applyCentralForce(force)
        ## print result.getClosestHitFraction()
        ## print result.getHitFraction(), \
            ## result.getNode(), \
            ## result.getHitPos(), \
            ## result.getHitNormal()

  def cleanup(self):
    self.world = None
    self.worldNP.removeNode()
    self.arrow.removeNode()
    self.lines.reset()
    self.text.clearText()

  def setup(self):
    self.attemptText.show()
    self.levelText.show()
    self.scoreText.show()
    self.text.show()
    
    self.worldNP = render.attachNewNode('World')

    # World
    self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
    self.debugNP.show()

    self.world = BulletWorld()
    self.world.setGravity(Vec3(0, 0, -9.81))
    self.world.setDebugNode(self.debugNP.node())
    
    #arrow
    self.scaleY = 10
    self.arrow = loader.loadModel('models/arrow.X')
    self.arrow.setScale(0.5,0.5,0.5)
    self.arrow.setAlphaScale(0.5)
    #self.arrow.setTransparency(TransparencyAttrib.MAlpha) 
    self.arrow.reparentTo(render)
    
    #SkyBox
    skybox = loader.loadModel('models/skybox.X')
    skybox.reparentTo(render)

    # Ground
    shape = BulletPlaneShape(Vec3(0, 0, 1), 0)

    np = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground'))
    np.node().addShape(shape)
    np.setPos(0, 0, -1)
    np.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(np.node())
    
    visualNP = loader.loadModel('models/ground.X')
    visualNP.clearModelNodes()
    visualNP.reparentTo(np)
    
    #some boxes
    self.boxes = []
    self.snowmans = []
    self.platforms = []
    self.presents = []
    #TODO: Make a table
    #Table Top
    #self.createBox(Vec3(),Vec3())
    if(self.gameLevel == 1):
      self.createBox(Vec3(5,7,1),Vec3(0,5,10),1.0)
      #2 legs
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-1,5),1.0)
      
      # Pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(1.5, Vec3(0,-10,4.0),10.0)
      
    if(self.gameLevel == 2):
      #table01
      self.createBox(Vec3(5,14,1),Vec3(0,-2,12),2.0)
      self.createBox(Vec3(5,7,1),Vec3(0,5,10),2.0)
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-1,5),1.0)
      #table02
      self.createBox(Vec3(5,7,1),Vec3(0,-9,10),2.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-3,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-15,5),1.0)
      #table03
      self.createBox(Vec3(1,1,1), Vec3(0,-1,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,-3,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,3,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,-5,14), 2.0)
      self.createBox(Vec3(1,1,1), Vec3(0,5,14), 2.0)
      #pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(2.0, Vec3(0,-9,2.0), 10.0)
      self.createSnowman(2.0,Vec3(0,-23,2.0),10.0)
      
    if(self.gameLevel == 3):
      #table01
      self.createBox(Vec3(4,2,2),Vec3(0,12,12),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,11,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,13,5),1.0)
      #table02
      self.createBox(Vec3(4,2,2),Vec3(0,-15,12),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-14,5),1.0)
      self.createBox(Vec3(4,1,4),Vec3(0,-16,5),1.0)
      #table03
      self.createBox(Vec3(4,10,1),Vec3(0,-1,12),1.0)
      self.createBox(Vec3(4,10,1),Vec3(0,-1,14),1.0)
      self.createBox(Vec3(4,2,4),Vec3(0,-2,5),0.1)
      #table04
      self.createPlatform(Vec3(4,8,1),Vec3(0,7,16),1.0)
      self.createPlatform(Vec3(4,8,1),Vec3(0,-9,16),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,13,20),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-16,20),1.0)
      #table05
      self.createBox(Vec3(4,15,1),Vec3(0,-1,24),1.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,2,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,-2,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,4,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,8,20),5.0)
      self.createStoneBox(Vec3(1,1,1),Vec3(0,6,20),5.0)
      
      #pigs
      self.createSnowman(2.0,Vec3(0, 5, 2.0),10.0)
      self.createSnowman(2.0,Vec3(0,-8.5,2.0),10.0)
      self.createSnowman(1.5, Vec3(0,-9,19.5), 7.0)
      
      #presents
      self.createPresent(Vec3(2,2,2),Vec3(0,-20,5))
         
    if(self.gameLevel == 4):
      #wall
      self.createStoneBox(Vec3(4,1.5,10), Vec3(0,20,10),20)
      #table01
      self.createBox(Vec3(4,1,5), Vec3(0,7,7),1)
      self.createBox(Vec3(4,1,5), Vec3(0,0,7),1)
      self.createBox(Vec3(4,1,4), Vec3(0,3,7),1)
      self.createPlatform(Vec3(5,8,1), Vec3(0,4,13),1)
      self.createBox(Vec3(4,1,3), Vec3(0,11,18),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-3,18),1)
      self.createBox(Vec3(4,8,1), Vec3(0,4,25),1)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,4,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,7,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,2,27),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,2,29),2)
      #stairs
      self.createPlatform(Vec3(4,50,4), Vec3(0,-55,5),100)
      #table02
      self.createBox(Vec3(4,1,5), Vec3(0,-13,15),1)
      self.createBox(Vec3(4,1,5), Vec3(0,-20,15),1)
      self.createBox(Vec3(4,1,4), Vec3(0,-17,15),1)
      self.createPlatform(Vec3(4,8,1), Vec3(0,-16,22),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-9,28),1)
      self.createBox(Vec3(4,1,3), Vec3(0,-23,28),1)
      self.createBox(Vec3(4,8,1), Vec3(0,-16,33),1)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-16,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-13,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-18,35),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-18,37),2)
      self.createStoneBox(Vec3(1,1,1), Vec3(0,-14,37),2)
      
      #snowman
      self.createSnowman(2.0,Vec3(0,30,5),1.0)
      self.createSnowman(1.5,Vec3(0,4,18),1.0)
      self.createSnowman(1.5,Vec3(0,-13,26),1.0)
      self.createSnowman(1.5,Vec3(0,-19,26),1.0)
      self.createSnowman(2.0,Vec3(0,12,5),1.0)
      self.createPresent(Vec3(2,2,2),Vec3(0,-25,13))
      self.createPresent(Vec3(3,3,3),Vec3(0,-30,13))
      self.createPresent(Vec3(4,4,4),Vec3(0,-36,13))
      #self.createSnowman(1.5,Vec3(0,4,20),1.0)

      
    if(self.gameLevel == 5):
      #table01
      self.createStoneBox(Vec3(4,7,3), Vec3(0,30,5),10.0)
      self.createStoneBox(Vec3(4,7,3), Vec3(0,-30,5),10.0)
      self.createBox(Vec3(4,1,3), Vec3(0,0,5), 1.0)
      self.createSnowman(1.5,Vec3(0,-6,5),1.0)
      self.createSnowman(1.5,Vec3(0,6,5),1.0)
      self.createBox(Vec3(4,1,3), Vec3(0,-12,5), 1.0)
      self.createBox(Vec3(4,1,3), Vec3(0,12,5), 1.0)
      self.createSnowman(1.5,Vec3(0,-18,5),1.0)
      self.createSnowman(1.5,Vec3(0,18,5),1.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-18,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-6,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,6,10), 0.1)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,18,10), 0.1)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,23,14), 1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,-23,14), 1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,18,14),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-18,14),1.0)
      self.createStoneBox(Vec3(4,1,7),Vec3(0,13,20), 2.0)
      self.createStoneBox(Vec3(4,1,7),Vec3(0,-13,20), 2.0)
      self.createBox(Vec3(4,1,3),Vec3(0,8,14),1.0)
      self.createBox(Vec3(4,1,3),Vec3(0,-8,14),1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,3,14), 1.0)
      self.createStoneBox(Vec3(4,1,3),Vec3(0,-3,14), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,-20 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,20 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,-5 ,20), 1.0)
      self.createPlatform(Vec3(4,3.5,1),Vec3(0,5 ,20), 1.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,-18,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,18,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,-7.5,25), 2.0)
      self.createStoneBox(Vec3(4,1,3.5),Vec3(0,7.5,25), 2.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,-12,30), 2.0)
      self.createStoneBox(Vec3(4,6,1),Vec3(0,12,30), 2.0)
      self.createBox(Vec3(4,1,5),Vec3(0,-5,30), 2.0)
      self.createBox(Vec3(4,1,5),Vec3(0,5,30), 2.0)
      self.createBox(Vec3(4,5,1),Vec3(0,0,40), 2.0)
      self.createPlatform(Vec3(4,2,0.5),Vec3(0,0,42), 2.0)
      self.createStoneBox(Vec3(4,0.5,2),Vec3(0,-3.5,45), 2.0)
      self.createStoneBox(Vec3(4,0.5,2),Vec3(0,3.5,45), 2.0)
      self.createStoneBox(Vec3(4,4,0.5),Vec3(0,0,48), 2.0)
      
      self.createPresent(Vec3(1.5,1.5,1.5),Vec3(0,22,30))
      self.createPresent(Vec3(1.5,1.5,1.5),Vec3(0,-22,30))
      self.createPresent(Vec3(2,2,1),Vec3(0,0,44))
      self.createPresent(Vec3(3,3,4),Vec3(0,0,33))
      
      
    if(self.gameLevel > 5):
      self.gameState = 'WIN'
      self.doContinue()
      return
        
    # drawing lines between the points 
    ## self.lines = LineNodePath(parent = render, thickness = 3.0, colorVec = Vec4(1, 0, 0, 1))
    ## self.pFrom = Point3(-4, 0, 0.5)
    ## self.pTo = Point3(4, 0, 0.5)
    
    # Aiming line 
    self.lines = LineNodePath(parent = render, thickness = 3.0, 
                              colorVec = Vec4(1, 0, 0, 1))
    self.pFrom = Point3(0, 100, 0.5)
    self.pTo = Point3(0, 60, 10)
    
    self.arrow.setPos(self.pFrom)
      
    
  def drawLines(self):  
    # Draws lines for the ray.
    self.lines.reset()  
    self.lines.drawLines([(self.pFrom,self.pTo)])
    self.lines.create()
    
  def createBox(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Obstacle')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/crate.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.boxes.append(body)
    
  def createStoneBox(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Obstacle')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/stone.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.boxes.append(body)
    
  def createSnowman(self, size, pos, mass):
    shape = BulletBoxShape(Vec3(size,size,size))
    shape01 = BulletSphereShape(size/2)
    body = BulletRigidBodyNode('Snowman')
    np = self.worldNP.attachNewNode(body)
    np.node().setMass(mass)
    np.node().addShape(shape, TransformState.makePos(Point3(0,0,-1)))
    np.node().addShape(shape01, TransformState.makePos(Point3(0,0,1)))
    np.node().setFriction(10.0)
    np.node().setDeactivationEnabled(False)
    np.setPos(pos)
    np.setCollideMask(BitMask32.allOn())
      
    self.world.attachRigidBody(np.node())
  
    visualNP = loader.loadModel('models/snowman.X')
    visualNP.setScale(size)
    visualNP.clearModelNodes()
    visualNP.reparentTo(np)
    self.snowmans.append(np)
    
  def createPlatform(self,size,pos,mass):
    shape = BulletBoxShape(size)
    body = BulletRigidBodyNode('Platform')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(mass)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())

    self.world.attachRigidBody(bodyNP.node())
            
    visNP = loader.loadModel('models/crate.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.platforms.append(body)
    
  def createPresent(self,size,pos):
    shape = BulletBoxShape(size*0.7)
    body = BulletRigidBodyNode('Present')
    bodyNP = self.worldNP.attachNewNode(body)
    bodyNP.node().addShape(shape)
    bodyNP.node().setMass(1.0)
    bodyNP.node().setFriction(1.0)
    bodyNP.node().setDeactivationEnabled(False)
    bodyNP.setPos(pos)
    bodyNP.setCollideMask(BitMask32.allOn())
    
    self.world.attachRigidBody(bodyNP.node())
    
    visNP = loader.loadModel('models/present.X')
    visNP.setScale(size*2)
    visNP.clearModelNodes()
    visNP.reparentTo(bodyNP)
    self.presents.append(bodyNP)
class DirectDiagram(DirectFrame):
    def __init__(self, parent=None, **kw):
        optiondefs = (
            # Define type of DirectGuiWidget
            ('data', [], self.refresh),
            ('numPosSteps', 0, self.refresh),
            ('numPosStepsStep', 1, self.refresh),
            ('numNegSteps', 0, self.refresh),
            ('numNegStepsStep', 1, self.refresh),
            ('numtextScale', 0.05, self.refresh),
            ('showDataNumbers', False, self.refresh),
            ('dataNumtextScale', 0.05, self.refresh),
            ('stepAccuracy', 2, self.refresh),
            ('stepFormat', float, self.refresh),
            ('numberAreaWidth', 0.15, self.refresh),
            #('numStates',      1,           None),
            #('state',          DGG.NORMAL,  None),
        )
        # Merge keyword options with default options
        self.defineoptions(kw, optiondefs)

        self.lines = None
        self.measureLines = None
        self.centerLine = None
        self.xDescriptions = []
        self.points = []

        # Initialize superclasses
        DirectFrame.__init__(self, parent)

        # Call option initialization functions
        self.initialiseoptions(DirectDiagram)

    def refresh(self):
        # sanity check so we don't get here to early
        if not hasattr(self, "bounds"): return
        self.frameInitialiseFunc()

        textLeftSizeArea = self['numberAreaWidth']
        # get the left and right edge of our frame
        left = DGH.getRealLeft(self)
        right = DGH.getRealRight(self)
        diagramLeft = left + textLeftSizeArea

        xStep = (DGH.getRealWidth(self) -
                 textLeftSizeArea) / (len(self['data']) - 1)
        posYRes = DGH.getRealTop(self) / (self['numPosSteps']
                                          if self['numPosSteps'] > 0 else max(
                                              self['data']))
        negYRes = DGH.getRealBottom(self) / (-self['numNegSteps']
                                             if self['numNegSteps'] > 0 else
                                             min(self['data']))

        # remove old content
        if self.lines is not None:
            self.lines.removeNode()

        if self.measureLines is not None:
            self.measureLines.removeNode()

        if self.centerLine is not None:
            self.centerLine.removeNode()

        for text in self.xDescriptions:
            text.removeNode()
        self.xDescriptions = []

        for text in self.points:
            text.removeNode()
        self.points = []

        # prepare the line drawings
        self.lines = LineNodePath(parent=self,
                                  thickness=3.0,
                                  colorVec=(1, 0, 0, 1))
        self.measureLines = LineNodePath(parent=self,
                                         thickness=1.0,
                                         colorVec=(0, 0, 0, 1))
        self.centerLine = LineNodePath(parent=self,
                                       thickness=2.0,
                                       colorVec=(0, 0, 0, 1))

        # draw the center line
        self.centerLine.reset()
        self.centerLine.drawLines([((diagramLeft, 0, 0), (right, 0, 0))])
        self.centerLine.create()

        self.xDescriptions.append(
            self.createcomponent('value0', (),
                                 None,
                                 DirectLabel, (self, ),
                                 text="0",
                                 text_scale=self['numtextScale'],
                                 text_align=TextNode.ARight,
                                 pos=(diagramLeft, 0, -0.01),
                                 relief=None,
                                 state='normal'))

        # calculate the positive measure lines and add the numbers
        measureLineData = []
        numSteps = (self['numPosSteps'] if self['numPosSteps'] > 0 else
                    math.floor(max(self['data']))) + 1
        for i in range(1, numSteps, self['numPosStepsStep']):
            measureLineData.append(
                ((diagramLeft, 0, i * posYRes), (right, 0, i * posYRes)))

            calcBase = 1 / DGH.getRealTop(self)
            maxData = self['numPosSteps'] if self['numPosSteps'] > 0 else max(
                self['data'])
            value = self['stepFormat'](round(i * posYRes * calcBase * maxData,
                                             self['stepAccuracy']))
            y = i * posYRes
            self.xDescriptions.append(
                self.createcomponent('value{}'.format(value), (),
                                     None,
                                     DirectLabel, (self, ),
                                     text=str(value),
                                     text_scale=self['numtextScale'],
                                     text_align=TextNode.ARight,
                                     pos=(diagramLeft, 0, y - 0.025),
                                     relief=None,
                                     state='normal'))

        # calculate the negative measure lines and add the numbers
        numSteps = (self['numNegSteps'] if self['numNegSteps'] > 0 else
                    math.floor(abs(min(self['data'])))) + 1
        for i in range(1, numSteps, self['numNegStepsStep']):
            measureLineData.append(
                ((diagramLeft, 0, -i * negYRes), (right, 0, -i * negYRes)))

            calcBase = 1 / DGH.getRealBottom(self)
            maxData = self['numPosSteps'] if self['numPosSteps'] > 0 else max(
                self['data'])
            value = self['stepFormat'](round(i * negYRes * calcBase * maxData,
                                             self['stepAccuracy']))
            y = -i * negYRes
            self.xDescriptions.append(
                self.createcomponent('value{}'.format(value), (),
                                     None,
                                     DirectLabel, (self, ),
                                     text=str(value),
                                     text_scale=self['numtextScale'],
                                     text_align=TextNode.ARight,
                                     pos=(diagramLeft, 0, y + 0.01),
                                     relief=None,
                                     state='normal'))

        # Draw the lines
        self.measureLines.reset()
        self.measureLines.drawLines(measureLineData)
        self.measureLines.create()

        lineData = []
        for i in range(1, len(self['data'])):
            yResA = posYRes if self['data'][i - 1] >= 0 else negYRes
            yResB = posYRes if self['data'][i] >= 0 else negYRes
            lineData.append((
                # Point A
                (diagramLeft + (i - 1) * xStep, 0, self['data'][i - 1] * yResA
                 ),
                # Point B
                (diagramLeft + i * xStep, 0, self['data'][i] * yResB)))

            if (self['showDataNumbers']):
                value = round(self['data'][i - 1], self['stepAccuracy'])
                self.points.append(
                    self.createcomponent('value{}'.format(value), (),
                                         None,
                                         DirectLabel, (self, ),
                                         text=str(value),
                                         text_scale=self['dataNumtextScale'],
                                         text_align=TextNode.ARight,
                                         pos=(diagramLeft + (i - 1) * xStep, 0,
                                              self['data'][i - 1] * yResA),
                                         relief=None,
                                         state='normal'))

        # Draw the lines
        self.lines.reset()
        self.lines.drawLines(lineData)
        self.lines.create()
Exemplo n.º 16
0
    def drawAxis(self, root, origin):
        PX = origin[0]
        PY = origin[1]
        PZ = origin[2]

        lengthX = PX + 1.5
        lengthY = PY + 1.5
        lengthZ = PZ + 1.5
        q1 = PX + 0.5
        q2 = -q1

        arrowLENGHT = PX + 0.2

        arrowXx1 = PY + 0.08
        arrowXx2 = PY - 0.08
        arrowXz2 = PX + 1.3

        arrowYx1 = PX + 0.08
        arrowYx2 = PX - 0.08
        arrowYz2 = PY + 1.3

        arrowZx1 = PX + 0.08
        arrowZx2 = PX - 0.08
        arrowZz2 = PZ + 1.3

        PIVarX = LineNodePath(root, "pivotX", 3, Vec4(1, 0, 0, 1))
        PIVarY = LineNodePath(root, "pivotY", 3, Vec4(0, 1, 1, 1))
        PIVarZ = LineNodePath(root, "pivotZ", 3, Vec4(1, 1, 0, 1))

        PIVOThandler = LineNodePath(root, "handler", 2, Vec4(1, 0, 1, 1))

        PIVarX.reparentTo(PIVOThandler)
        PIVarY.reparentTo(PIVOThandler)
        PIVarZ.reparentTo(PIVOThandler)

        arrowX1 = (lengthX, PY, PZ)
        arrowX2 = (arrowXz2, arrowXx1, PZ)
        arrowX3 = (arrowXz2, arrowXx2, PZ)

        arrowY1 = (PX, lengthY, PZ)
        arrowY2 = (arrowYx1, arrowYz2, PZ)
        arrowY3 = (arrowYx2, arrowYz2, PZ)

        arrowZ1 = (PX, PY, lengthZ)
        arrowZ2 = (arrowZx1, PY, arrowZz2)
        arrowZ3 = (arrowZx2, PY, arrowZz2)

        PIVarX.drawLines([[(PX, PY, PZ), (lengthX, PY, PZ)], [arrowX1, arrowX2], [arrowX1, arrowX3]])
        PIVarY.drawLines([[(PX, PY, PZ), (PX, lengthY, PZ)], [arrowY1, arrowY2], [arrowY1, arrowY3]])
        PIVarZ.drawLines([[(PX, PY, PZ), (PX, PY, lengthZ)], [arrowZ1, arrowZ2], [arrowZ1, arrowZ3]])

        PIVOThandler.drawLines(
            [
                [(PX, PY, PZ), (PX + 0.5, PY, PZ)],
                [(PX + 0.5, PY, PZ), (PX, PY + 0.5, PZ)],
                [(PX, PY + 0.5, PZ), (PX, PY, PZ)],
            ]
        )

        PIVarX.create()
        PIVarY.create()
        PIVarZ.create()
        PIVOThandler.create()

        return PIVOThandler
Exemplo n.º 17
0
from pandac.PandaModules import *
from direct.directtools.DirectGeometry import LineNodePath
from direct.gui.OnscreenText import OnscreenText
import buttonsGRID

global output
output = [1]

textObject = OnscreenText(text="gridUNITS",
                          pos=(-1.23, .94),
                          scale=0.04,
                          fg=(0, 0, 0, .8))
textObject.setTransparency(TransparencyAttrib.MAlpha)

line = LineNodePath(render2d, 'line', 2, Vec4(.3, .3, .3, 0))
line.drawLines([[(-.76, 0, 1), (-.76, 0, -1)]])
line.create()


def react(input):

    output.append(input)
    print output


def clear():
    gU.enterText('')


gU = DirectEntry(text="",
                 scale=.05,
Exemplo n.º 18
0
class Ball:

    NAME_DEFAULT = "UNNAMED"
    POS_DEFAULT = (0, 0, 5)
    SCALE_DEFAULT = (1, 1, 1)
    HPR_DEFAULT = (0, 0, 0)
    MODEL_EGG_DEFAULT = "../egg/paahahmo.egg"
    JUMP_SOUND_DEFAULT = "../media/jump_sound.wav"
    BOUNCE_SOUND_DEFAULT = "../media/bounce_sound.wav"

    BALL_BODY_MASS_WEIGHT = 1000
    BALL_BODY_MASS_RADIUS = 1
    FORCE = 90000
    TORQUE = 3000

    MOVEMENT_DEBUG = 0
    JUMP_DEBUG = 0
    STATIC_JUMP = 0
    STATIC_JUMP_FORCE = 2800000
    JUMP_FORCE = 120000
    MAX_JUMP_REACH_TIME = 0.7
    COLLISION_THRESHOLD_TIME = 0.33
    MAX_MOVEMENT_SPEED = 20.0

    def __init__(
        self,
        world,
        space,
        name=NAME_DEFAULT,
        modelEgg=MODEL_EGG_DEFAULT,
        pos=POS_DEFAULT,
        scale=SCALE_DEFAULT,
        hpr=HPR_DEFAULT,
    ):
        self.limitedYMovement = False
        self.limitedYCoords = [-1, -1]
        self.limitedZMovement = False
        self.limitedZCoords = [-1, -1]
        self.name = name
        self.pos = pos
        self.hpr = hpr
        self.scale = scale
        self.world = world
        self.space = space
        self.jumping = False
        self.jumpStarted = 0.0
        self.jumpLastUpdate = 0.0
        self.lastCollisionTime = 0.0
        self.lastCollisionIsGround = True
        self.lastGroundCollisionBodyPos = None
        self.jumpSound = loader.loadSfx(self.JUMP_SOUND_DEFAULT)
        self.bounceSound = loader.loadSfx(self.BOUNCE_SOUND_DEFAULT)

        if Ball.MOVEMENT_DEBUG:
            self.lastDrawTime = 0.0
            self.lastDrawTime2 = 0.0
            self.lines = LineNodePath(parent=render,
                                      thickness=3.0,
                                      colorVec=Vec4(1, 0, 0, 1))
            self.lines2 = LineNodePath(parent=render,
                                       thickness=3.0,
                                       colorVec=Vec4(0, 0, 1, 1))
            self.lines3 = LineNodePath(parent=render,
                                       thickness=3.0,
                                       colorVec=Vec4(0, 1, 0, 1))
        if Ball.JUMP_DEBUG:
            self.lastTakeoffTime = 0.0
        self.moveLeft = False
        self.moveRight = False
        self.modelNode = self.createModelNode(self.pos, self.hpr, self.scale,
                                              modelEgg)
        self.ballBody = self.createBallBody(self.modelNode, self.world)
        self.ballGeom = self.createBallGeom(self.modelNode, self.ballBody,
                                            self.space)
        self.modelNode.reparentTo(render)

    def createModelNode(self, pos, hpr, scale, modelEgg):
        modelNode = loader.loadModel(modelEgg)
        modelNode.setPos(pos)
        modelNode.setHpr(hpr)
        modelNode.setScale(scale)
        return modelNode

    def createBallBody(self, modelNode, world):
        ballBody = OdeBody(world)
        M = OdeMass()
        M.setSphere(Ball.BALL_BODY_MASS_WEIGHT, Ball.BALL_BODY_MASS_RADIUS)
        ballBody.setMass(M)
        ballBody.setPosition(modelNode.getPos(render))
        ballBody.setQuaternion(modelNode.getQuat(render))
        return ballBody

    def createBallGeom(self, modelNode, ballBody, space):
        ballGeom = OdeSphereGeom(space, 1)
        ballGeom.setCollideBits(BitMask32(0x2))
        ballGeom.setCategoryBits(BitMask32(0x1))
        ballGeom.setBody(ballBody)
        space.setSurfaceType(ballGeom, SurfaceType.BALL)
        return ballGeom

    def getDefaultGravityVec3(self):
        out = VBase3()
        out.setX(0.0)
        out.setY(0.0)
        out.setZ(-9.8)
        return out

    def angleVec3(self, v1, v2):
        return math.acos(
            self.dotProductVec3(v1, v2) / (v1.length() * v2.length()))

    def dotProductVec3(self, v1, v2):
        return v1.getX() * v2.getX() + v1.getY() * v2.getY() + v1.getZ(
        ) * v2.getZ()

    def moveBall(self, normalGravity, func):
        g = self.world.getGravity()
        angle = self.angleVec3(g, self.getDefaultGravityVec3())
        if not (angle > math.pi / 3.99 and angle < math.pi / 1.99):
            if normalGravity:
                func()
        else:
            if not normalGravity:
                func()
        return

    def arrowRightDown(self):
        self.moveBall(1, self.startMoveRight)

    def arrowRightUp(self):
        self.moveBall(1, self.stopMoveRight)

    def arrowLeftDown(self):
        self.moveBall(1, self.startMoveLeft)

    def arrowLeftUp(self):
        self.moveBall(1, self.stopMoveLeft)

    def arrowUpDown(self):
        self.moveBall(0, self.startMoveRight)

    def arrowUpUp(self):
        self.moveBall(0, self.stopMoveRight)

    def arrowDownDown(self):
        self.moveBall(0, self.startMoveLeft)

    def arrowDownUp(self):
        self.moveBall(0, self.stopMoveLeft)

    def startMoveLeft(self):
        self.moveLeft = True

    def stopMoveLeft(self):
        self.moveLeft = False

    def isMovingLeft(self):
        return self.moveLeft

    def startMoveRight(self):
        self.moveRight = True

    def stopMoveRight(self):
        self.moveRight = False

    def isMovingRight(self):
        return self.moveRight

    def perpendicularUnitVec3WithFixedX(self, v):
        out = VBase3()
        a = 1.0
        out.setX(0.0)
        if v.getY() != 0.0:
            out.setY(-(v.getZ() * a) / v.getY())
            out.setZ(a)
        else:
            out.setY(a)
            out.setZ(0.0)
        out /= out.length()
        return out

    def playSound(self, name, override):
        if name == "jump":
            if self.jumpSound != None:
                if override == False and self.jumpSound.status() != 1:
                    self.jumpSound.stop()
                self.jumpSound.play()
        if name == "bounce":
            if self.bounceSound != None:
                if override == False and self.bounceSound.status() != 1:
                    self.bounceSound.stop()
                self.bounceSound.play()
        return

    def jumpOn(self):
        if self.isColliding():
            self.playSound("jump", False)
        if self.isColliding() == True and self.lastCollisionIsGround:
            self.jumping = True
            self.jumpStarted = globalClock.getLongTime()
        return

    def jumpOff(self):
        self.jumping = False
        self.jumpStarted = 0.0
        self.jumpLastUpdate = 0.0
        return

    def isColliding(self):
        if self.lastCollisionTime == 0.0:
            return False

        now = globalClock.getLongTime()
        interval = now - self.lastCollisionTime

        if interval < Ball.COLLISION_THRESHOLD_TIME:
            if Ball.JUMP_DEBUG:
                self.lastTakeoffTime = 0.0
            return True
        else:
            if Ball.JUMP_DEBUG:
                # Draw debug info
                if self.lastTakeoffTime == 0.0:
                    self.lastTakeoffTime = now
                    messenger.send('updateHUD', [", Ball state: AIR"])
            return False

    def isGroundCollision(self, bodyPos, colPos):
        # Tolerance should probably be some fraction of the radius
        g = self.world.getGravity()
        g /= g.length()
        # g *= Ball.RADIUS
        bodyPos[0] = bodyPos[0] + g.getX()
        bodyPos[1] = bodyPos[1] + g.getY()
        bodyPos[2] = bodyPos[2] + g.getZ()
        return self.areCloseEnough(bodyPos, colPos)

    def areCloseEnough(self, pos1, pos2):
        tolerance = 0.5
        dy = pos1[1] - pos2[1]
        # >= is important
        if (dy >= 0.0 and dy < tolerance) or (dy < 0.0 and dy > -tolerance):
            dz = pos1[2] - pos2[2]
            # >= is important
            if (dz >= 0.0 and dz < tolerance) or (dz < 0.0
                                                  and dz > -tolerance):
                return True
        return False

    def refreshCollisionTime(self, collisionEntry):
        body = self.ballBody
        pos = body.getPosition()
        now = globalClock.getLongTime()

        if self.isColliding() == False:
            self.playSound("bounce", False)
        '''
		Only "sample" collisions occasionally, should be enough for jumping.
		This also effects the collision threshold time, which should be somewhat
		larger (maybe twice?) than this value for jumping to work properly
		'''

        if now - self.lastCollisionTime < 0.15:
            return

        self.lastCollisionTime = now

        if Ball.JUMP_DEBUG:
            previous = self.lastCollisionIsGround

        self.lastCollisionIsGround = False
        n = collisionEntry.getNumContacts()

        for i in range(n):
            p = collisionEntry.getContactPoint(i)
            if Ball.MOVEMENT_DEBUG and now - self.lastDrawTime > 0.1:
                self.lines2.reset()
                x = p.getX(
                ) + 1.2  # This will bring the line in front of the ball
                y = p.getY()
                z = p.getZ()
                self.lines2.drawLines([
                    ((x, y, z), (x, y - 1.0, z + 2.0))
                ])  # "marker" will be a line upwards tilting to the left
                self.lines2.create()
                self.lastDrawTime = now
            if self.isGroundCollision(pos, p):
                self.lastCollisionIsGround = True
                self.lastGroundCollisionBodyPos = pos
                break

        if not self.lastCollisionIsGround and self.lastGroundCollisionBodyPos != None:
            if self.areCloseEnough(pos, self.lastGroundCollisionBodyPos):
                self.lastCollisionIsGround = True
                # Position should not be updated, since this was not technically a ground collision
                # as we normally judge them

        if Ball.JUMP_DEBUG:
            # Draw debug info
            if previous != self.lastCollisionIsGround or self.lastTakeoffTime != 0.0:
                self.lastTakeoffTime = 0.0
                if self.lastCollisionIsGround:
                    messenger.send('updateHUD', [", Ball state: GROUND"])
                else:
                    messenger.send('updateHUD', [", Ball state: ???"])

    def haveRoughlySameDirection(self, ivec, ivec2):
        if ivec.length() == 0 or ivec2.length() == 0:
            return False
        angle = self.angleVec3(ivec, ivec2)
        #print angle
        if (-math.pi / 8.0) < angle and angle < (math.pi / 8.0):
            return True
        return False

    def limitYMovement(self, ymin, ymax):
        if ymin >= ymax:
            return
        self.limitedYMovement = True
        self.limitedYCoords = [ymin, ymax]

    def limitZMovement(self, zmin, zmax):
        if zmin >= zmax:
            return
        self.limitedZMovement = True
        self.limitedZCoords = [zmin, zmax]

    def updateModelNode(self):
        ''' Update objects after one physics iteration '''
        now = globalClock.getLongTime()
        body = self.ballBody
        g = self.world.getGravity()

        if self.limitedYMovement:
            if body.getPosition().getY() > self.limitedYCoords[1]:
                self.ballBody.setLinearVel(Vec3(0, -10, 0))
            if body.getPosition().getY() < self.limitedYCoords[0]:
                self.ballBody.setLinearVel(Vec3(0, 10, 0))
        if self.limitedZMovement:
            if body.getPosition().getZ() > self.limitedZCoords[1]:
                messenger.send(EventType.RESTART)
                return
            if body.getPosition().getZ() < self.limitedZCoords[0]:
                messenger.send(EventType.RESTART)
                return

        if Ball.MOVEMENT_DEBUG and now - self.lastDrawTime2 > 0.2:
            v = body.getLinearVel()
            v2 = self.perpendicularUnitVec3WithFixedX(v)
            self.lines.reset()
            self.lines3.reset()
            x = body.getPosition().getX(
            ) + 1.2  # This will bring the line in front of the ball
            y = body.getPosition().getY()
            z = body.getPosition().getZ()
            self.lines.drawLines([((x, y, z), (x + v.getX(), y + v.getY(),
                                               z + v.getZ()))])
            self.lines3.drawLines([((x, y, z), (x + v2.getX(), y + v2.getY(),
                                                z + v2.getZ()))])
            self.lines.create()
            self.lines3.create()
            self.lastDrawTime2 = 0.0
        ''' Can move better when on (touching) something, moving in the air is harder '''
        divisor = 3.5
        if self.isColliding() and self.lastCollisionIsGround:
            divisor = 1.0

        if self.moveLeft or self.moveRight:
            factor = 1.0
            if self.moveLeft:
                factor = -1.0

            # Limit speed to some constant
            v3 = self.perpendicularUnitVec3WithFixedX(g)
            v3 *= factor * Ball.FORCE / divisor
            lv = self.ballBody.getLinearVel()
            lv.setX(0.0)
            lv.setZ(0.0)
            if self.haveRoughlySameDirection(
                    lv, v3) and abs(lv.length()) > self.MAX_MOVEMENT_SPEED:
                factor = 0.0

            v3 = self.perpendicularUnitVec3WithFixedX(g)
            v3 *= factor * Ball.FORCE / divisor

            self.ballBody.setForce(y=v3.getY(), x=v3.getX(), z=v3.getZ())
            v3 = self.perpendicularUnitVec3WithFixedX(g)
            v3 *= factor * Ball.TORQUE / divisor
            self.ballBody.setTorque(y=v3.getY(), x=v3.getX(), z=v3.getX())
        ''' This is still really crappy, will revise later '''
        if self.jumping == True:
            g = -g
            g /= g.length()
            if Ball.STATIC_JUMP:
                g *= Ball.STATIC_JUMP_FORCE
                self.ballBody.setForce(y=g.getY(), x=g.getX(), z=g.getZ())
                self.jumping = False
            else:
                elapsed = now - self.jumpStarted
                if elapsed > 0.0 and elapsed < Ball.MAX_JUMP_REACH_TIME:
                    g *= Ball.JUMP_FORCE
                    self.ballBody.setForce(y=g.getY(), x=g.getX(), z=g.getZ())
                elif elapsed > Ball.MAX_JUMP_REACH_TIME:
                    self.jumping = False

        # Keep the body in 2d position
        self.alignBodyTo2d()

        # Set the new position
        self.modelNode.setPos(render, self.ballBody.getPosition())
        self.modelNode.setQuat(render, Quat(self.ballBody.getQuaternion()))

    def alignBodyTo2d(self):
        body = self.ballBody

        # Constrain position of the body
        oldPos = body.getPosition()
        newPos = oldPos
        newPos[0] = 0
        newPos[1] = oldPos[1]
        newPos[2] = oldPos[2]

        # Constrain quaternion of the body
        oldQuat = body.getQuaternion()
        newQuat = oldQuat
        newQuat[0] = oldQuat[0]
        newQuat[1] = oldQuat[1]
        newQuat[2] = 0
        newQuat[3] = 0

        # Set new position and quaternion of the body
        body.setPosition(newPos)
        body.setQuaternion(Quat(newQuat))

    def getPosition(self):
        return self.ballBody.getPosition()

    def setPosition(self, pos):
        self.ballBody.setPosition(pos)

    def getBody(self):
        return self.ballBody

    def getModelNode(self):
        return self.modelNode

    def removeNode(self):
        self.modelNode.removeNode()
Exemplo n.º 19
0
PIVOThandler = LineNodePath(render, 'handler', 2, Vec4(1, 0, 1, 1))

arrowX1 = (lengthX, PY, PZ)
arrowX2 = (arrowXz2, arrowXx1, PZ)
arrowX3 = (arrowXz2, arrowXx2, PZ)

arrowY1 = (PX, lengthY, PZ)
arrowY2 = (arrowYx1, arrowYz2, PZ)
arrowY3 = (arrowYx2, arrowYz2, PZ)

arrowZ1 = (PX, PY, lengthZ)
arrowZ2 = (arrowZx1, PY, arrowZz2)
arrowZ3 = (arrowZx2, PY, arrowZz2)

PIVarX.drawLines([[(PX, PY, PZ), (lengthX, PY, PZ)], [arrowX1, arrowX2],
                  [arrowX1, arrowX3]])
PIVarY.drawLines([[(PX, PY, PZ), (PX, lengthY, PZ)], [arrowY1, arrowY2],
                  [arrowY1, arrowY3]])
PIVarZ.drawLines([[(PX, PY, PZ), (PX, PY, lengthZ)], [arrowZ1, arrowZ2],
                  [arrowZ1, arrowZ3]])

PIVOThandler.drawLines([[(PX, PY, PZ), (PX + 0.5, PY, PZ)],
                        [(PX + .5, PY, PZ), (PX, PY + .5, PZ)],
                        [(PX, PY + .5, PZ), (PX, PY, PZ)]])

PIVarX.create()
PIVarY.create()
PIVarZ.create()
PIVOThandler.create()
Exemplo n.º 20
0
X2 = -10
Y1 = 10
Y2 = -10

linesX = LineNodePath(render, 'quad', 2, Vec4(.3, .3, .3, .3))
linesXX = LineNodePath(render, 'quad', 1, Vec4(.3, .3, .3, .3))
axis = LineNodePath(render, 'axis', 4, Vec4(.2, .2, .2, .2))
quad = LineNodePath(render, 'quad', 4, Vec4(.2, .2, .2, .2))

x1 = (0, Y2, 0)
x2 = (0, Y1, 0)

x3 = (X2, 0, 0)
x4 = (X1, 0, 0)

axis.drawLines([[x1, x2], [x3, x4]])
axis.create()

q1 = (X1, Y1, 0)
q2 = (X1, Y2, 0)

q3 = (q2)
q4 = (X2, Y2, 0)

q5 = (q4)
q6 = (X2, Y1, 0)

q7 = (q6)
q8 = (X1, Y1, 0)

quad.drawLines([[q1, q2], [q3, q4], [q5, q6], [q7, q8]])
Exemplo n.º 21
0
class Planet(SphericalBody): 
    '''
    Planet contains units and structures
    '''

    def __init__(self, orbital_radius, orbital_angle, radius, parent_star, prev_planet=None, player=None):
        '''
        Constructor for class planet.
        @param position: Point3D, position in space
        @param radius: float, body radius
        @param player: Player, the owner of the planet
        @param parent_star: Star, the specific star the planet is orbiting around
        @param prev_planet: previous planet in the star system, if None then the planet is the first
        '''
        position = Point3(orbital_radius * math.cos(orbital_angle),
                          orbital_radius * math.sin(orbital_angle), 0)
        super(Planet, self).__init__(position, radius, False, player)
        self.orbital_velocity = 0
        self.max_orbital_velocity = 0
        self.orbital_radius = orbital_radius
        self.orbital_angle = orbital_angle
        self.parent_star = parent_star
        self.prev_planet = prev_planet
        self.next_planet = None
        self._orbiting_units = []
        self._surface_structures = []
        self.__initSceneGraph()
               
        '''For the Player'''
        self.task_structure_timer = None
        self.task_unit_timer = None
        '''For the AI'''
        self.task_structure_timers = []
        self.task_unit_timers = []
        
    def __initSceneGraph(self):

        #load various texture stages of the planet
        self.forge_tex = TextureStage('forge')
        self.forge_tex.setMode(TextureStage.MDecal)
        self.nexus_tex = TextureStage('nexus')
        self.nexus_tex.setMode(TextureStage.MDecal)
        self.extractor_phylon_ge_tex = TextureStage('extractor_phylon_ge')
        self.extractor_phylon_ge_tex.setMode(TextureStage.MDecal)
        
        # Parent node for relative position (no scaling)
        self.point_path = self.parent_star.point_path.attachNewNode("planet_node")
        self.point_path.setPos(self.position)
        
        #Models & textures
        self.model_path = loader.loadModel("models/planets/planet_sphere")
        self.model_path.setTexture(SphericalBody.dead_planet_tex, 1)
        self.model_path.reparentTo(self.point_path)
        self.model_path.setScale(self.radius)
        self.model_path.setPythonTag('pyPlanet', self);
        
        cnode = CollisionNode("coll_sphere_node")
        cnode.setTag('planet', str(id(self)))
        #We use no displacement (0,0,0) and no scaling factor (1)
        cnode.addSolid(CollisionSphere(0,0,0,1))
        cnode.setIntoCollideMask(BitMask32.bit(1))
        # Reparenting the collision sphere so that it 
        # matches the planet perfectly.
        self.cnode_path = self.model_path.attachNewNode(cnode)
        
        self.lines = LineNodePath(parent = self.parent_star.point_path, thickness = 4.0, colorVec = Vec4(1.0, 1.0, 1.0, 0.2))
        self.quad_path = None
        
    def setTexture(self, structureType):
        '''
        Used whenever a structure is built on the planet
        @ StructureType is a string specifying the type of the structure
        '''
        if(structureType == "forge"):
            #SphericalBody.planet_forge_tex.setWrapU(Texture.WMInvalid)
            #SphericalBody.planet_forge_tex.setWrapV(Texture.WMInvalid)
            self.model_path.setTexture(self.forge_tex, SphericalBody.planet_forge_tex)
            #self.model_path.getTexture().setWrapU(Texture.WMClamp)
            #self.model_path.getTexture().setWrapV(Texture.WMClamp)
            self.model_path.setTexOffset(self.forge_tex, 0, 0)
            #self.model_path.setTexScale(self.forge_tex, -4, -2)
        elif(structureType == "nexus"):
            self.model_path.setTexture(self.nexus_tex, SphericalBody.planet_nexus_tex)
            self.model_path.setTexOffset(self.nexus_tex, 0, 10)
        elif(structureType == "extractor"):
            self.model_path.setTexture(self.extractor_phylon_ge_tex, SphericalBody.planet_extractor_tex)
            self.model_path.setTexOffset(self.extractor_phylon_ge_tex, 0, 20)
        elif(structureType == "phylon"):
            self.model_path.setTexture(self.extractor_phylon_ge_tex, SphericalBody.planet_phylon_tex)
            self.model_path.setTexOffset(self.extractor_phylon_ge_tex, 0, 20)
        elif(structureType == "generatorCore"):
            self.model_path.setTexture(self.extractor_phylon_ge_tex, SphericalBody.planet_generatorCore_tex)
            self.model_path.setTexOffset(self.extractor_phylon_ge_tex, 0, 20)
    
    def activateHighlight(self, thin):
        if thin:
            flare_tex = base.loader.loadTexture("models/billboards/thin_ring.png")
        else:
            flare_tex = base.loader.loadTexture("models/billboards/ring.png")
        cm = CardMaker('quad')
        cm.setFrameFullscreenQuad() # so that the center acts as the origin (from -1 to 1)
        self.quad_path = self.point_path.attachNewNode(cm.generate())        
        self.quad_path.setTransparency(TransparencyAttrib.MAlpha)
        self.quad_path.setTexture(flare_tex)
        if thin:
            self.quad_path.setColor(Vec4(1,1,1, 1))
        else:
            self.quad_path.setColor(Vec4(0.2, 0.3, 1.0, 1))
        self.quad_path.setScale(5)
        self.quad_path.setPos(Vec3(0,0,0))
        self.quad_path.setBillboardPointEye()
    
    def deactivateHighlight(self):
        if self.quad_path:
            self.quad_path.detachNode()
            self.quad_path = None
    
    def select(self, player):
        '''
        This method observes the events on the planet and calls the related methods
        and notifies the corresponding objects based on the state of the planet
        @param player, the player who has selected
        '''
        player.selected_star = None
        
        if(not self.activated and player.selected_planet == self):
            if((self.prev_planet == None or self.prev_planet.activated) and \
                    self.parent_star.activated and self.parent_star.player == player):
                self.activatePlanet(player)
        else:
#            from gameEngine.gameEngine import all_stars 
#            for star in all_stars:
#                star.deactivateHighlight()
            from gameEngine.gameEngine import all_planets
            for planet in all_planets:
                if(self != planet or self.next_planet != planet or self.prev_planet != planet):
                    planet.deactivateHighlight()
            if self.next_planet != None: self.next_planet.activateHighlight(True) 
            if self.prev_planet != None: self.prev_planet.activateHighlight(True)
            self.activateHighlight(False)
        
        player.selected_planet = self
        
        from gameEngine.gameEngine import updateGUI
        updateGUI.refreshUnitsAndConstructions(self)
        
    def selectRight(self, player):
        '''
        This method observes the events on the planet and calls the related methods
        and notifies the corresponding objects based on the state of the planet
        @param player, the player who has selected with right mouse click
        '''
        move_occured = False
        for selected_unit in player.selected_units:
            if(selected_unit != None and selected_unit.player == player):
                '''movement is inside the solar system'''
                if(selected_unit.host_planet.parent_star == self.parent_star):
                    if(selected_unit.host_planet == self.prev_planet):
                        selected_unit.moveUnitNext()
                        move_occured = True
                    if(selected_unit.host_planet == self.next_planet):
                        selected_unit.moveUnitPrev()   
                        move_occured = True 
                else:
                    '''movement is between solar systems in deep space'''
                    if(self.next_planet == None and selected_unit.host_planet.next_planet == None):
                        selected_unit.moveDeepSpace(self)
                        move_occured = True

        if(len(player.selected_units)!=0 and move_occured):
            if(player.selected_units[0] != None and player.selected_units[0].move_unit != None):
                base.sfxManagerList[0].update()
                player.selected_units[0].move_unit.play()
            
    def activatePlanet(self, player):
        '''
        Activates a constructed dead planet object, starting the orbital movement with the assigned value while
        the Game Engine calls the graphic engine to display the corresponding animation.
        @param player: Player, the player who controls the planet
        @precondition: MIN_PLANET_VELOCITY < orbital_velocity < MAX_PLANET_VELOCITY
        '''
        self.activated = True
        player.planets.append(self)
        self.player = player
        
        
        planet_created_sound = base.loader.loadSfx("sound/effects/planet/planetCreation.wav")
        planet_created_sound.setVolume(0.3)
        planet_created_sound.play()
#        base.sfxManagerList[0].update()
#        SphericalBody.planet_created_sound.play()
        
        self.radius = MAX_PLANET_RADIUS
        self.model_path.setScale(self.radius)
        
        '''TODO : display planet creation animation '''
        
        #rand = random.randrange(1,8,1)
        self.model_path.setTexture(SphericalBody.planet_activated_tex, 1)
        self.startSpin()
        
        # We want to avoid adding this task when the 'collapseOrbit' is already running
        if self.parent_star.lifetime != 0:
            taskMgr.add(self._accelerateOrbit, 'accelerateOrbit')
        
        self.orbit_path = shapes.makeArc(self.player.color, 360, int(self.orbital_radius))
        self.orbit_path.reparentTo(self.parent_star.point_path)
        self.orbit_path.setScale(self.orbital_radius)
        
        from gameModel.ai import AI
        if(type(self.player) != AI):
            from gameEngine.gameEngine import updateGUI
            updateGUI.refreshUnitsAndConstructions(self)
    
    def startSpin(self):
        self.day_period = self.model_path.hprInterval(PLANET_SPIN_VELOCITY, Vec3(360, 0, 0))
        self.day_period.loop()
    
    def startCollapse(self):
        try:
            if self.orbit_task:
                taskMgr.remove(self.orbit_task)
        except AttributeError:
            pass # no orbit on this planet (has not been activated)
        
        taskMgr.add(self._collapseOrbit, 'collapseOrbit')
#        taskMgr.setupTaskChain('collapseChain')
#        taskMgr.add(self._collapseOrbit, 'collapseOrbit')#, taskChain='collapseChain')
#        taskMgr.add(self._consume, 'consumePlanet', taskChain='collapseChain')
#        self.orbitTask = None
    
    def _consume(self):
        self._consumeUnits()
        self._consumeStructures()
        self.removeFromGame()
        
    def _accelerateOrbit(self, task):
        self.orbital_angle = self.orbital_angle + self.orbital_velocity
        self.orbital_angle = math.fmod(self.orbital_angle, 2.0*math.pi);
        self.point_path.setPos(self.orbital_radius * math.cos(self.orbital_angle),
                               self.orbital_radius * math.sin(self.orbital_angle), 0)
        self.position = self.point_path.getPos()
        self.orbital_velocity = self.orbital_velocity + 0.0001
        if self.orbital_velocity > self.max_orbital_velocity:
            self.orbit_task = taskMgr.add(self._stepOrbit, 'stepOrbit')
            return task.done
        else:
            return task.cont
    
    def _stepOrbit(self, task):
        self.orbital_angle = self.orbital_angle + self.orbital_velocity
        self.orbital_angle = math.fmod(self.orbital_angle, 2.0*math.pi)
        self.point_path.setPos(self.orbital_radius * math.cos(self.orbital_angle),
                               self.orbital_radius * math.sin(self.orbital_angle), 0)
        self.position = self.point_path.getPos()
        return task.cont
    
    def _collapseOrbit(self, task):
        self.orbital_radius = self.orbital_radius - 0.23
        self.orbital_angle = self.orbital_angle + self.orbital_velocity
        self.orbital_angle = math.fmod(self.orbital_angle, 2.0*math.pi)
        self.point_path.setPos(self.orbital_radius * math.cos(self.orbital_angle),
                               self.orbital_radius * math.sin(self.orbital_angle), 0)
        self.position = self.point_path.getPos()
#        if self.orbital_velocity < 0.01:
        if self.orbital_radius != 0:
            self.orbital_velocity = self.orbital_velocity + 0.01/(self.orbital_radius**2)
        try:
            self.orbit_path.setScale(self.orbital_radius)
        except AttributeError:
            pass # no orbit on this planet (has not been activated)
        
        if self.orbital_radius <= 0:
            self._consume()
            return task.done
        else:
            return task.cont
        
    
    def drawLines(self): 
        # put some lighting on the line
        # for some reason the ambient and directional light in the environment drain out
        # all other colors in the scene
        # this is a temporary solution just so we can view the lines... the light can be removed and
        #a glow effect will be added later
#        alight = AmbientLight('alight')
#        alnp = render.attachNewNode(alight)
#        alight.setColor(Vec4(0.2, 0.2, 0.2, 1))
#        render.setLight(alnp)
        self.lines.reset()
        self.lines.drawLines([((0,0, 0),
                               (self.point_path.getX(), self.point_path.getY(), 0))])
        self.lines.create()
    
    def drawConnections(self, task):
#        cur_pos = self.point_path.getPos()
#        paired_pos = pairedPlanetDraw.point_path.getPos()
#        paired_pos = self.point_path.getRelativePoint(pairedPlanetDraw.point_path, pairedPlanetDraw.point_path.getPos())
#        print pairedPlanetDraw.point_path.getX(), pairedPlanetDraw.point_path.getY(), pairedPlanetDraw.point_path.getZ()
        self.connections.reset()
        if(self.next_planet):
            point_list = []
            point_list.append((self.point_path.getPos(), self.next_planet.point_path.getPos()))
            self.connections.drawLines(point_list)
            self.connections.create()
        return task.cont
        
    def changePlayer(self, player):
        '''
        Change the control of the planet from the self.player to the parameter player
        @param player: Player, the player who has captured the planet by swarms
        @precondition: the player must have used the capture ability of a swarm type unit on the planet
        '''
        '''TODO: Use makeArc to change the color of the orbit'''
        
        ''' stop any constructions on the planet '''
        if(self.task_structure_timer != None):
            taskMgr.remove(self.task_structure_timer)
            self.task_structure_timer = None
        if(self.task_unit_timer != None):
            taskMgr.remove(self.task_unit_timer)
            self.task_unit_timer = None
        if(self.task_structure_timers != None):
            taskMgr.remove(self.task_structure_timers)
            self.task_structure_timers = None
        if(self.task_unit_timers != None):
            taskMgr.remove(self.task_unit_timers)
            self.task_unit_timers = None
        ''' remove previous player's control from the planet '''
        for structure in self.structures():
            self.player.structures.remove(structure)
        ''' set control of the planet to the new player '''
        for structure in self.structures():
            player.structures.append(structure)
        ''' update the construction panel for the human player'''
        from gameModel.ai import AI
        ''' if human player is the previous owner '''
        if(type(self.player) != AI):
            from gameEngine.gameEngine import updateGUI
            updateGUI.refreshUnitsAndConstructions(self)
        ''' give total control to new player '''
        self.player = player
        ''' if human player is the new owner '''
        if(type(player) != AI):
            from gameEngine.gameEngine import updateGUI
            updateGUI.refreshUnitsAndConstructions(self)
        
    def addOrbitingUnit(self, unit):
        ''' 
        Add a unit to the hosted units by the planet
        @param unit: Orbiting unit object
        '''
        self._orbiting_units.append(unit)
    
    def addOrbitingUnits(self, units):
        '''
        Add a list of units to be hosted by the planet
        @param units: iterable of units
        '''
        self._orbiting_units.extend(units)
    
    def removeOrbitingUnit(self, unit):
        ''' 
        Remove the hosted unit from the planet
        @param unit: Orbiting unit object
        '''
        self._orbiting_units.remove(unit)
    
    def removeOrbitingUnits(self, units):
        ''' 
        Remove many hosted units from the planet
        @param units: List of unit objects
        '''
        self._orbiting_units[:] = [u for u in self._orbiting_units if u not in units]
        
    def units(self):
        '''
        Generator that iterates over the hosted units.
        '''
        for unit in self._orbiting_units:
            yield unit
            
    def unitsOfPlayer(self, player):
        '''
        Generator that iterates over the hosted units belonging to the player.
        @param player, the owner of the units 
        '''
        for unit in self._orbiting_units:
            if unit.player == player:
                yield unit
    
    def unitsOfEnemy(self, player):
        '''
        Generator that iterates over the hosted units not belonging to the player.
        @param player, the owner of the units 
        '''
        for unit in self._orbiting_units:
            if unit.player != player:
                yield unit
    
    def unitsOfEnemyLowestEnergy(self, player):
        '''
        Generator that iterates over the hosted units not belonging to the player
        sorted by lowest energy.
        @param player, the owner of the units 
        '''
        energyList = sorted(self._orbiting_units, key=lambda unit: unit.energy)
        for unit in energyList:
            if unit.player != player:
                yield unit
                
    def getNumberOfUnits(self):
        '''
        Returns the number of hosted units from the planet
        '''
        return len(self._orbiting_units)
    
    def getNumberOfUnitsOfPlayer(self, player):
        '''
        Returns the number of hosted units from the planet that belongs to the player
        @param player, the owner of the units
        '''
        num = 0
        for unit in self._orbiting_units:
            if(unit.player == player):
                num = num + 1
        return num
    
    def _task_unit_timers(self):
        '''
        Generator that iterates over the hosted units construction tasks.
        '''
        for task_unit in self.task_unit_timers:
            yield task_unit
            
    def _task_structure_timers(self):
        '''
        Generator that iterates over the surface structure construction tasks.
        '''
        for task_structure in self.task_structure_timers:
            yield task_structure
            
    def _consumeUnits(self):
        if(self.task_unit_timer!=None):
            taskMgr.remove(self.task_unit_timer)
            self.task_unit_timer = None
            
        for task in self.task_unit_timers:
            taskMgr.remove(task)
        del self.task_unit_timers[:]

        from gameModel.ai import AI        
        for unit in self._orbiting_units:
            unit.player.units.remove(unit)
            if(type(unit.player) != AI):
                try:
                    unit.player.selected_units.remove(unit)
                    print "selected unit"
                except ValueError:
                    pass
            unit.removeFromGame()    
        del self._orbiting_units[:]
        
    def _consumeStructures(self):
        if(self.task_structure_timer!=None):
            taskMgr.remove(self.task_structure_timer)
            self.task_structure_timer = None
        for task in self.task_structure_timers:
            taskMgr.remove(task)
        del self.task_structure_timers[:]

        for structure in self._surface_structures:
            self.player.structures.remove(structure)
        del self._surface_structures[:]
       
    def addSurfaceStructure(self, structure):
        ''' 
        Add a structure to the surface structures by the planet
        @param structure: Surface structure object
        '''
        if(len(self._surface_structures) < MAX_NUMBER_OF_STRUCTURE):
            self._surface_structures.append(structure)
    
    def addSurfaceStructures(self, structures):
        '''
        Add a list of structures to be hosted by the planet
        @param structures: iterable of structure
        '''
        if(len(self._surface_structures) + len(structures) <= MAX_NUMBER_OF_STRUCTURE):
            self._surface_structures.extend(structures)
    
    def removeSurfaceStructure(self, structure):
        ''' 
        Remove the surface structure from the planet
        @param structure: Surface structure object
        '''
        self._surface_structures.remove(structure)
    
    def removeSurfaceStructures(self, structures):
        ''' 
        Remove many surface structures from the planet
        @param structures: List of structure objects
        '''
        self._surface_structures[:] = [s for s in self._surface_structures if s not in structures]
        
    def structures(self):
        '''
        Generator that iterates over the surface structures.
        '''
        for structure in self._surface_structures:
            yield structure
            
    def getNumberOfStructures(self):
        '''
        Returns the number of surface structures from the planet
        '''
        return len(self._surface_structures)
        
    def hasStructure(self, structure):
        '''
        Returns true if a type of the structure already exists on the planet
        @structure: String, the desired structure type
        '''
        from structures import Forge, Nexus, Extractor, Phylon, GeneratorCore,\
            PlanetaryDefenseI, PlanetaryDefenseII, PlanetaryDefenseIII, PlanetaryDefenseIV
        for surface_structure in self._surface_structures:
            if(structure == "forge" and type(surface_structure) == Forge):
                return True
            elif(structure == "nexus" and type(surface_structure) == Nexus):
                return True
            elif(structure == "extractor" and type(surface_structure) == Extractor):
                return True
            elif(structure == "phylon" and type(surface_structure) == Phylon):
                return True
            elif(structure == "generatorCore" and type(surface_structure) == GeneratorCore):
                return True
            elif(structure == "pd1" and type(surface_structure) == PlanetaryDefenseI):
                return True
            elif(structure == "pd2" and type(surface_structure) == PlanetaryDefenseII):
                return True
            elif(structure == "pd3" and type(surface_structure) == PlanetaryDefenseIII):
                return True
            elif(structure == "pd4" and type(surface_structure) == PlanetaryDefenseIV):
                return True
        return False
    
    def removeFromGame(self):
        if(self.next_planet != None):
            self.next_planet.prev_planet = None
        self.point_path.removeNode()
        from player import Player
        if type(self.player) == Player and self.player.selected_planet == self:
            self.player.selected_planet = None
        if(self.player != None):
            self.player.planets.remove(self)
        self.parent_star.removePlanet(self)