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()
class NodeConnector: def __init__(self, socketA, socketB): self.connectorID = uuid4() self.socketA = socketA self.socketB = socketB self.line = LineNodePath(ShowBaseGlobal.aspect2d, thickness=2, colorVec=(0.8, 0.8, 0.8, 1)) self.draw() def update(self): self.line.reset() self.draw() def draw(self): self.line.moveTo(self.socketA.plug.getPos(ShowBaseGlobal.aspect2d)) self.line.drawTo(self.socketB.plug.getPos(ShowBaseGlobal.aspect2d)) self.line.create() def has(self, socket): """Returns True if one of the sockets this connector connects is the given socket""" return socket == self.socketA or socket == self.socketB def connects(self, a, b): """Returns True if this connector connects socket a and b""" return (a == self.socketA or a == self.socketB) and (b == self.socketA or b == self.socketB) def disconnect(self): self.line.reset() self.socketA.setConnected(False) self.socketB.setConnected(False)
def P3DCreateAxes(length=0.5, arrowAngle=25, arrowLength=0.05): nodePath = LineNodePath() nodePath.reparentTo(render2d) #~ nodePath.drawArrow2d(Vec3(0, 0, 0), Vec3(0.5, 0, 0.5), 30, 0.1) nodePath.drawArrow2d(Vec3(0, 0, 0), Vec3(0., 0, length), arrowAngle, arrowLength) nodePath.create() return nodePath
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
def draw_lines(lines: LineNodePath, *paths: dict, origin=None, relative=True): if origin is None: origin = lines.getCurrentPosition() lines.reset() for path in paths: if 'color' in path: lines.setColor(*path['color']) points = path['points'] lines.moveTo(*origin) for point in points: if relative: point += origin lines.drawTo(*point) lines.create()
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
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()
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
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
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
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()
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()
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
def __init__(self): ShowBase.__init__(self) wp = core.WindowProperties() wp.setTitle("Dorfdelf") self.win.requestProperties(wp) self.render.setAntialias(core.AntialiasAttrib.MAuto) self.setBackgroundColor(0.5, 0.5, 0.5) self.disableMouse() self.enableParticles() font = self.loader.loadFont('media/calibri.ttf') font.setPixelsPerUnit(120) font.setPageSize(512, 1024) loading = OnscreenText(text='Loading...', scale=0.2, pos=(0.0, 0.0), fg=(1, 1, 1, 1), shadow=(0.3, 0.3, 0.3, 1.0), align=core.TextNode.ACenter, mayChange=True, font=font, parent=self.aspect2d) self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() loading.setText('Generating world') self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() self.world = world.World(128, 128, 100) self.world.generate() loading.setText('Creating world geometry') self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() self.world_geometry = geometry.WorldGeometry(self.world) self.camLens.setFocalLength(1) self.camera.setPos(0, 0, 100) self.camera.lookAt(self.world.midpoint.x, self.world.midpoint.y, 100) self.cam.setPos(0, 0, 0) self.cam.setHpr(0, -45, 0) self.cc = camera.CameraController(self.world.size, self.mouseWatcherNode, self.camera, self.cam) self.gui = gui.GUI(self.pixel2d, font) self.world_geometry.node.setPos(0, 0, 0) self.world_geometry.node.reparentTo(self.render) self.explore_mode = True self.current_slice = int(self.world.midpoint.z) self.accept_keyboard() self.accept('mouse1', self.toggle_block) self.accept('console-command', self.console_command) self.designation = designation.Designation() self.dorfs = [] self.tool = lambda w, x, y, z: None self.toolargs = () self.tools = { 'bomb': tools.bomb, 'block': tools.block, 'd': self.designation.add } self.console = console.Console(self) self.picker = block_picker.BlockPicker(self.world, self) self.zmap = zmap.ZMap(self.world, self) self.change_slice(0) arrow = LineNodePath() arrow.reparentTo(self.render) arrow.drawArrow2d(Vec3(-5, -5, self.world.midpoint.z), Vec3(15, -5, self.world.midpoint.z), 30, 3) arrow.create() loading.hide()
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 Fisherman(Toon.Toon): numFishTypes = 3 def __init__(self, id, toNpcId=20001, fAutonomous=1): # Default NPC ID is Flippy Toon.Toon.__init__(self) self.id = id self.fAutonomous = fAutonomous npcInfo = NPCToons.NPCToonDict[toNpcId] dnaList = npcInfo[2] gender = npcInfo[3] dna = ToonDNA.ToonDNA() dna.newToonFromProperties(*dnaList) self.setDNA(dna) self.reparentTo(render) self.angleNP = self.find('**/actorGeom') # Create pole self.pole = Actor.Actor() self.pole.loadModel('phase_4/models/props/fishing-pole-mod') self.pole.loadAnims({'cast': 'phase_4/models/props/fishing-pole-chan'}) # Get the top of the pole. self.ptop = self.pole.find('**/joint_attachBill') self.pole.pose('cast', 0) # Prepare Pole self.poleNode = [] self.holdPole() self.createCastTrack() self.castIval = None # Prepare actor self.setupNeutralBlend() self.targetInterval = None # Start automatic casting or create cast button if self.fAutonomous: self.castButton = None self.targetButton = None self.startCasting() else: # Starts casting mode when mouse enters button region self.castButton = DirectButton(text='CAST', relief=None, scale=0.1, pos=(0, 0, -0.2)) self.castButton.bind(DGG.ENTER, self.showCancelFrame) # A big screen encompassing frame to catch the button releases self.cancelFrame = DirectFrame(parent=self.castButton, frameSize=(-1, 1, -1, 1), relief=None, state='normal') # Make sure this is on top of all the other widgets self.cancelFrame.setBin('gui-popup', 0) self.cancelFrame.bind(DGG.B1PRESS, self.startAdjustingCastTask) self.cancelFrame.bind(DGG.B1RELEASE, self.finishCast) self.cancelFrame.hide() # Create bob self.bob = loader.loadModel('phase_4/models/props/fishing_bob') self.bobSpot = Point3(0) # Parameters to control bob motion self.vZeroMax = 30.0 self.angleMax = 30.0 # Ripple effect self.ripples = Ripples.Ripples(self.angleNP) self.ripples.hide() # Target self.buttonFrame = DirectFrame() self.target = base.distributedFishingTarget.fishingTargetNode self.fishPivot = self.attachNewNode('fishPivot') self.fish = loader.loadModel('models/misc/smiley') self.fish.reparentTo(self.fishPivot) self.fish.setScale(0.3, 1, 0.3) self.wiggleIval = None self.circleIval = None self.initFish() self.targetButton = DirectButton(parent=self.buttonFrame, text='MOVE', relief=DGG.RAISED, scale=0.1, pos=(0, 0, -0.9), command=self.moveTarget) self.targetTypeButton = DirectCheckButton(parent=self.buttonFrame, text='MOVING', relief=DGG.RAISED, scale=0.085, pos=(0.4, 0, -0.895), command=self.setfMove) self.fMovingTarget = 0 self.targetModeButton = DirectCheckButton( parent=self.buttonFrame, text='dTASK', relief=DGG.RAISED, scale=0.085, pos=(0.8, 0, -0.895), command=self.setfTargetMode) self.fTargetMode = 0 # Vector line self.line = LineNodePath(render2d) self.line.setColor(VBase4(1, 0, 0, 1)) self.line.moveTo(0, 0, 0) self.line.drawTo(1, 0, 0) self.line.create() self.moveTarget() def showCancelFrame(self, event): # Also display cancel frame to catch clicks outside of the popup self.cancelFrame.show() def startAdjustingCastTask(self, event): # Start task to adjust power of cast self.getMouse() self.initMouseX = self.mouseX self.initMouseY = self.mouseY self.initMouseX = 0 self.initMouseY = -0.2 self.line.lineSegs.setVertex(0, self.initMouseX, 0, self.initMouseY) self.angleNP.setH(0) self.__hideBob() taskMgr.remove('distCheck') # Position and scale cancel frame to fill entire window self.cancelFrame.setPos(render2d, 0, 0, 0) self.cancelFrame.setScale(render2d, 1, 1, 1) self.castTrack.finish() self.castTrack.setT(0) self.castTrack.start(startT=0, endT=0.4) self.castIval = Sequence( Wait(0.4), Func(taskMgr.add, self.adjustingCastTask, 'adjustCastTask')) self.castIval.start() def adjustingCastTask(self, state): self.getMouse() deltaX = self.mouseX - self.initMouseX deltaY = self.mouseY - self.initMouseY self.line.lineSegs.setVertex(1, self.mouseX, 0, self.mouseY) dist = math.sqrt(deltaX * deltaX + deltaY * deltaY) delta = (dist / 0.5) if deltaY > 0: delta *= -1 p = max(min(delta, 1.0), 0.0) self.power = p self.castTrack.setT(0.4 + p * 0.5) self.bobSpot = Point3(0, 6.5 + p * 25.0, -1.9) # Calc angle if deltaY == 0: angle = 0 else: angle = rad2Deg(math.atan(deltaX / deltaY)) self.angleNP.setH(-angle) return Task.cont def stopAdjustingCastTask(self): taskMgr.remove('adjustingTask') def setupNeutralBlend(self): self.stop() self.loop('neutral') self.enableBlend() self.pose('cast', 0) self.setControlEffect('neutral', 0.2) self.setControlEffect('cast', 0.8) def startCasting(self): if self.fAutonomous: self.castIval = Sequence( ActorInterval(self, 'cast'), Func(self.catchFish), Parallel( ActorInterval(self, 'neutral', loop=1, duration=100), Sequence( Wait(random.random() * 20.0), Func(self.startCasting), ))) else: self.castIval = Sequence( ActorInterval(self, 'cast'), Func(self.catchFish), ActorInterval(self, 'neutral', loop=1, duration=100)) self.castIval.play() def stopCasting(self): if self.castIval: self.castIval.pause() if self.targetInterval: self.stopTargetInterval() taskMgr.remove('distCheck') def catchFish(self): fishNum = int(round(random.random() * self.numFishTypes)) messenger.send('caughtFish', sentArgs=[self.id, fishNum]) def setupNeutralBlend(self): self.stop() self.loop('neutral') self.enableBlend() self.pose('cast', 0) self.setControlEffect('neutral', 0.2) self.setControlEffect('cast', 0.8) def getPole(self): toonTrack = Sequence( # Blend in neutral anim Func(self.setupNeutralBlend), # Pull out pole Func(self.holdPole), Parallel( ActorInterval(self, 'cast', playRate=0.5, duration=27. / 12.), ActorInterval(self.pole, 'cast', playRate=0.5, duration=27. / 12.), LerpScaleInterval(self.pole, duration=2.0, scale=1.0, startScale=0.01)), ) toonTrack.play() def putAwayPole(self): Sequence( Parallel( ActorInterval(self, 'cast', duration=1.0, startTime=1.0, endTime=0.0), ActorInterval(self.pole, 'cast', duration=1.0, startTime=1.0, endTime=0.0), LerpScaleInterval(self.pole, duration=0.5, scale=0.01, startScale=1.0)), Func(self.dropPole)).start() def holdPole(self): if self.poleNode != []: self.dropPole() # One node, instanced to each of the toon's three right hands, # will hold the pole. np = NodePath('pole-holder') hands = self.getRightHands() for h in hands: self.poleNode.append(np.instanceTo(h)) self.pole.reparentTo(self.poleNode[0]) def dropPole(self): self.__hideBob() #self.__hideLine() if self.pole != None: self.pole.clearMat() self.pole.detachNode() for pn in self.poleNode: pn.removeNode() self.poleNode = [] def createCastTrack(self): self.castTrack = Sequence( Parallel( ActorInterval(self, 'cast', duration=2.0, startTime=1.0), ActorInterval(self.pole, 'cast', duration=2.0, startTime=1.0), )) def cast(self): self.castTrack.start() def finishCast(self, event=None): #self.line.lineSegs.setVertex(1,self.initMouseX,0,self.initMouseY) self.cancelFrame.hide() if not self.castTrack: self.createCastTrack() self.castIval.finish() taskMgr.remove('adjustCastTask') taskMgr.remove('moveBobTask') self.castTrack.pause() #self.castTrack.start(self.castTrack.getT()) p = self.power startT = 0.9 + (1 - p) * 0.3 self.castTrack.start(startT) self.bobStartPos = Point3(0.017568, 7.90371, 6.489) Sequence(Wait(1.2 - startT), Func(self.startMoveBobTask)).start() def startMoveBobTask(self): self.__showBob() self.bobStartT = globalClock.getFrameTime() taskMgr.add(self.moveBobTask, 'moveBobTask') def moveBobTask(self, state): # Accel due to gravity g = 32.2 # Elapsed time of cast t = globalClock.getFrameTime() - self.bobStartT # Scale bob velocity and angle based on power of cast vZero = self.power * self.vZeroMax angle = deg2Rad(self.power * self.angleMax) # How far has bob moved from start point? deltaY = vZero * math.cos(angle) * t deltaZ = vZero * math.sin(angle) * t - (g * t * t) / 2.0 deltaPos = Point3(0, deltaY, deltaZ) # Current bob position pos = self.bobStartPos + deltaPos # Have we reached end condition? if pos[2] < -1.9: pos.setZ(-1.9) self.ripples.reparentTo(self.angleNP) self.ripples.setPos(pos) self.ripples.play() returnVal = Task.done if self.fTargetMode: taskMgr.add(self.distCheck, 'distCheck') else: self.distCheck() else: returnVal = Task.cont self.bob.setPos(pos) return returnVal def distCheck(self, state=None): # Check to see if we hit the target bPos = self.bob.getPos() # Check target returnVal = self.__distCheck(bPos, self.target) if returnVal == Task.done: return returnVal # Check fish return self.__distCheck(bPos, self.fish) def __distCheck(self, bPos, target): def flashTarget(): self.stopTargetInterval() self.target.getChild(0).setColor(0, 0, 1) def flashFish(): taskMgr.remove('turnTask') self.fish.lerpScale(Point3(0.01), 0.5, task='flashFish') tPos = target.getPos(self.angleNP) tDist = Vec3(tPos - bPos) tDist.setZ(0) dist = tDist.length() if target == self.target: flashFunc = flashTarget moveFunc = self.moveTarget else: flashFunc = flashFish moveFunc = self.turnFish if dist < 2.5: fBite = (random.random() < 0.4) or (not self.fTargetMode) delay = self.fTargetMode * 0.25 if fBite: print('BITE') Sequence( Wait(random.random() * delay), Func(flashFunc), Func(self.catchFish), Wait(2.0), Func(moveFunc), ).play() else: print('MISS') def moveIt(): moveFunc(targetPos=target.getPos()) Sequence(Wait(random.random() * delay), Func(moveIt)).play() return Task.done return Task.cont def stopTargetInterval(self): if self.targetInterval: self.targetInterval.pause() self.targetInterval = None def __showBob(self): # Put the bob in the water and make it gently float. self.__hideBob() self.bob.reparentTo(self.angleNP) self.bob.setPos(self.ptop, 0, 0, 0) def __hideBob(self): if self.bob != None: self.bob.detachNode() def getMouse(self): if (base.mouseWatcherNode.hasMouse()): self.mouseX = base.mouseWatcherNode.getMouseX() self.mouseY = base.mouseWatcherNode.getMouseY() else: self.mouseX = 0 self.mouseY = 0 def setfMove(self, fMoving): self.fMovingTarget = fMoving def setfTargetMode(self, fTargetMode): self.fTargetMode = fTargetMode def moveTarget(self, targetPos=None): base.distributedFishingTarget.sendUpdate('bobEnter', []) # self.stopTargetInterval() # self.target.clearColor() # if not targetPos: # x = -87.0 + random.random() * 15.0 # y = 25.0 + random.random() * 20.0 # z = -4.8 # self.targetPos = Point3(x,y,z) # else: # self.targetPos.assign(targetPos) # if self.fMovingTarget: # self.makeTargetInterval() # else: # #self.target.setPos(self.targetPos) def initFish(self): x = -10.0 + random.random() * 20.0 y = 00.0 + random.random() * 30.0 z = -1.6 self.fishPivot.setPos(x, y, z) self.turningRadius = 5.0 + random.random() * 5.0 self.fish.setPos(self.turningRadius, 0, -0.4) if self.wiggleIval: self.wiggleIval.pause() self.wiggleIval = Sequence( self.fish.hprInterval(0.5, hpr=Point3(10, 0, 0), startHpr=Point3(-10, 0, 0), blendType='easeInOut'), self.fish.hprInterval(0.5, hpr=Point3(-10, 0, 0), startHpr=Point3(10, 0, 0), blendType='easeInOut')) self.wiggleIval.loop() if self.circleIval: self.circleIval.pause() self.circleIval = self.fishPivot.hprInterval(20, Point3(360, 0, 0), startHpr=Point3(0)) self.circleIval.loop() taskMgr.remove('turnTask') taskMgr.doMethodLater(3.0 + random.random() * 3.0, self.turnFish, 'turnTask') taskMgr.remove('fishBoundsCheck') taskMgr.add(self.fishBoundsCheck, 'fishBoundsCheck') def fishBoundsCheck(self, state): pos = self.fish.getPos(self) if pos[0] < -20: self.fishPivot.setX(self.fishPivot.getX() + 40.0) elif pos[0] > 20: self.fishPivot.setX(self.fishPivot.getX() - 40.0) if pos[1] < -10: self.fishPivot.setY(self.fishPivot.getY() + 50.0) elif pos[1] > 40: self.fishPivot.setY(self.fishPivot.getY() - 50.0) return Task.cont def turnFish(self, state=None, targetPos=None): self.fish.setScale(0.3, 1, 0.3) if self.circleIval: self.circleIval.pause() newTurningRadius = 5.0 + random.random() * 5.0 fRightTurn = random.random() < 0.5 if fRightTurn: newTurningRadius *= -1.0 offset = self.turningRadius - newTurningRadius self.fishPivot.setX(self.fishPivot, offset) self.turningRadius = newTurningRadius self.fish.setX(self.turningRadius) currH = self.fishPivot.getH() % 360.0 if fRightTurn: self.circleIval = self.fishPivot.hprInterval( 20, Point3(currH - 360, 0, 0), startHpr=Point3(currH, 0, 0)) else: self.circleIval = self.fishPivot.hprInterval( 20, Point3(currH + 360, 0, 0), startHpr=Point3(currH, 0, 0)) self.circleIval.loop() taskMgr.doMethodLater(3.0 + random.random() * 3.0, self.turnFish, 'turnTask') return Task.done def makeTargetInterval(self): x = -10.0 + random.random() * 20.0 y = 0.0 + random.random() * 30.0 z = -1.6 self.targetEndPos = Point3(x, y, z) dist = Vec3(self.targetEndPos - self.targetPos).length() dur = dist / 1.5 dur = dur * (0.75 + random.random() * 0.5) self.targetInterval = Sequence( self.target.posInterval(dur, self.targetEndPos, startPos=self.targetPos, blendType='easeInOut'), self.target.posInterval(dur, self.targetPos, startPos=self.targetEndPos, blendType='easeInOut'), name='moveInterval') offsetDur = dur / random.randint(1, 4) amplitude = 0.1 + random.random() * 1.0 self.targetInterval.loop() def destroy(self): if not self.fAutonomous: self.castButton.destroy() self.buttonFrame.destroy() self.line.removeNode() taskMgr.remove('turnTask') taskMgr.remove('fishBoundsCheck') self.stopCasting() self.removeNode()
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()
class main(ShowBase): def __init__(self): ShowBase.__init__(self) # Disable the default camera movements self.disableMouse() # # VIEW SETTINGS # self.win.setClearColor((0.16, 0.16, 0.16, 1)) render.setAntialias(AntialiasAttrib.MAuto) render2d.setAntialias(AntialiasAttrib.MAuto) # # NODE VIEW # self.viewNP = aspect2d.attachNewNode("viewNP") self.viewNP.setScale(0.5) # # NODE MANAGER # self.nodeMgr = NodeManager(self.viewNP) # # NODE RELATED EVENTS # # Add nodes self.accept("addNode", self.nodeMgr.addNode) # Remove nodes self.accept("removeNode", self.nodeMgr.removeNode) self.accept("x", self.nodeMgr.removeNode) self.accept("delete", self.nodeMgr.removeNode) # Selecting self.accept("selectNode", self.nodeMgr.selectNode) # Deselecting self.accept("mouse3", self.nodeMgr.deselectAll) # Node Drag and Drop self.accept("dragNodeStart", self.setDraggedNode) self.accept("dragNodeMove", self.updateNodeMove) self.accept("dragNodeStop", self.updateNodeStop) # Duplicate/Copy nodes self.accept("shift-d", self.nodeMgr.copyNodes) self.accept("copyNodes", self.nodeMgr.copyNodes) # Refresh node logics self.accept("ctlr-r", self.nodeMgr.updateAllLeaveNodes) self.accept("refreshNodes", self.nodeMgr.updateAllLeaveNodes) # # SOCKET RELATED EVENTS # self.accept("updateConnectedNodes", self.nodeMgr.updateConnectedNodes) # Socket connection with drag and drop self.accept("startPlug", self.nodeMgr.setStartPlug) self.accept("endPlug", self.nodeMgr.setEndPlug) self.accept("connectPlugs", self.nodeMgr.connectPlugs) self.accept("cancelPlug", self.nodeMgr.cancelPlug) # Draw line while connecting sockets self.accept("startLineDrawing", self.startLineDrawing) self.accept("stopLineDrawing", self.stopLineDrawing) # # PROJECT MANAGEMENT # self.accept("new", self.newProject) self.accept("save", self.saveProject) self.accept("load", self.loadProject) self.accept("quit", exit) # # EDITOR VIEW # # Zooming self.accept("zoom", self.zoom) self.accept("zoom_reset", self.zoomReset) self.accept("wheel_up", self.zoom, [True]) self.accept("wheel_down", self.zoom, [False]) # Drag view self.mouseSpeed = 1 self.mousePos = None self.startCameraMovement = False self.accept("mouse2", self.setMoveCamera, [True]) self.accept("mouse2-up", self.setMoveCamera, [False]) # Box select # accept the 1st mouse button events to start and stop the draw self.accept("mouse1", self.startBoxDraw) self.accept("mouse1-up", self.stopBoxDraw) # variables to store the start and current pos of the mousepointer self.startPos = LPoint2f(0, 0) self.lastPos = LPoint2f(0, 0) # variables for the to be drawn box self.boxCardMaker = CardMaker("SelectionBox") self.boxCardMaker.setColor(1, 1, 1, 0.25) self.box = None # # WINDOW RELATED EVENTS # self.screenSize = base.getSize() self.accept("window-event", self.windowEventHandler) # # MENU BAR # self.menuBar = MenuBar() # # TASKS # # Task for handling dragging of the camera/view self.taskMgr.add(self.updateCam, "task_camActualisation", priority=-4) # ------------------------------------------------------------------ # PROJECT FUNCTIONS # ------------------------------------------------------------------ def newProject(self): self.nodeMgr.cleanup() def saveProject(self): Save(self.nodeList, self.connections) def loadProject(self): self.nodeMgr.cleanup() Load(self.nodeMgr) # ------------------------------------------------------------------ # CAMERA SPECIFIC FUNCTIONS # ------------------------------------------------------------------ def setMoveCamera(self, moveCamera): """Start dragging around the editor area/camera""" # store the mouse position if weh have a mouse if base.mouseWatcherNode.hasMouse(): x = base.mouseWatcherNode.getMouseX() y = base.mouseWatcherNode.getMouseY() self.mousePos = Point2(x, y) # set the variable according to if we want to move the camera or not self.startCameraMovement = moveCamera def updateCam(self, task): """Task that will move the editor area/camera around according to mouse movements""" # variables to store the mouses current x and y position x = 0.0 y = 0.0 if base.mouseWatcherNode.hasMouse(): # get the mouse position x = base.mouseWatcherNode.getMouseX() y = base.mouseWatcherNode.getMouseY() if base.mouseWatcherNode.hasMouse() \ and self.mousePos is not None \ and self.startCameraMovement: # Move the viewer node aspect independent wp = self.win.getProperties() aspX = 1.0 aspY = 1.0 wpXSize = wp.getXSize() wpYSize = wp.getYSize() if wpXSize > wpYSize: aspX = wpXSize / float(wpYSize) else: aspY = wpYSize / float(wpXSize) mouseMoveX = (self.mousePos.getX() - x) / self.viewNP.getScale( ).getX() * self.mouseSpeed * aspX mouseMoveY = (self.mousePos.getY() - y) / self.viewNP.getScale( ).getZ() * self.mouseSpeed * aspY self.mousePos = Point2(x, y) self.viewNP.setX(self.viewNP, -mouseMoveX) self.viewNP.setZ(self.viewNP, -mouseMoveY) self.nodeMgr.updateConnections() # continue the task until it got manually stopped return task.cont def zoom(self, zoomIn): """Zoom the editor in or out dependent on the value in zoomIn""" zoomFactor = 0.05 maxZoomIn = 2 maxZoomOut = 0.1 if zoomIn: s = self.viewNP.getScale() if s.getX() - zoomFactor < maxZoomIn and s.getY( ) - zoomFactor < maxZoomIn and s.getZ() - zoomFactor < maxZoomIn: self.viewNP.setScale(s.getX() + zoomFactor, s.getY() + zoomFactor, s.getZ() + zoomFactor) else: s = self.viewNP.getScale() if s.getX() - zoomFactor > maxZoomOut and s.getY( ) - zoomFactor > maxZoomOut and s.getZ() - zoomFactor > maxZoomOut: self.viewNP.setScale(s.getX() - zoomFactor, s.getY() - zoomFactor, s.getZ() - zoomFactor) self.nodeMgr.updateConnections() def zoomReset(self): """Set the zoom level back to the default""" self.viewNP.setScale(0.5) self.nodeMgr.updateConnections() # ------------------------------------------------------------------ # DRAG LINE # ------------------------------------------------------------------ def startLineDrawing(self, startPos): """Start a task that will draw a line from the given start position to the cursor""" self.line = LineNodePath(render2d, thickness=2, colorVec=(0.8, 0.8, 0.8, 1)) self.line.moveTo(startPos) t = self.taskMgr.add(self.drawLineTask, "drawLineTask") t.startPos = startPos def drawLineTask(self, task): """Draws a line from a given start position to the cursor""" mwn = base.mouseWatcherNode if mwn.hasMouse(): pos = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) self.line.reset() self.line.moveTo(task.startPos) self.line.drawTo(pos) self.line.create() return task.cont def stopLineDrawing(self): """Stop the task that draws a line to the cursor""" taskMgr.remove("drawLineTask") if self.line is not None: self.line.reset() self.line = None # ------------------------------------------------------------------ # EDITOR NODE DRAGGING UPDATE # ------------------------------------------------------------------ def setDraggedNode(self, node): """This will set the node that is currently dragged around as well as update other selected nodes which will be moved in addition to the main dragged node""" self.draggedNode = node self.tempNodePositions = {} for node in self.nodeMgr.selectedNodes: self.tempNodePositions[node] = node.frame.getPos(render2d) def updateNodeMove(self, mouseA, mouseB): """Will be called as long as a node is beeing dragged around""" for node in self.nodeMgr.selectedNodes: if node is not self.draggedNode and node in self.tempNodePositions.keys( ): editVec = Vec3(self.tempNodePositions[node] - mouseA) newPos = mouseB + editVec node.frame.setPos(render2d, newPos) self.nodeMgr.updateConnections() def updateNodeStop(self, node=None): """Will be called when a node dragging stopped""" self.draggedNode = None self.tempNodePositions = {} self.nodeMgr.updateConnections() # ------------------------------------------------------------------ # BASIC WINDOW HANDLING # ------------------------------------------------------------------ def windowEventHandler(self, window=None): """Custom handler for window events. We mostly use this for resizing.""" # call showBase windowEvent which would otherwise get overridden and breaking the app self.windowEvent(window) if window != self.win: # This event isn't about our window. return if window is not None: # window is none if panda3d is not started if self.screenSize == base.getSize(): return self.screenSize = base.getSize() # Resize all editor frames self.menuBar.resizeFrame() # ------------------------------------------------------------------ # SELECTION BOX # ------------------------------------------------------------------ def startBoxDraw(self): """Start drawing the box""" if self.mouseWatcherNode.hasMouse(): # get the mouse position self.startPos = LPoint2f(self.mouseWatcherNode.getMouse()) taskMgr.add(self.dragBoxDrawTask, "dragBoxDrawTask") def stopBoxDraw(self): """Stop the draw box task and remove the box""" if not taskMgr.hasTaskNamed("dragBoxDrawTask"): return taskMgr.remove("dragBoxDrawTask") if self.startPos is None or self.lastPos is None: return self.nodeMgr.deselectAll() if self.box is not None: for node in self.nodeMgr.getAllNodes(): # store some view scales for calculations viewXScale = self.viewNP.getScale().getX() viewZScale = self.viewNP.getScale().getZ() # calculate the node edges nodeLeft = node.getLeft() * viewXScale nodeRight = node.getRight() * viewXScale nodeBottom = node.getBottom() * viewZScale nodeTop = node.getTop() * viewZScale # calculate bounding box edges left = min(self.lastPos.getX(), self.startPos.getX()) right = max(self.lastPos.getX(), self.startPos.getX()) top = max(self.lastPos.getY(), self.startPos.getY()) bottom = min(self.lastPos.getY(), self.startPos.getY()) # check for hits xGood = yGood = False if left < nodeLeft and right > nodeLeft: xGood = True elif left < nodeRight and right > nodeRight: xGood = True if top > nodeTop and bottom < nodeTop: yGood = True elif top > nodeBottom and bottom < nodeBottom: yGood = True # check if we have any hits if xGood and yGood: self.nodeMgr.selectNode(node, True, True) # Cleanup the selection box self.box.removeNode() self.startPos = None self.lastPos = None def dragBoxDrawTask(self, task): """This task will track the mouse position and actualize the box's size according to the first click position of the mouse""" if self.mouseWatcherNode.hasMouse(): if self.startPos is None: self.startPos = LPoint2f(self.mouseWatcherNode.getMouse()) # get the current mouse position self.lastPos = LPoint2f(self.mouseWatcherNode.getMouse()) else: return task.cont # check if we already have a box if self.box != None: # if so, remove that old box self.box.removeNode() # set the box's size self.boxCardMaker.setFrame(self.lastPos.getX(), self.startPos.getX(), self.startPos.getY(), self.lastPos.getY()) # generate, setup and draw the box node = self.boxCardMaker.generate() self.box = render2d.attachNewNode(node) self.box.setBin("gui-popup", 25) self.box.setTransparency(TransparencyAttrib.M_alpha) # run until the task is manually stopped return task.cont
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
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, width=5,
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()
def __init__(self): ShowBase.__init__(self) wp = core.WindowProperties() wp.setTitle("Dorfdelf") self.win.requestProperties(wp) self.render.setAntialias(core.AntialiasAttrib.MAuto) self.setBackgroundColor(0.5, 0.5, 0.5) self.disableMouse() self.enableParticles() font = self.loader.loadFont('media/Carlito-Regular.ttf') font.setPixelsPerUnit(120) font.setPageSize(512, 1024) loading = OnscreenText(text='Loading...', scale=0.2, pos=(0.0, 0.0), fg=(1, 1, 1, 1), shadow=(0.3, 0.3, 0.3, 1.0), align=core.TextNode.ACenter, mayChange=True, font=font, parent=self.aspect2d) self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() loading.setText('Generating world') self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() self.world = world.World(128, 128, 100) self.world.generate() loading.setText('Creating world geometry') self.graphicsEngine.renderFrame() self.graphicsEngine.renderFrame() self.world_geometry = geometry.WorldGeometry(self.world) self.camLens.setFocalLength(1) self.camera.setPos(0, 0, 100) self.camera.lookAt(self.world.midpoint.x, self.world.midpoint.y, 100) self.cam.setPos(0, 0, 0) self.cam.setHpr(0, -45, 0) self.cc = camera.CameraController(self.world.size, self.mouseWatcherNode, self.camera, self.cam) self.gui = gui.GUI(self.pixel2d, font) self.world_geometry.node.setPos(0, 0, 0) self.world_geometry.node.reparentTo(self.render) self.explore_mode = True self.current_slice = int(self.world.midpoint.z) self.accept_keyboard() self.accept('mouse1', self.toggle_block) self.accept('console-command', self.console_command) self.designation = designation.Designation() self.dorfs = [] self.tool = lambda w, x, y, z: None self.toolargs = () self.tools = { 'bomb': tools.bomb, 'block': tools.block, 'd': self.designation.add } self.console = console.Console(self) self.picker = block_picker.BlockPicker(self.world, self) self.zmap = zmap.ZMap(self.world, self) self.change_slice(0) arrow = LineNodePath() arrow.reparentTo(self.render) arrow.drawArrow2d(Vec3(-5, -5, self.world.midpoint.z), Vec3(15, -5, self.world.midpoint.z), 30, 3) arrow.create() loading.hide()
class NodeEditor(DirectObject): def __init__(self, parent, customNodeMap={}, customExporterMap={}): DirectObject.__init__(self) fn = Filename.fromOsSpecific(os.path.dirname(__file__)) fn.makeTrueCase() self.icon_dir = str(fn) + "/" loadPrcFileData("", f"model-path {self.icon_dir}") # # NODE VIEW # self.viewNP = aspect2d.attachNewNode("viewNP") self.viewNP.setScale(0.5) # # NODE MANAGER # self.nodeMgr = NodeManager(self.viewNP, customNodeMap) # Drag view self.mouseSpeed = 1 self.mousePos = None self.startCameraMovement = False # Box select # variables to store the start and current pos of the mousepointer self.startPos = LPoint2f(0, 0) self.lastPos = LPoint2f(0, 0) # variables for the to be drawn box self.boxCardMaker = CardMaker("SelectionBox") self.boxCardMaker.setColor(1, 1, 1, 0.25) self.box = None # # MENU BAR # self.mainView = MainView(parent, customNodeMap, customExporterMap) self.enable_editor() # ------------------------------------------------------------------ # FRAME COMPATIBILITY FUNCTIONS # ------------------------------------------------------------------ def is_dirty(self): """ This method returns True if an unsaved state of the editor is given """ return len(self.nodeMgr.getAllNodes()) > 0 def enable_editor(self): """ Enable the editor. """ self.enable_events() # Task for handling dragging of the camera/view taskMgr.add(self.updateCam, "NodeEditor_task_camActualisation", priority=-4) self.viewNP.show() self.nodeMgr.showConnections() def disable_editor(self): """ Disable the editor. """ self.ignore_all() taskMgr.remove("NodeEditor_task_camActualisation") self.viewNP.hide() self.nodeMgr.hideConnections() def do_exception_save(self): """ Save content of editor if the application crashes """ Save(self.nodeMgr.nodeList, self.nodeMgr.connections, True) # ------------------------------------------------------------------ # NODE EDITOR RELATED EVENTS # ------------------------------------------------------------------ def enable_events(self): # Add nodes self.accept("addNode", self.nodeMgr.addNode) # Remove nodes self.accept("NodeEditor_removeNode", self.nodeMgr.removeNode) self.accept("x", self.nodeMgr.removeNode) self.accept("delete", self.nodeMgr.removeNode) # Selecting self.accept("selectNode", self.nodeMgr.selectNode) # Deselecting self.accept("mouse3", self.nodeMgr.deselectAll) # Node Drag and Drop self.accept("dragNodeStart", self.setDraggedNode) self.accept("dragNodeMove", self.updateNodeMove) self.accept("dragNodeStop", self.updateNodeStop) # Duplicate/Copy nodes self.accept("shift-d", self.nodeMgr.copyNodes) self.accept("NodeEditor_copyNodes", self.nodeMgr.copyNodes) # Refresh node logics self.accept("ctlr-r", self.nodeMgr.updateAllLeaveNodes) self.accept("NodeEditor_refreshNodes", self.nodeMgr.updateAllLeaveNodes) # # SOCKET RELATED EVENTS # self.accept("updateConnectedNodes", self.nodeMgr.updateConnectedNodes) # Socket connection with drag and drop self.accept("startPlug", self.nodeMgr.setStartPlug) self.accept("endPlug", self.nodeMgr.setEndPlug) self.accept("connectPlugs", self.nodeMgr.connectPlugs) self.accept("cancelPlug", self.nodeMgr.cancelPlug) # Draw line while connecting sockets self.accept("startLineDrawing", self.startLineDrawing) self.accept("stopLineDrawing", self.stopLineDrawing) # # CONNECTION RELATED EVENTS # self.accept("NodeEditor_updateConnections", self.nodeMgr.updateConnections) # # PROJECT MANAGEMENT # self.accept("NodeEditor_new", self.newProject) self.accept("NodeEditor_save", self.saveProject) self.accept("NodeEditor_load", self.loadProject) self.accept("quit_app", exit) # # EXPORTERS # self.accept("NodeEditor_customSave", self.customExport) # # EDITOR VIEW # # Zooming self.accept("NodeEditor_zoom", self.zoom) self.accept("NodeEditor_zoom_reset", self.zoomReset) self.accept("wheel_up", self.zoom, [True]) self.accept("wheel_down", self.zoom, [False]) # Drag view self.accept("mouse2", self.setMoveCamera, [True]) self.accept("mouse2-up", self.setMoveCamera, [False]) # Box select # accept the 1st mouse button events to start and stop the draw self.accept("mouse1", self.startBoxDraw) self.accept("mouse1-up", self.stopBoxDraw) # ------------------------------------------------------------------ # PROJECT FUNCTIONS # ------------------------------------------------------------------ def newProject(self): self.nodeMgr.cleanup() def saveProject(self): Save(self.nodeMgr.nodeList, self.nodeMgr.connections) def loadProject(self): self.nodeMgr.cleanup() Load(self.nodeMgr) def customExport(self, exporter): exporter(self.nodeMgr.nodeList, self.nodeMgr.connections) # ------------------------------------------------------------------ # CAMERA SPECIFIC FUNCTIONS # ------------------------------------------------------------------ def setMoveCamera(self, moveCamera): """Start dragging around the editor area/camera""" # store the mouse position if weh have a mouse if base.mouseWatcherNode.hasMouse(): x = base.mouseWatcherNode.getMouseX() y = base.mouseWatcherNode.getMouseY() self.mousePos = Point2(x, y) # set the variable according to if we want to move the camera or not self.startCameraMovement = moveCamera def updateCam(self, task): """Task that will move the editor area/camera around according to mouse movements""" # variables to store the mouses current x and y position x = 0.0 y = 0.0 if base.mouseWatcherNode.hasMouse(): # get the mouse position x = base.mouseWatcherNode.getMouseX() y = base.mouseWatcherNode.getMouseY() if base.mouseWatcherNode.hasMouse() \ and self.mousePos is not None \ and self.startCameraMovement: # Move the viewer node aspect independent wp = base.win.getProperties() aspX = 1.0 aspY = 1.0 wpXSize = wp.getXSize() wpYSize = wp.getYSize() if wpXSize > wpYSize: aspX = wpXSize / float(wpYSize) else: aspY = wpYSize / float(wpXSize) mouseMoveX = (self.mousePos.getX() - x) / self.viewNP.getScale( ).getX() * self.mouseSpeed * aspX mouseMoveY = (self.mousePos.getY() - y) / self.viewNP.getScale( ).getZ() * self.mouseSpeed * aspY self.mousePos = Point2(x, y) self.viewNP.setX(self.viewNP, -mouseMoveX) self.viewNP.setZ(self.viewNP, -mouseMoveY) self.nodeMgr.updateConnections() # continue the task until it got manually stopped return task.cont def zoom(self, zoomIn): """Zoom the editor in or out dependent on the value in zoomIn""" zoomFactor = 0.05 maxZoomIn = 2 maxZoomOut = 0.1 if zoomIn: s = self.viewNP.getScale() if s.getX() - zoomFactor < maxZoomIn and s.getY( ) - zoomFactor < maxZoomIn and s.getZ() - zoomFactor < maxZoomIn: self.viewNP.setScale(s.getX() + zoomFactor, s.getY() + zoomFactor, s.getZ() + zoomFactor) else: s = self.viewNP.getScale() if s.getX() - zoomFactor > maxZoomOut and s.getY( ) - zoomFactor > maxZoomOut and s.getZ() - zoomFactor > maxZoomOut: self.viewNP.setScale(s.getX() - zoomFactor, s.getY() - zoomFactor, s.getZ() - zoomFactor) self.nodeMgr.updateConnections() def zoomReset(self): """Set the zoom level back to the default""" self.viewNP.setScale(0.5) self.nodeMgr.updateConnections() # ------------------------------------------------------------------ # DRAG LINE # ------------------------------------------------------------------ def startLineDrawing(self, startPos): """Start a task that will draw a line from the given start position to the cursor""" self.line = LineNodePath(render2d, thickness=2, colorVec=(0.8, 0.8, 0.8, 1)) self.line.moveTo(startPos) t = taskMgr.add(self.drawLineTask, "drawLineTask") t.startPos = startPos def drawLineTask(self, task): """Draws a line from a given start position to the cursor""" mwn = base.mouseWatcherNode if mwn.hasMouse(): pos = Point3(mwn.getMouse()[0], 0, mwn.getMouse()[1]) self.line.reset() self.line.moveTo(task.startPos) self.line.drawTo(pos) self.line.create() return task.cont def stopLineDrawing(self): """Stop the task that draws a line to the cursor""" taskMgr.remove("drawLineTask") if self.line is not None: self.line.reset() self.line = None # ------------------------------------------------------------------ # EDITOR NODE DRAGGING UPDATE # ------------------------------------------------------------------ def setDraggedNode(self, node): """This will set the node that is currently dragged around as well as update other selected nodes which will be moved in addition to the main dragged node""" self.draggedNode = node self.draggedNode.disable() self.tempNodePositions = {} for node in self.nodeMgr.selectedNodes: self.tempNodePositions[node] = node.frame.getPos(render2d) def updateNodeMove(self, mouseA, mouseB): """Will be called as long as a node is beeing dragged around""" for node in self.nodeMgr.selectedNodes: if node is not self.draggedNode and node in self.tempNodePositions.keys( ): editVec = Vec3(self.tempNodePositions[node] - mouseA) newPos = mouseB + editVec node.frame.setPos(render2d, newPos) self.nodeMgr.updateConnections() def updateNodeStop(self, node=None): """Will be called when a node dragging stopped""" self.draggedNode.enable() self.draggedNode = None self.tempNodePositions = {} self.nodeMgr.updateConnections() # ------------------------------------------------------------------ # SELECTION BOX # ------------------------------------------------------------------ def startBoxDraw(self): """Start drawing the box""" if base.mouseWatcherNode.hasMouse(): # get the mouse position self.startPos = LPoint2f(base.mouseWatcherNode.getMouse()) taskMgr.add(self.dragBoxDrawTask, "dragBoxDrawTask") def stopBoxDraw(self): """Stop the draw box task and remove the box""" if not taskMgr.hasTaskNamed("dragBoxDrawTask"): return taskMgr.remove("dragBoxDrawTask") if self.startPos is None or self.lastPos is None: return self.nodeMgr.deselectAll() if self.box is not None: for node in self.nodeMgr.getAllNodes(): # store some view scales for calculations viewXScale = self.viewNP.getScale().getX() viewZScale = self.viewNP.getScale().getZ() # calculate the node edges nodeLeft = node.getLeft() * viewXScale nodeRight = node.getRight() * viewXScale nodeBottom = node.getBottom() * viewZScale nodeTop = node.getTop() * viewZScale # calculate bounding box edges left = min(self.lastPos.getX(), self.startPos.getX()) right = max(self.lastPos.getX(), self.startPos.getX()) top = max(self.lastPos.getY(), self.startPos.getY()) bottom = min(self.lastPos.getY(), self.startPos.getY()) # check for hits xGood = yGood = False if left < nodeLeft and right > nodeLeft: xGood = True elif left < nodeRight and right > nodeRight: xGood = True if top > nodeTop and bottom < nodeTop: yGood = True elif top > nodeBottom and bottom < nodeBottom: yGood = True # check if we have any hits if xGood and yGood: self.nodeMgr.selectNode(node, True, True) # Cleanup the selection box self.box.removeNode() self.startPos = None self.lastPos = None def dragBoxDrawTask(self, task): """This task will track the mouse position and actualize the box's size according to the first click position of the mouse""" if base.mouseWatcherNode.hasMouse(): if self.startPos is None: self.startPos = LPoint2f(base.mouseWatcherNode.getMouse()) # get the current mouse position self.lastPos = LPoint2f(base.mouseWatcherNode.getMouse()) else: return task.cont # check if we already have a box if self.box != None: # if so, remove that old box self.box.removeNode() # set the box's size self.boxCardMaker.setFrame(self.lastPos.getX(), self.startPos.getX(), self.startPos.getY(), self.lastPos.getY()) # generate, setup and draw the box node = self.boxCardMaker.generate() self.box = render2d.attachNewNode(node) self.box.setBin("gui-popup", 25) self.box.setTransparency(TransparencyAttrib.M_alpha) # run until the task is manually stopped return task.cont
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()
class Simulation(ShowBase): scale = 1 height = 500 lateralError = 200 dt = 0.1 steps = 0 #Test Controllers fuelPID = PID(10, 0.5, 10, 0, 100) heightPID = PID(0.08, 0, 0.3, 0.1, 1) pitchPID = PID(10, 0, 1000, -10, 10) rollPID = PID(10, 0, 1000, -10, 10) XPID = PID(0.2, 0, 0.8, -10, 10) YPID = PID(0.2, 0, 0.8, -10, 10) vulcain = NeuralNetwork() tau = 0.5 Valves=[] CONTROL = False EMPTY = False LANDED = False DONE = False gimbalX = 0 gimbalY = 0 targetAlt = 150 R = RE(200 * 9.806, 250 * 9.806, 7607000 / 9 * scale, 0.4) throttle = 0.0 fuelMass_full = 417000 * scale fuelMass_init = 0.10 radius = 1.8542 * scale length = 47 * scale Cd = 1.5 def __init__(self, VISUALIZE=False): self.VISUALIZE = VISUALIZE if VISUALIZE is True: ShowBase.__init__(self) self.setBackgroundColor(0.2, 0.2, 0.2, 1) self.setFrameRateMeter(True) self.render.setShaderAuto() self.cam.setPos(-120 * self.scale, -120 * self.scale, 120 * self.scale) self.cam.lookAt(0, 0, 10 * self.scale) alight = AmbientLight('ambientLight') alight.setColor(Vec4(0.5, 0.5, 0.5, 1)) alightNP = self.render.attachNewNode(alight) dlight = DirectionalLight('directionalLight') dlight.setDirection(Vec3(1, -1, -1)) dlight.setColor(Vec4(0.7, 0.7, 0.7, 1)) dlightNP = self.render.attachNewNode(dlight) self.render.clearLight() self.render.setLight(alightNP) self.render.setLight(dlightNP) 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) inputState.watchWithModifiers('forward', 'w') inputState.watchWithModifiers('left', 'a') inputState.watchWithModifiers('reverse', 's') inputState.watchWithModifiers('right', 'd') inputState.watchWithModifiers('turnLeft', 'q') inputState.watchWithModifiers('turnRight', 'e') self.ostData = OnscreenText(text='ready', pos=(-1.3, 0.9), scale=0.07, fg=Vec4(1, 1, 1, 1), align=TextNode.ALeft) self.fuelMass = self.fuelMass_full * self.fuelMass_init self.vulcain.load_existing_model(path="LandingRockets/",model_name="140k_samples_1024neurons_3layers_l2-0.000001") # Physics self.setup() # _____HANDLER_____ def doExit(self): self.cleanup() sys.exit(1) def doReset(self): self.cleanup() self.setup() def toggleWireframe(self): ...#self.toggleWireframe() def toggleTexture(self): ...#self.toggleTexture() def toggleDebug(self): if self.debugNP.isHidden(): self.debugNP.show() else: self.debugNP.hide() def doScreenshot(self): self.screenshot('Bullet') # ____TASK___ def processInput(self): throttleChange = 0.0 if inputState.isSet('forward'): self.gimbalY = 10 if inputState.isSet('reverse'): self.gimbalY = -10 if inputState.isSet('left'): self.gimbalX = 10 if inputState.isSet('right'): self.gimbalX = -10 if inputState.isSet('turnLeft'): throttleChange = -1.0 if inputState.isSet('turnRight'): throttleChange = 1.0 self.throttle += throttleChange / 100.0 self.throttle = min(max(self.throttle, 0), 1) def processContacts(self): result = self.world.contactTestPair(self.rocketNP.node(), self.groundNP.node()) #print(result.getNumContacts()) if result.getNumContacts() != 0: self.LANDED = True #self.DONE = True def update(self,task): #self.control(0.1,0.1,0.1) #self.processInput() #self.processContacts() # self.terrain.update() return task.cont def cleanup(self): self.world.removeRigidBody(self.groundNP.node()) self.world.removeRigidBody(self.rocketNP.node()) self.world = None self.debugNP = None self.groundNP = None self.rocketNP = None self.worldNP.removeNode() self.LANDED = False self.EMPTY = False self.DONE = False self.steps = 0 self.fuelMass = self.fuelMass_full*self.fuelMass_init def setup(self): self.targetAlt = r.randrange(100,300) self.Valves = np.array([0.15,0.2,0.15]) self.EngObs = self.vulcain.predict_data_point(np.array(self.Valves).reshape(1,-1)) if self.VISUALIZE is True: self.worldNP = self.render.attachNewNode('World') else: self.root = NodePath(PandaNode("world root")) self.worldNP = self.root.attachNewNode('World') self.world = BulletWorld() self.world.setGravity(Vec3(0, 0, -9.80665)) # World self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug')) self.debugNP.node().showWireframe(True) self.debugNP.node().showConstraints(True) self.debugNP.node().showBoundingBoxes(False) self.debugNP.node().showNormals(True) self.debugNP.show() self.world.setDebugNode(self.debugNP.node()) # self.debugNP.showTightBounds() # self.debugNP.showBounds() # Ground (static) shape = BulletPlaneShape(Vec3(0, 0, 1), 1) self.groundNP = self.worldNP.attachNewNode(BulletRigidBodyNode('Ground')) self.groundNP.node().addShape(shape) self.groundNP.setPos(0, 0, 0) self.groundNP.setCollideMask(BitMask32.allOn()) self.world.attachRigidBody(self.groundNP.node()) # Rocket shape = BulletCylinderShape(self.radius, self.length, ZUp) self.rocketNP = self.worldNP.attachNewNode(BulletRigidBodyNode('Cylinder')) self.rocketNP.node().setMass(27200 * self.scale) self.rocketNP.node().addShape(shape) #self.rocketNP.setPos(20,20,250) self.rocketNP.setPos(20, 20, r.randrange(100, 300)+200) #self.rocketNP.setPos(r.randrange(-self.lateralError, self.lateralError, 1), r.randrange(-self.lateralError, self.lateralError, 1), self.height) # self.rocketNP.setPos(0, 0, self.length*10) self.rocketNP.setCollideMask(BitMask32.allOn()) # self.rocketNP.node().setCollisionResponse(0) self.rocketNP.node().notifyCollisions(True) self.world.attachRigidBody(self.rocketNP.node()) for i in range(4): leg = BulletCylinderShape(0.1 * self.radius, 0.5 * self.length, XUp) self.rocketNP.node().addShape(leg, TransformState.makePosHpr( Vec3(6 * self.radius * math.cos(i * math.pi / 2), 6 * self.radius * math.sin(i * math.pi / 2), -0.6 * self.length), Vec3(i * 90, 0, 30))) shape = BulletConeShape(0.75 * self.radius, 0.5 * self.radius, ZUp) self.rocketNP.node().addShape(shape, TransformState.makePosHpr(Vec3(0, 0, -1 / 2 * self.length), Vec3(0, 0, 0))) # Fuel self.fuelRadius = 0.9 * self.radius shape = BulletCylinderShape(self.fuelRadius, 0.01 * self.length, ZUp) self.fuelNP = self.worldNP.attachNewNode(BulletRigidBodyNode('Cone')) self.fuelNP.node().setMass(self.fuelMass_full * self.fuelMass_init) self.fuelNP.node().addShape(shape) self.fuelNP.setPos(0, 0, self.rocketNP.getPos().getZ() - self.length * 0.5 * (1 - self.fuelMass_init)) self.fuelNP.setCollideMask(BitMask32.allOn()) self.fuelNP.node().setCollisionResponse(0) self.world.attachRigidBody(self.fuelNP.node()) frameA = TransformState.makePosHpr(Point3(0, 0, 0), Vec3(0, 0, 90)) frameB = TransformState.makePosHpr(Point3(0, 0, 0), Vec3(0, 0, 90)) self.fuelSlider = BulletSliderConstraint(self.rocketNP.node(), self.fuelNP.node(), frameA, frameB, 1) self.fuelSlider.setTargetLinearMotorVelocity(0) self.fuelSlider.setDebugDrawSize(2.0) self.fuelSlider.set_lower_linear_limit(0) self.fuelSlider.set_upper_linear_limit(0) self.world.attachConstraint(self.fuelSlider) self.npThrustForce = LineNodePath(self.rocketNP, 'Thrust', thickness=4, colorVec=Vec4(1, 0.5, 0, 1)) self.npDragForce = LineNodePath(self.rocketNP, 'Drag', thickness=4, colorVec=Vec4(1, 0, 0, 1)) self.npLiftForce = LineNodePath(self.rocketNP, 'Lift', thickness=4, colorVec=Vec4(0, 0, 1, 1)) self.npFuelState = LineNodePath(self.fuelNP, 'Fuel', thickness=20, colorVec=Vec4(0, 1, 0, 1)) self.rocketCSLon = self.radius ** 2 * math.pi self.rocketCSLat = self.length * 2 * self.radius if self.VISUALIZE is True: self.terrain = loader.loadModel("LZGrid2.egg") self.terrain.setScale(10) self.terrain.reparentTo(self.render) self.terrain.setColor(Vec4(0.1, 0.2, 0.1, 1)) self.toggleTexture() #self.fuelNP.setPos(0, 0, self.rocketNP.getPos().getZ() - self.length * 0.4 * (1 - self.fuelMass_init)) for i in range(5): self.world.doPhysics(self.dt, 5, 1.0 / 180.0) self.fuelSlider.set_lower_linear_limit(-self.length * 0.5 * (1 - self.fuelMass_init)) self.fuelSlider.set_upper_linear_limit(self.length * 0.5 * (1 - self.fuelMass_init)) for i in range(100): self.world.doPhysics(self.dt, 5, 1.0 / 180.0) self.rocketNP.node().applyForce(Vec3(0,0,300000), Vec3(0, 0, 0)) def updateRocket(self, mdot, dt): # Fuel Update self.fuelMass = self.fuelNP.node().getMass() - dt * mdot if self.fuelMass <= 0: self.EMPTY is True fuel_percent = self.fuelMass / self.fuelMass_full self.fuelNP.node().setMass(self.fuelMass) fuelHeight = self.length * fuel_percent I1 = 1 / 2 * self.fuelMass * self.fuelRadius ** 2 I2 = 1 / 4 * self.fuelMass * self.fuelRadius ** 2 + 1 / 12 * self.fuelMass * fuelHeight * fuelHeight self.fuelNP.node().setInertia(Vec3(I2, I2, I1)) # Shift fuel along slider constraint fuelTargetPos = 0.5 * (self.length - fuelHeight) fuelPos = self.fuelSlider.getLinearPos() self.fuelSlider.set_upper_linear_limit(fuelTargetPos) self.fuelSlider.set_lower_linear_limit(-fuelTargetPos) self.npFuelState.reset() self.npFuelState.drawArrow2d(Vec3(0, 0, -0.5 * fuelHeight), Vec3(0, 0, 0.5 * fuelHeight), 45, 2) self.npFuelState.create() def observe(self): pos = self.rocketNP.getPos() vel = self.rocketNP.node().getLinearVelocity() quat = self.rocketNP.getTransform().getQuat() Roll, Pitch, Yaw = quat.getHpr() rotVel = self.rocketNP.node().getAngularVelocity() offset = self.targetAlt-pos.getZ() return pos, vel, Roll, Pitch, Yaw, rotVel, self.fuelMass / self.fuelMass_full, self.EMPTY, self.DONE, self.LANDED, offset, self.EngObs[0], self.Valves def control(self,ValveCommands): self.gimbalX = 0 self.gimbalY = 0 self.Valves = ValveCommands-(ValveCommands-self.Valves)*np.exp(-self.dt/self.tau) self.EngObs = self.vulcain.predict_data_point(np.array(self.Valves).reshape(1,-1 )) #Brennkammerdruck, Gaskammertemp, H2Massenstrom, LOX MAssentrom, Schub #Bar,K,Kg/s,Kg/s,kN #self.dt = globalClock.getDt() pos = self.rocketNP.getPos() vel = self.rocketNP.node().getLinearVelocity() quat = self.rocketNP.getTransform().getQuat() Roll, Pitch, Yaw = quat.getHpr() rotVel = self.rocketNP.node().getAngularVelocity() # CHECK STATE if self.fuelMass <= 0: self.EMPTY = True #if pos.getZ() <= 36: # self.LANDED = True self.LANDED = False self.processContacts() P, T, rho = air_dens(pos[2]) rocketZWorld = quat.xform(Vec3(0, 0, 1)) AoA = math.acos(min(max(dot(norm(vel), norm(-rocketZWorld)), -1), 1)) dynPress = 0.5 * dot(vel, vel) * rho dragArea = self.rocketCSLon + (self.rocketCSLat - self.rocketCSLon) * math.sin(AoA) drag = norm(-vel) * dynPress * self.Cd * dragArea time = globalClock.getFrameTime() liftVec = norm(vel.project(rocketZWorld) - vel) if AoA > 0.5 * math.pi: liftVec = -liftVec lift = liftVec * (math.sin(AoA * 2) * self.rocketCSLat * dynPress) if self.CONTROL: self.throttle = self.heightPID.control(pos.getZ(), vel.getZ(), 33) pitchTgt = self.XPID.control(pos.getX(), vel.getX(), 0) self.gimbalX = -self.pitchPID.control(Yaw, rotVel.getY(), pitchTgt) rollTgt = self.YPID.control(pos.getY(), vel.getY(), 0) self.gimbalY = -self.rollPID.control(Pitch, rotVel.getX(), -rollTgt) self.thrust = self.EngObs[0][4]*1000 #print(self.EngObs) quat = self.rocketNP.getTransform().getQuat() quatGimbal = TransformState.makeHpr(Vec3(0, self.gimbalY, self.gimbalX)).getQuat() thrust = quatGimbal.xform(Vec3(0, 0, self.thrust)) thrustWorld = quat.xform(thrust) #print(thrustWorld) self.npDragForce.reset() self.npDragForce.drawArrow2d(Vec3(0, 0, 0), quat.conjugate().xform(drag) / 1000, 45, 2) self.npDragForce.create() self.npLiftForce.reset() self.npLiftForce.drawArrow2d(Vec3(0, 0, 0), quat.conjugate().xform(lift) / 1000, 45, 2) self.npLiftForce.create() self.npThrustForce.reset() if self.EMPTY is False & self.LANDED is False: self.npThrustForce.drawArrow2d(Vec3(0, 0, -0.5 * self.length), Vec3(0, 0, -0.5 * self.length) - thrust / 30000, 45, 2) self.npThrustForce.create() self.rocketNP.node().applyForce(drag, Vec3(0, 0, 0)) self.rocketNP.node().applyForce(lift, Vec3(0, 0, 0)) #print(self.EMPTY,self.LANDED) if self.EMPTY is False & self.LANDED is False: self.rocketNP.node().applyForce(thrustWorld, quat.xform(Vec3(0, 0, -1 / 2 * self.length))) self.updateRocket(self.EngObs[0][2]+self.EngObs[0][3], self.dt) self.rocketNP.node().setActive(True) self.fuelNP.node().setActive(True) self.processInput() self.world.doPhysics(self.dt) self.steps+=1 if self.steps > 1000: self.DONE = True telemetry = [] telemetry.append('Thrust: {}'.format(int(self.EngObs[0][4]))) telemetry.append('Fuel: {}%'.format(int(self.fuelMass / self.fuelMass_full * 100.0))) telemetry.append('Gimbal: {}'.format(int(self.gimbalX)) + ',{}'.format(int(self.gimbalY))) telemetry.append('AoA: {}'.format(int(AoA / math.pi * 180.0))) telemetry.append('\nPos: {},{}'.format(int(pos.getX()), int(pos.getY()))) telemetry.append('Height: {}'.format(int(pos.getZ()))) telemetry.append('RPY: {},{},{}'.format(int(Roll), int(Pitch), int(Yaw))) telemetry.append('Speed: {}'.format(int(np.linalg.norm(vel)))) telemetry.append('Vel: {},{},{}'.format(int(vel.getX()), int(vel.getY()), int(vel.getZ()))) telemetry.append('Rot: {},{},{}'.format(int(rotVel.getX()), int(rotVel.getY()), int(rotVel.getZ()))) telemetry.append('LANDED: {}'.format(self.LANDED)) telemetry.append('Time: {}'.format(self.steps*self.dt)) telemetry.append('TARGET: {}'.format(self.targetAlt)) #print(pos) if self.VISUALIZE is True: self.ostData.setText('\n'.join(telemetry)) self.cam.setPos(pos[0] - 120 * self.scale, pos[1] - 120 * self.scale, pos[2] + 80 * self.scale) self.cam.lookAt(pos[0], pos[1], pos[2]) self.taskMgr.step() """
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
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()
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)