def throwObject(self, projectile=True): if not self.weapon: return self.acceptOnce('enter' + self.wsnp.node().getName(), self.handleWeaponCollision) self.playWeaponSound() if self.weapon: self.weapon.wrtReparentTo(render) self.weapon.setHpr(Vec3(0, 0, 0)) if self.attack not in ('glowerpower', ): parent = self.suit.find('**/joint_Rhold') else: parent = self.suit.find('**/joint_head') startNP = parent.attachNewNode('startNp') startNP.lookAt(render, self.targetX, self.targetY, self.targetZ) pathNP = NodePath('throwPath') pathNP.reparentTo(startNP) pathNP.setScale(render, 1.0) pathNP.setPos(0, 50, 0) if self.attack in ('clipontie', 'powertie', 'halfwindsor'): self.weapon.setHpr(pathNP.getHpr(render)) if projectile == True: self.throwTrajectory = ProjectileInterval(self.weapon, startPos=self.suit.find('**/joint_Rhold').getPos(render), endPos=pathNP.getPos(render), gravityMult=0.7, duration=1.0) else: self.weapon.setH(pathNP.getH(render)) self.throwTrajectory = LerpPosInterval(self.weapon, duration=0.5, pos=pathNP.getPos(render), startPos=startNP.getPos(render) + (0, 3, 0)) self.throwTrajectory.start() self.weapon_state = 'released' startNP.removeNode() del startNP pathNP.removeNode() del pathNP
def generateToonMoveTrack(self, toon): node = NodePath('tempNode') displacement = Vec3(toon.getPos(render) - self.getPos(render)) displacement.setZ(0) displacement.normalize() movieDistance = self.movieNode.getDistance(self.rotateNode) displacement *= movieDistance node.reparentTo(render) node.setPos(displacement + self.getPos(render)) node.lookAt(self) heading = PythonUtil.fitDestAngle2Src(toon.getH(render), node.getH(render)) hpr = toon.getHpr(render) hpr.setX(heading) finalX = node.getX(render) finalY = node.getY(render) finalZ = node.getZ(render) node.removeNode() toonTrack = Sequence( Parallel( ActorInterval(toon, 'walk', loop=True, duration=1), Parallel( LerpPosInterval(toon, 1.0, Point3(finalX, finalY, toon.getZ(render)), fluid=True, bakeInStart=False)), LerpHprInterval(toon, 1.0, hpr=hpr)), Func(toon.loop, 'neutral')) return toonTrack
def throwObject(self, projectile = True): if not self.weapon: return self.acceptOnce('enter' + self.wsnp.node().getName(), self.handleWeaponCollision) self.playWeaponSound() if self.weapon: self.weapon.wrtReparentTo(render) self.weapon.setHpr(Vec3(0, 0, 0)) if self.attack not in ('glowerpower',): parent = self.suit.find('**/joint_Rhold') else: parent = self.suit.find('**/joint_head') startNP = parent.attachNewNode('startNp') startNP.lookAt(render, self.targetX, self.targetY, self.targetZ) pathNP = NodePath('throwPath') pathNP.reparentTo(startNP) pathNP.setScale(render, 1.0) pathNP.setPos(0, 50, 0) if self.attack in ('clipontie', 'powertie', 'halfwindsor'): self.weapon.setHpr(pathNP.getHpr(render)) if projectile == True: self.throwTrajectory = ProjectileInterval(self.weapon, startPos=self.suit.find('**/joint_Rhold').getPos(render), endPos=pathNP.getPos(render), gravityMult=0.7, duration=1.0) else: self.weapon.setH(pathNP.getH(render)) self.throwTrajectory = LerpPosInterval(self.weapon, duration=0.5, pos=pathNP.getPos(render), startPos=startNP.getPos(render) + (0, 3, 0)) self.throwTrajectory.start() self.weapon_state = 'released' startNP.removeNode() del startNP pathNP.removeNode() del pathNP
class CamManager(DirectObject.DirectObject): """1st or 3d person camera, or disable """ def __init__(self, game): self.game = game self.char = self.game.char self.win = self.game.gui.win self.hotkeys = self.game.gui.hotkeys self.node = NodePath('char') self.Ccentr = NodePath('Ccentr') self.Ccentr.reparentTo(self.node) self.Ccentr.setZ(1) self.third_dist = -6 self.sleep = 0.001 self.camera = self.game.gui.camera self.char.reparentTo(self.node) taskMgr.setupTaskChain('cam_move', numThreads = 1, frameSync = False, threadPriority = TPUrgent, timeslicePriority = False) def set_enable(self, value, third = False): self.enable = value self.third = third self.node.reparentTo(self.game.world.root_node) self.node.setPos(self.game.world.avatar.getPos()) if self.enable: self.camera.reparentTo(self.Ccentr) if self.third: self.camera.setPos(0, self.third_dist, 0) #self.char.show() else: self.camera.setPos(0, 0, 0) #self.char.hide() self.camera.lookAt(self.Ccentr) taskMgr.add(self.mouse_update, 'mouse-task') else: self.camera.reparentTo(self.game.world.root_node) self.camera.setPos(self.game.world.root_node, self.game.world.avatar.getPos(self.game.world.root_node)) self.node.detachNode() #@profile_decorator def mouse_update(self, task): """ this task updates the mouse """ if not self.enable: return task.done md = base.win.getPointer(0) x = md.getX() y = md.getY() if self.win.movePointer(0, self.win.getXSize()/2, self.win.getYSize()/2): self.node.setH(self.node.getH() - (x - self.win.getXSize()/2)*0.1) self.Ccentr.setP(self.Ccentr.getP() - (y - self.win.getYSize()/2)*0.1) time.sleep(self.sleep) return task.cont def point_dist(self, p1, p2): return math.sqrt((p1[0]-p2[0])**2+(p1[1]-p2[1])**2+(p1[2]-p2[2])**2)
class SkyBox(DynamicElement): """ SkyBox is only related to render """ ROTATION_MAX = 5000 def __init__(self, pure_background: bool = False): super(SkyBox, self).__init__() self._accumulate = 0 self.f = 1 if not self.render or pure_background: self.node_path = NodePath("pure_background") return skybox = self.loader.loadModel(AssetLoader.file_path("models", "skybox.bam")) skybox.hide(CamMask.MiniMap | CamMask.RgbCam | CamMask.Shadow | CamMask.ScreenshotCam) skybox.set_scale(20000) skybox_texture = self.loader.loadTexture(AssetLoader.file_path("textures", "skybox.jpg")) skybox_texture.set_minfilter(SamplerState.FT_linear) skybox_texture.set_magfilter(SamplerState.FT_linear) skybox_texture.set_wrap_u(SamplerState.WM_repeat) skybox_texture.set_wrap_v(SamplerState.WM_mirror) skybox_texture.set_anisotropic_degree(16) skybox.set_texture(skybox_texture) gles = ConfigVariableString("load-display").getValue() if gles == "pandagles2": skybox_shader = Shader.load( Shader.SL_GLSL, AssetLoader.file_path("shaders", "skybox_gles.vert.glsl"), AssetLoader.file_path("shaders", "skybox_gles.frag.glsl") ) else: if is_mac(): vert_file = "skybox_mac.vert.glsl" frag_file = "skybox_mac.frag.glsl" else: vert_file = "skybox.vert.glsl" frag_file = "skybox.frag.glsl" skybox_shader = Shader.load( Shader.SL_GLSL, AssetLoader.file_path("shaders", vert_file), AssetLoader.file_path("shaders", frag_file) ) skybox.set_shader(skybox_shader) self.node_path = skybox skybox.setZ(-4400) skybox.setH(30) def step(self): if not self.render: return if self._accumulate >= self.ROTATION_MAX: self.f *= -1 self._accumulate = 0 self._accumulate += 1 factor = self.f * (1 - abs(self._accumulate - self.ROTATION_MAX / 2) * 2 / self.ROTATION_MAX) self.node_path.setH(self.node_path.getH() + factor * 0.0035)
def buildRotateAnim(self, unit_model, start_pos, end_pos, start_h, heading=None): if heading == None: dummy_start = NodePath("dummy_start") dummy_end = NodePath("dummy_end") dummy_start.setPos(start_pos) dummy_end.setPos(end_pos) dummy_start.lookAt(dummy_end) end_h = dummy_start.getH(render) else: end_h = utils.getHeadingAngle(heading) interval = unit_model.model.quatInterval(0.2, hpr = Point3(end_h, 0, 0), startHpr = Point3(start_h, 0, 0)) duration = 0.2 return interval, duration, start_pos, end_h
def _runToonThroughSlot(self, toon, slot, goInside=True): helperNode = NodePath('helper') helperNode.reparentTo(toon.getParent()) helperNode.lookAt(self) lookAtH = helperNode.getH(self._model) toonH = toon.getH(self._model) hDiff = abs(lookAtH - toonH) distanceFromElev = toon.getDistance(self._model) moveSpeed = 9.778 anim = 'run' if toon.animFSM.getCurrentState() == 'Sad': moveSpeed *= 0.5 anim = 'sad-walk' runInsideDistance = 20 track = Sequence(Func(toon.stopSmooth), Func(toon.loop, anim, 1.0), Parallel( toon.hprInterval(hDiff / 360.0, Point3(lookAtH, 0, 0), other=self._model, blendType='easeIn'), toon.posInterval(distanceFromElev / moveSpeed, Point3( self._elevatorPoints[slot], 0, 0), other=self._model, blendType='easeIn')), name=toon.uniqueName('runThroughExit'), autoPause=1) if goInside: track.append( Parallel( toon.hprInterval(lookAtH / 360.0, Point3(0, 0, 0), other=self._model, blendType='easeOut'), toon.posInterval(runInsideDistance / moveSpeed, Point3(self._elevatorPoints[slot], runInsideDistance, 0), other=self._model, blendType='easeOut'))) track.append(Func(self._clearToonTrack, toon)) track.append(Func(toon.setAnimState, 'Happy', 1.0)) self._storeToonTrack(toon, track) track.start()
def buildMoveAnim(self, unit_model, start_pos, end_pos, start_h): dummy_start = NodePath("dummy_start") dummy_end = NodePath("dummy_end") duration = 0.0 p = None dummy_start.setPos(start_pos) dummy_end.setPos(end_pos) dummy_start.lookAt(dummy_end) end_h = dummy_start.getH(render) # Model heading is different than movement heading, first create animation that turns model to his destination i_h = None if end_h != start_h: i_h = unit_model.model.quatInterval(0.2, hpr = Point3(end_h, 0, 0), startHpr = Point3(start_h, 0, 0)) i = unit_model.node.posInterval(0.5, end_pos, start_pos) duration += 0.5 if i_h: p = Parallel(i, i_h) else: p = i return p, duration, end_pos, end_h
class Vehicle(ActorNode): def __init__(self, parent=None): ''' Create a new Vehicle node. Physics should be initialized before any instances of Vehicle are created. arguments: parent -- A PandaNode for the vehicle to attach to. Default is None, in which case the Vehicle should be added to the scene graph via NodePath.attachNewNode(). ''' ActorNode.__init__(self, 'VehiclePhysics') base.physicsMgr.attachPhysicalNode(self) self.getPhysicsObject().setMass(MASS) if parent: self.myPath = parent.attachNewNode(self) else: self.myPath = NodePath(self) # Load vehicle model and place in the transparent bin. vehicleModel = loader.loadModel(MODEL_PATH) hull = vehicleModel.find('**/Hull') hull.setBin('transparent', 30) pwnsEnclosure = vehicleModel.find('**/Pwns_Enclosure') pwnsEnclosure.setBin('transparent', 30) self.myPath.setPos(0, 0, -0.0) selectable = self.myPath.attachNewNode(SelectableNode('vehicle sel')) vehicleModel.reparentTo(selectable) # ==== Initialize Physics ==== # thrusterForceNode = ForceNode('ThrusterForce') self.myPath.attachNewNode(thrusterForceNode) self.linearForce = LinearVectorForce(0, 0, 0) self.linearForce.setMassDependent(1) self.angularForce = AngularVectorForce(0, 0, 0) thrusterForceNode.addForce(self.linearForce) thrusterForceNode.addForce(self.angularForce) self.getPhysical(0).addLinearForce(self.linearForce) self.getPhysical(0).addAngularForce(self.angularForce) self.previousXY = (self.myPath.getX(), self.myPath.getY()) self.tm = ThrusterManager() # Add self.updatePhysics to the task manager and run this task as # frequently as possible. self.updatePhysicsTask = taskMgr.add(self.updatePhysics, 'UpdatePhysics') # ==== Initialize Cameras ==== # lens = PerspectiveLens() lens.setNearFar(0.05, 100.0) #Use either FocalLength or Fov. Fov ~40 is about what actual forward cameras are #lens.setFocalLength(0.8) lens.setFov(70, 70) camera = Camera("Forward_left", lens).getPath() camera.reparentTo(vehicleModel.find('**/Forward_Camera')) camera.setX(camera.getX() - 0.1) # Forward cameras 20cm apart camera.setY( camera.getY() + 0.05) # Move in front of torpedo tubes to avoid abstruction camera.setHpr(0, 0, 0) camera = Camera("Forward_right", lens).getPath() camera.reparentTo(vehicleModel.find('**/Forward_Camera')) camera.setX(camera.getX() + 0.1) # Forward cameras 20cm apart camera.setY( camera.getY() + 0.05) # Move in front of torpedo tubes to avoid abstruction camera.setHpr(0, 0, 0) lens = PerspectiveLens() lens.setNearFar(0.05, 100.0) lens.setFocalLength(0.8) camera = Camera("Downward", lens).getPath() camera.reparentTo(vehicleModel.find('**/Downward_Camera')) camera.setHpr(0, -90, 0) #Layout link (to access hydrophone information) self.layout = None #Hydrophone variables self.start_time = time() self.last_hydro_update = time() def setLayout(self, layout): #Add a link to the layout to allow for referencing other objects #This is necessary for the hydrophone addition self.layout = layout def getDepth(self): ''' Returns the depth of the vehicle, in meters. ''' return -0.15 - self.myPath.getZ() def getHeading(self): ''' Returns the heading of the vehicle, in clockwise degrees. ''' # Panda uses counter-clockwise degrees, with the range (-180, 180]. heading = self.myPath.getH() if heading < 0: return -heading elif heading > 0: return 360 - heading else: return 0 def updatePhysics(self, task): ''' Use the motor PWM values calculated by the controller to apply forces to the simulated vehicle. This runs at every frame, so it needs to complete quickly. ''' outputs = shm.kalman.get() self.tm.update(outputs) passive_wrench = vehicle.passive_forces(outputs, self.tm) passive_forces, passive_torques = passive_wrench[:3], \ passive_wrench[3:] # Get motor thrusts thrusts = np.array(self.tm.get_thrusts()) # Add passive forces and torques to that produced by thrusters, # converting them to sub space first. force = self.tm.total_thrust(thrusts) + \ self.tm.orientation.conjugate() * passive_forces torque = self.tm.total_torque(thrusts) + \ self.tm.orientation.conjugate() * passive_torques # Finally apply forces and torques to the model # we also need to account for panda3d's strange coordinate system # (x and y are flipped and z points up (instead of down)) self.linearForce.setVector(force_subspace[1], \ force_subspace[0], \ -force_subspace[2]) # We're supposed to use axis angle here, but I'm being sneaky # and using the torque vector directly, i.e. non normalized axis angle # with the hopes that this LRotationf constructor will figure it out self.angularForce.setQuat(\ LRotationf(LVector3f(torque_subspace[1], \ torque_subspace[0], \ -torque_subspace[2]), 1)) # Update shared variables for controller outputs.heading = self.getHeading() outputs.pitch = self.myPath.getP() outputs.roll = self.myPath.getR() # This velocity is in world space # We need to put it into THRUST CONVENTION SPACE # which we assume kalman outputs in... velocity = self.getPhysicsObject().getVelocity() # Bring the velocity into THRUST CONVENTION SPACE # Don't forget to account for panda's coordinate system velocity = self.tm.heading_quat.conjugate() * \ np.array((velocity.getY(), velocity.getX(), -velocity.getZ())) outputs.velx = velocity[0] outputs.vely = velocity[1] outputs.depth_rate = velocity[2] outputs.depth = self.getDepth() outputs.north = self.myPath.getY() outputs.east = self.myPath.getX() dX = self.myPath.getX() - self.previousXY[0] dY = self.myPath.getY() - self.previousXY[1] # Forward and sway are in THRUST CONVENTION SPACE # don't forget to account for panda's coordinate system dF, dS, dD = self.tm.heading_quat.conjugate() * np.array((dY, dX, 0.0)) outputs.forward += dF outputs.sway += dS # Output some quaternions, accounting for Panda's coordinate system outputs.q0, outputs.q2, outputs.q1, outputs.q3 = self.myPath.getQuat() outputs.q3 *= -1.0 shm.kalman.set(outputs) svHeadingInt.set(self.getHeading()) svDepth.set(self.getDepth()) #XXX: Approximate altitude assuming that the pool is 12 feet deep svAltitude.set(3.6 - self.getDepth()) svDvlDmgNorth.set(self.myPath.getY()) svDvlDmgEast.set(self.myPath.getX()) self.previousXY = (self.myPath.getX(), self.myPath.getY()) #update self.output_hydro_data() return Task.cont def output_hydro_data(self): #Update simulated hydrophone values pingers = [] #Get all pingers from the layout for element in self.layout.elements: if element.getTypeName() == "Pinger": pingers.append(element) HYDRO_TICK_PERIOD = 1 if time() - self.last_hydro_update > HYDRO_TICK_PERIOD: dt = time() - self.last_hydro_update self.last_hydro_update = time() if shm.hydrophones_settings.dsp_mode.get() == 1: #Search mode #Incr search count shm.hydrophones_results.search_count.set( shm.hydrophones_results.search_count.get() + 1) #Generate proper "hydrophone bins" marks sb = 0 for p in pingers: f = p.pinger_frequency dc = (f - (shm.hydrophones_settings.searchCenter.get() - shm.hydrophones_settings.searchDelta.get()) ) / shm.hydrophones_settings.searchStep.get() + 0.5 sb |= 1 << int(dc) shm.hydrophones_results.search_bins.set(sb) else: #Track Mode #Incr ping count shm.hydrophones_results.ping_count.set( shm.hydrophones_results.ping_count.get() + 1) #Determine which pinger we are actively tracking (within 0.7khz of target) targetp = None for p in pingers: if abs(shm.hydrophones_settings.trackFrequency.get() - p.pinger_frequency) < 700: targetp = p if targetp is not None: shm.hydrophones_results.intensity.set( int(shm.hydrophones_settings.trackMagThresh.get() + 1e4 * random())) shm.hydrophones_results.ping_time.set(int(dt * 1000)) pp = targetp.path.getPos() vv = vector.Vector(self.myPath.getY(), self.myPath.getX()) pv = vector.Vector(pp.getY(), pp.getX()) #heading dv = pv - vv ang = vector.GetAuvAngle(dv) hdiff = helpers.heading_diff(self.getHeading(), ang) shm.hydrophones_results.heading.set(hdiff) #elevation dh = self.myPath.getZ() - pp.getZ() dist = vector.Length(dv) elev = math.degrees(math.atan2(dist, dh)) elev = min(elev, 90) shm.hydrophones_results.elevation.set(elev) #phase calculations dy = self.myPath.getY() - pp.getY() dx = self.myPath.getX() - pp.getX() yang = math.degrees(math.atan2(dist, dy)) xang = math.degrees(math.atan2(dist, dx)) shm.hydrophones_results.phaseX.set((90.0 - xang) / 90.0) shm.hydrophones_results.phaseY.set((90.0 - yang) / 90.0) shm.hydrophones_results.phaseZ.set((90.0 - elev) / 90.0) else: shm.hydrophones_results.heading.set(0) shm.hydrophones_results.elevation.set(0) shm.hydrophones_results.intensity.set(0) shm.hydrophones_results.ping_time.set(0) shm.hydrophones_results.uptime.set(int(time() - self.start_time)) def __del__(self): ''' Remove update tasks from the panda task manager. ''' taskMgr.remove(self.updatePhysicsTask) ActorNode.__del__(self)
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2])) self._lookAtZ = self._toon.getHeight( ) + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt=0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / ( maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[ 1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E**(dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr( smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if np not in nodesInBetween: nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: if not np.find('**/*floor_mesh').isEmpty(): np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: if not np.find('**/*Floor').isEmpty(): np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween
class Golem(FSM, DirectObject): def __init__(self): FSM.__init__(self, "FSM-Golem") random.seed() self.golem = loader.loadModel("Golem") self.golem = Actor( "Golem", { "Idle": "Golem-Idle", "Walk": "Golem-Walk", "Attack": "Golem-Attack", "Destroyed": "Golem-Destroyed" }) self.golem.setBlend(frameBlend=True) golemViewSphere = CollisionSphere(0, 0, 0.5, 6) golemViewSphere.setTangible(False) golemViewColNP = self.golem.attachNewNode( CollisionNode('golemViewField')) golemViewColNP.node().addSolid(golemViewSphere) golemHitSphere = CollisionSphere(0, 0, 0.5, 1) golemHitColNP = self.golem.attachNewNode( CollisionNode('golemHitField')) golemHitColNP.node().addSolid(golemHitSphere) # a collision segment to check attacks self.attackCheckSegment = CollisionSegment(0, 0, 1, 0, -1.3, 1) self.golemAttackRay = self.golem.attachNewNode( CollisionNode("golemAttackCollision")) self.golemAttackRay.node().addSolid(self.attackCheckSegment) self.golemAttackRay.node().setIntoCollideMask(0) self.attackqueue = CollisionHandlerQueue() base.cTrav.addCollider(self.golemAttackRay, self.attackqueue) attackAnim = self.golem.actorInterval("Attack", playRate=2) self.AttackSeq = Parallel(attackAnim, Sequence(Wait(0.5), Func(self.ceckAttack))) self.lookatFloater = NodePath(PandaNode("golemTracker")) self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.hide() self.lookatFloater.reparentTo(render) self.trackerObject = loader.loadModel("misc/Pointlight") self.trackerObject.setColor(0, 1, 0) self.trackerObject.setScale(0.25) self.trackerObject.reparentTo(self.lookatFloater) def start(self, startPos): self.golem.setPos(startPos.getPos()) self.golem.setHpr(startPos.getHpr()) self.golem.reparentTo(render) self.trackedEnemy = None self.health = 5 self.accept( "playerCollision-in-golemViewField", lambda extraArgs: base. messenger.send("golemSeesPlayer", [self.golem])) def stop(self): self.trackedEnemy = None taskMgr.remove("GolemAI_task") self.golem.hide() self.ignoreAll() def cleanup(self): self.stop() self.lookatFloater.removeNode() self.golem.cleanup() self.golem.removeNode() def activate(self, trackedEnemy): self.trackedEnemy = trackedEnemy taskMgr.add(self.aiTask, "GolemAI_task") self.lookatFloater.show() def aiTask(self, task): dt = globalClock.getDt() if self.AttackSeq.isPlaying(): return task.cont self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.lookAt(self.trackedEnemy) self.lookatFloater.setH(self.lookatFloater.getH() + 180) self.lookatFloater.setP(0) self.lookatFloater.setR(0) self.golem.lookAt(self.trackedEnemy) self.golem.setH(self.golem.getH() + 180) distanceVec = self.golem.getPos() - self.trackedEnemy.getPos() enemyDist = distanceVec.length() if enemyDist < 2.0: # close enough for combat action = random.choice(["Attack", "Idle"]) if action == "Attack": self.request("Attack") else: if self.state != "Idle": self.request("Idle") else: self.golem.setY(self.golem, -0.5 * dt) if self.state != "Walk": self.request("Walk") return task.cont def hit(self): hitInterval = Sequence(Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15)) self.health -= 1 if self.health == 4: self.trackerObject.setColor(0, 1, 0) hitInterval.start() elif self.health == 3: self.trackerObject.setColor(0.25, 0.75, 0) hitInterval.start() elif self.health == 2: self.trackerObject.setColor(0.5, .5, 0) hitInterval.start() elif self.health == 1: self.trackerObject.setColor(0.75, 0.25, 0) hitInterval.start() elif self.health == 0: self.trackerObject.setColor(0, 0, 0) self.request("Destroyed") def ceckAttack(self): for i in range(self.attackqueue.getNumEntries()): entry = self.attackqueue.getEntry(i) into = entry.getIntoNode() if "playerCollision" in into.getName(): if random.random() > .5: base.messenger.send("HitPlayer") def enterIdle(self): self.golem.loop("Idle") def enterWalk(self): self.golem.setPlayRate(2, "Walk") self.golem.loop("Walk") def enterAttack(self): self.AttackSeq.start() def enterDestroyed(self): self.ignoreAll() taskMgr.remove("GolemAI_task") self.AttackSeq.finish() self.golem.play("Destroyed") self.lookatFloater.hide() base.messenger.send("GolemDestroyed")
class Maleficium(ShowBase): def __init__(self): compressedTextures = ConfigVariableString('compressed-textures','1') # Compresses Textures on load (increases loadtime / framerate) ShowBase.__init__(self) ## Debug Values (True/False) self.fpsMeter = True debug.checkDebugSettings(self) self.KeyBindings() ## Load World world.load('prisonCrater') ## Add Player to World self.playerBox = NodePath('player') self.player = Actor("data/models/hm.bam", {"run":"data/models/hm-run.bam", "idle":"data/models/hm.bam"}) self.player.reparentTo(self.playerBox) self.player.setScale(.01) self.playerBox.reparentTo(render) self.isMoving = False ## Create Camera base.disableMouse() self.cameratarget = self.render.attachNewNode('Camera Target') base.camera.setPos(self.playerBox.getX(),self.playerBox.getY()+20,self.playerBox.getZ()+5) self.cameratarget.setPos(self.playerBox.getX(),self.playerBox.getY(),self.playerBox.getZ()+6) self.radius = 10 self.XYAngle = .028 self.ZAngle = .01 ## Set Up Ground Collisions ## Player Collision base.cTrav = CollisionTraverser() self.ColHandler = CollisionHandlerFloor() self.colGroundRay = CollisionNode('colGroundRay') self.colGroundRay.addSolid(CollisionRay(0,0,2,0,0,-1)) self.playerCol = self.playerBox.attachNewNode(self.colGroundRay) base.cTrav.addCollider(self.playerCol,self.ColHandler) self.ColHandler.addCollider(self.playerCol,self.playerBox) ## Add main Game Loop to taskmanager taskMgr.add(self.gameLoop,'mainLoop') ### Input Structure; Coded by Darren Kent (Modeled after Roaming-Ralph by Ryan Myers) def KeyBindings(self): ## Setup Map self.startRightClick = True self.keyMap = { "forward":0, "backward":0, "turn_left":0, "turn_right":0, "strafe_left":0, "strafe_right":0, "cam_up":0, "cam_down":0, "cam_right":0, "cam_left":0, "zoom_in":0, "zoom_out":0, "right_click":0, "wheel_zoom_in":0, "wheel_zoom_out":0, } ## Accept Keys self.accept('escape',sys.exit) self.accept('w', self.setKey, ['forward',1]) self.accept('w-up', self.setKey, ['forward',0]) self.accept('s', self.setKey, ['backward',1]) self.accept('s-up', self.setKey, ['backward',0]) self.accept('a', self.setKey, ['turn_left',1]) self.accept('a-up', self.setKey, ['turn_left',0]) self.accept('d', self.setKey, ['turn_right',1]) self.accept('d-up', self.setKey, ['turn_right',0]) self.accept('q', self.setKey, ['strafe_left',1]) self.accept('q-up', self.setKey, ['strafe_left',0]) self.accept('e', self.setKey, ['strafe_right',1]) self.accept('e-up', self.setKey, ['strafe_right',0]) self.accept('arrow_up', self.setKey, ['cam_down',1]) self.accept('arrow_up-up', self.setKey, ['cam_down',0]) self.accept('arrow_down', self.setKey, ['cam_up',1]) self.accept('arrow_down-up', self.setKey, ['cam_up',0]) self.accept('arrow_right', self.setKey, ['cam_right',1]) self.accept('arrow_right-up', self.setKey, ['cam_right',0]) self.accept('arrow_left', self.setKey, ['cam_left',1]) self.accept('arrow_left-up', self.setKey, ['cam_left',0]) self.accept('[', self.setKey, ['zoom_in',1]) self.accept('[-up', self.setKey, ['zoom_in',0]) self.accept(']', self.setKey, ['zoom_out',1]) self.accept(']-up', self.setKey, ['zoom_out',0]) ## Accept Mouse self.accept('mouse3',self.setKey, ['right_click',1]) self.accept('mouse3-up',self.setKey, ['right_click',0]) self.accept('wheel_up',self.setKey, ['wheel_zoom_in',1]) self.accept('wheel_down',self.setKey, ['wheel_zoom_out',1]) ### Set Key Presses; Coded by Darren Kent (Modeled after Roaming-Ralph by Ryan Myers) def setKey(self,key,value): self.keyMap[key] = value ### Main Game Loop; Coded by Darren Kent def gameLoop(self,task): ## Keyboard Camera Controls if (self.keyMap["cam_left"]!=0): self.XYAngle += .002 if (self.keyMap["cam_right"]!=0): self.XYAngle -= .002 if (self.keyMap["cam_up"] != 0): if self.ZAngle <= .045: self.ZAngle += .001 if (self.keyMap["cam_down"] != 0): if self.ZAngle >= .002: self.ZAngle -= .001 if (self.keyMap["zoom_in"] != 0): if self.radius >= 4: self.radius -= 1 self.setRadius = self.radius if (self.keyMap["zoom_out"] != 0): if self.radius <= 40: self.radius += 1 self.setRadius = self.radius ## Mouse Camera Controls if (self.keyMap["right_click"]!=0): if self.startRightClick == True: self.startRightClick = False self.tempMouseX = base.mouseWatcherNode.getMouseX() self.tempMouseY = base.mouseWatcherNode.getMouseY() self.tempXAngle = self.XYAngle self.tempZAngle = self.ZAngle self.tempPlayerH = self.playerBox.getH() elif self.startRightClick == False: Ztemp = self.tempZAngle + (base.mouseWatcherNode.getMouseY() - self.tempMouseY) / 20 self.XYAngle = self.tempXAngle - (base.mouseWatcherNode.getMouseX() - self.tempMouseX) / 20 if Ztemp >= .045: Ztemp = .045 if Ztemp <= 0.002: Ztemp = 0.002 self.ZAngle = Ztemp else: self.startRightClick = True if (self.keyMap["wheel_zoom_in"] != 0): if self.radius >= 7: self.radius -= 3 self.setRadius = self.radius if (self.keyMap["wheel_zoom_out"] != 0): if self.radius <= 38: self.radius += 2 self.setRadius = self.radius self.setKey("wheel_zoom_out",0) self.setKey("wheel_zoom_in", 0) ## Reposition Camera x = self.cameratarget.getX() + self.radius * math.sin(math.degrees(self.ZAngle)) * math.cos(math.degrees(self.XYAngle)) y = self.cameratarget.getY() + self.radius * math.sin(math.degrees(self.ZAngle)) * math.sin(math.degrees(self.XYAngle)) z = self.cameratarget.getZ() + self.radius * math.cos(math.degrees(self.ZAngle)) base.camera.setPos(x,y,z) base.camera.lookAt(self.cameratarget) self.cameratarget.setPos(self.playerBox.getX(),self.playerBox.getY(),self.playerBox.getZ()+6) ## Keyboard Movement Controls if (self.keyMap["turn_left"]!=0): self.playerBox.setH(self.playerBox.getH() + 200 * globalClock.getDt()) if (self.keyMap["turn_right"]!=0): self.playerBox.setH(self.playerBox.getH() - 200 * globalClock.getDt()) if (self.keyMap["strafe_left"]!=0): self.playerBox.setX(self.playerBox, +20 * globalClock.getDt()) if (self.keyMap["strafe_right"]!=0): self.playerBox.setX(self.playerBox, -20 * globalClock.getDt()) if (self.keyMap["forward"]!=0): self.playerBox.setY(self.playerBox, -25 * globalClock.getDt()) if (self.keyMap["backward"] != 0): self.playerBox.setY(self.playerBox, +15 * globalClock.getDt()) if (self.keyMap["forward"]!=0): if self.isMoving == False: self.player.setPlayRate(2.5,'run') self.player.loop('run') self.isMoving = True else: if self.isMoving: self.player.setPlayRate(1,'idle') self.player.loop('idle') self.isMoving = False ## Check Collisions return task.cont
class PartyCog(FSM): notify = directNotify.newCategory('PartyCog') HpTextGenerator = TextNode('HpTextGenerator') hpText = None height = 7 def __init__(self, parentNode, id, bounceSpeed=3, bounceHeight=1, rotateSpeed=1, heightShift=1, xMoveSpeed=0, xMoveDistance=0, bounceOffset=0): self.id = id FSM.__init__(self, 'PartyCogFSM-%d' % self.id) self.showFacingStatus = False self.xMoveSpeed = xMoveSpeed self.xMoveDistance = xMoveDistance self.heightShift = heightShift self.bounceSpeed = bounceSpeed self.bounceHeight = bounceHeight self.rotateSpeed = rotateSpeed self.parentNode = parentNode self.bounceOffset = bounceOffset self.hitInterval = None self.kaboomTrack = None self.resetRollIval = None self.netTimeSentToStartByHit = 0 self.load() self.request('Down') return def load(self): self.root = NodePath('PartyCog-%d' % self.id) self.root.reparentTo(self.parentNode) path = 'phase_13/models/parties/cogPinata_' self.actor = Actor( path + 'actor', { 'idle': path + 'idle_anim', 'down': path + 'down_anim', 'up': path + 'up_anim', 'bodyHitBack': path + 'bodyHitBack_anim', 'bodyHitFront': path + 'bodyHitFront_anim', 'headHitBack': path + 'headHitBack_anim', 'headHitFront': path + 'headHitFront_anim' }) self.actor.reparentTo(self.root) self.temp_transform = Mat4() self.head_locator = self.actor.attachNewNode('temphead') self.bodyColl = CollisionTube(0, 0, 1, 0, 0, 5.75, 0.75) self.bodyColl.setTangible(1) self.bodyCollNode = CollisionNode('PartyCog-%d-Body-Collision' % self.id) self.bodyCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.bodyCollNode.addSolid(self.bodyColl) self.bodyCollNodePath = self.root.attachNewNode(self.bodyCollNode) self.headColl = CollisionTube(0, 0, 3, 0, 0, 3.0, 1.5) self.headColl.setTangible(1) self.headCollNode = CollisionNode('PartyCog-%d-Head-Collision' % self.id) self.headCollNode.setCollideMask(ToontownGlobals.PieBitmask) self.headCollNode.addSolid(self.headColl) self.headCollNodePath = self.root.attachNewNode(self.headCollNode) self.arm1Coll = CollisionSphere(1.65, 0, 3.95, 1.0) self.arm1Coll.setTangible(1) self.arm1CollNode = CollisionNode('PartyCog-%d-Arm1-Collision' % self.id) self.arm1CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm1CollNode.addSolid(self.arm1Coll) self.arm1CollNodePath = self.root.attachNewNode(self.arm1CollNode) self.arm2Coll = CollisionSphere(-1.65, 0, 3.45, 1.0) self.arm2Coll.setTangible(1) self.arm2CollNode = CollisionNode('PartyCog-%d-Arm2-Collision' % self.id) self.arm2CollNode.setCollideMask(ToontownGlobals.PieBitmask) self.arm2CollNode.addSolid(self.arm2Coll) self.arm2CollNodePath = self.root.attachNewNode(self.arm2CollNode) splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splatType = globalPropPool.getPropType(splatName) self.pieHitSound = globalBattleSoundCache.getSound( 'AA_wholepie_only.ogg') self.upSound = globalBattleSoundCache.getSound('AV_jump_to_side.ogg') self.hole = loader.loadModel('phase_13/models/parties/cogPinataHole') self.hole.setTransparency(True) self.hole.setP(-90.0) self.hole.setScale(3) self.hole.setBin('ground', 3) self.hole.reparentTo(self.parentNode) def unload(self): self.request('Off') self.clearHitInterval() if self.hole is not None: self.hole.removeNode() self.hole = None if self.actor is not None: self.actor.cleanup() self.actor.removeNode() self.actor = None if self.root is not None: self.root.removeNode() self.root = None if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.kaboomTrack = None if self.resetRollIval is not None and self.resetRollIval.isPlaying(): self.resetRollIval.finish() self.resetRollIval = None if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.finish() self.hitInterval = None del self.upSound del self.pieHitSound return def enterStatic(self): pass def exitStatic(self): pass def enterActive(self, startTime): self.root.setR(0.0) updateTask = Task.Task(self.updateTask) updateTask.startTime = startTime taskMgr.add(updateTask, 'PartyCog.update-%d' % self.id) def exitActive(self): taskMgr.remove('PartyCog.update-%d' % self.id) taskMgr.remove('PartyCog.bounceTask-%d' % self.id) self.clearHitInterval() self.resetRollIval = self.root.hprInterval(0.5, Point3( self.root.getH(), 0.0, 0.0), blendType='easeInOut') self.resetRollIval.start() self.actor.stop() def enterDown(self): if self.oldState == 'Off': downAnimControl = self.actor.getAnimControl('down') self.actor.pose('down', downAnimControl.getNumFrames() - 1) return self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpFunc(self.setAlongSpline, duration=1.0, fromData=self.currentT, toData=0.0), LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'down', loop=0)), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def exitDown(self): self.root.setR(0.0) self.root.setH(0.0) self.targetDistance = 0.0 self.targetFacing = 0.0 self.currentT = 0.0 self.setAlongSpline(0.0) self.clearHitInterval() startScale = self.hole.getScale() endScale = Point3(5, 5, 5) self.hitInterval = Sequence( LerpScaleInterval(self.hole, duration=0.175, scale=endScale, startScale=startScale, blendType='easeIn'), Parallel( SoundInterval(self.upSound, volume=0.6, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), ActorInterval(self.actor, 'up', loop=0)), Func(self.actor.loop, 'idle'), LerpScaleInterval(self.hole, duration=0.175, scale=Point3(3, 3, 3), startScale=endScale, blendType='easeOut')) self.hitInterval.start() def filterDown(self, request, args): if request == 'Down': return None else: return self.defaultFilter(request, args) return None def setEndPoints(self, start, end, amplitude=1.7): self.sinAmplitude = amplitude self.sinPeriod = (end.getX() - start.getX()) / 2 self.sinDisplacement = start.getY() self.startPoint = start self.endPoint = end self.currentT = 0.0 self.targetDistance = 0.0 self.currentFacing = 0.0 self.targetFacing = 0.0 self.setAlongSpline(self.currentT) self.hole.setPos(self.root.getPos()) self.hole.setZ(0.02) def rockBackAndForth(self, task): t = task.startTime + task.time angle = math.sin(t) * 20.0 self.root.setR(angle) return task.cont def updateDistance(self, distance): self.targetDistance = clamp(distance, -1.0, 1.0) def updateTask(self, task): self.rockBackAndForth(task) if self.targetDistance > self.currentT: self.currentT += min(0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) elif self.targetDistance < self.currentT: self.currentT += max(-0.01, self.targetDistance - self.currentT) self.setAlongSpline(self.currentT) if self.currentT < 0.0: self.targetFacing = -90.0 elif self.currentT > 0.0: self.targetFacing = 90.0 else: self.targetFacing = 0.0 if self.targetFacing > self.currentFacing: self.currentFacing += min(10, self.targetFacing - self.currentFacing) elif self.targetFacing < self.currentFacing: self.currentFacing += max(-10, self.targetFacing - self.currentFacing) self.root.setH(self.currentFacing) return task.cont def setAlongSpline(self, t): t = t + 1.0 dist = (self.endPoint.getX() - self.startPoint.getX()) / 2.0 x = self.startPoint.getX() + t * dist y = self.startPoint.getY() - math.sin( t * 2 * math.pi) * self.sinAmplitude self.root.setPos(x, y, 0) def startBounce(self): taskMgr.add(self.bounce, 'PartyCog.bounceTask-%d' % self.id) def bounce(self, task): self.root.setZ( math.sin((self.bounceOffset + task.time) * self.bounceSpeed) * self.bounceHeight + self.heightShift) return task.cont def setPos(self, position): self.root.setPos(position) def respondToPieHit(self, timestamp, position, hot=False, direction=1.0): if self.netTimeSentToStartByHit < timestamp: self.__showSplat(position, direction, hot) if self.netTimeSentToStartByHit < timestamp: self.netTimeSentToStartByHit = timestamp else: self.notify.debug( 'respondToPieHit self.netTimeSentToStartByHit = %s' % self.netTimeSentToStartByHit) def clearHitInterval(self): if self.hitInterval is not None and self.hitInterval.isPlaying(): self.hitInterval.clearToInitial() return def __showSplat(self, position, direction, hot=False): if self.kaboomTrack is not None and self.kaboomTrack.isPlaying(): self.kaboomTrack.finish() self.clearHitInterval() splatName = 'splat-creampie' self.splat = globalPropPool.getProp(splatName) self.splat.setBillboardPointEye() self.splat.reparentTo(render) self.splat.setPos(self.root, position) self.splat.setAlphaScale(1.0) if not direction == 1.0: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[0]) if self.currentFacing > 0.0: facing = 'HitFront' else: facing = 'HitBack' else: self.splat.setColorScale(PartyGlobals.CogActivitySplatColors[1]) if self.currentFacing > 0.0: facing = 'HitBack' else: facing = 'HitFront' if hot: targetscale = 0.75 part = 'head' else: targetscale = 0.5 part = 'body' def setSplatAlpha(amount): self.splat.setAlphaScale(amount) self.hitInterval = Sequence( ActorInterval(self.actor, part + facing, loop=0), Func(self.actor.loop, 'idle')) self.hitInterval.start() self.kaboomTrack = Parallel( SoundInterval(self.pieHitSound, volume=1.0, node=self.actor, cutOff=PartyGlobals.PARTY_COG_CUTOFF), Sequence( Func(self.splat.showThrough), Parallel( Sequence( LerpScaleInterval(self.splat, duration=0.175, scale=targetscale, startScale=Point3(0.1, 0.1, 0.1), blendType='easeOut'), Wait(0.175)), Sequence( Wait(0.1), LerpFunc(setSplatAlpha, duration=1.0, fromData=1.0, toData=0.0, blendType='easeOut'))), Func(self.splat.cleanup), Func(self.splat.removeNode))) self.kaboomTrack.start() return def showHitScore(self, number, scale=1): if number <= 0: return if self.hpText: self.hideHitScore() self.HpTextGenerator.setFont(ToontownGlobals.getSignFont()) if number < 0: self.HpTextGenerator.setText(str(number)) else: self.HpTextGenerator.setText('+' + str(number)) self.HpTextGenerator.clearShadow() self.HpTextGenerator.setAlign(TextNode.ACenter) r = 1 g = 1 b = 0 a = 1 self.HpTextGenerator.setTextColor(r, g, b, a) self.hpTextNode = self.HpTextGenerator.generate() self.hpText = render.attachNewNode(self.hpTextNode) self.hpText.setScale(scale) self.hpText.setBillboardPointEye() self.hpText.setBin('fixed', 100) self.hpText.setPos(self.root, 0, 0, self.height / 2) seq = Sequence( self.hpText.posInterval( 0.25, Point3(self.root.getX(render), self.root.getY(render), self.root.getZ(render) + self.height + 1.0), blendType='easeOut'), Wait(0.25), self.hpText.colorInterval(0.1, Vec4(r, g, b, 0)), Func(self.hideHitScore)) seq.start() def hideHitScore(self): if self.hpText: taskMgr.remove('PartyCogHpText' + str(self.id)) self.hpText.removeNode() self.hpText = None return def getHeadLocation(self): self.actor.getJoints(jointName='head')[0].getNetTransform( self.temp_transform) self.head_locator.setMat(self.temp_transform) return self.head_locator.getZ(self.root)
class CameraControl(DirectObject, HasKeybinds): """ adds controls to a given camera, usually base.camera""" def __init__(self, camera=None): #camera setup self.camera = camera if self.camera == None: self.camera = base.camera #XXX note, when moving cam target we need to make sure the camera doesnt move too... cameraBase = GeomNode('cameraBase') #utility node for pan targetGeom = makeCameraTarget() cameraBase.addGeom(targetGeom) self.cameraBase = render.attachNewNode(cameraBase) #self.cameraBase.setTwoSided(True) #backface culling issue with my tristrip fail self.cameraTarget = NodePath( 'cameraTarget') #utility node for rot, zoom, reattach self.cameraTarget.reparentTo(self.cameraBase) #self.cameraTarget.reparentTo(render) self.camera.reparentTo(self.cameraTarget) self.track = self.camera.attachNewNode( 'track') #hack for pointing vector self.track.setPos(LVecBase3f(0, 50, 0)) #nn = GeomNode('helper') #ng = makeCameraTarget() #nn.addGeom(targetGeom) #self.track.attachNewNode(nn) #keybind setup self.__ends__ = defaultdict(list) #self.accept("escape", sys.exit) #no, exit_cleanup will handle this... for function_name, key in keybinds['view'].items(): #self.accept(key,taskMgr.add,(getattr(self,function),function+'Task')) self.accept( key, self.makeTask, [function_name ]) # TODO split out functions that don't require tasks keytest = key.split('-')[-1] #print(keytest) if keytest in {'mouse1', 'mouse2', 'mouse3'}: self.addEndTask(keytest, function_name) self.accept(keytest + '-up', self.endTask, [keytest, function_name]) #gains #TODO tweak me! self.XGAIN = .01 self.YGAIN = .01 #window setup self.getWindowSize() self.accept('window-event', self.getWindowSize) #self.accept('mouse1') #mouse 1 by itself does selection? #self.accpet('mouse3') #pan #self.accpet('mouse2') #--camera moves relatvie to arbitrary origin-- #pan in plane #zoom #this needs to be on a log scale, linear is balls #rotate #--camera in place-- #roll camera in place #yaw #pitch #look at selection/origin/center of mass of #--camera lense changes-- #fov (for perspective) #perspective/orthographic #--worldcraft-- #z mode wasd + mouse to orient for zooming #--selection functions we need to leave space for-- #drop origin if we don't have something selected #click select #drag select, logial intersec #right click for menu self.__ch__ = None self.__cp__ = None self.__cr__ = None self.__cth__ = None self.__ctp__ = None pass def getWindowSize(self, wat=None): self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() #print(self.__winx__,self.__winy__) def makeTask(self, function_name): """ ye old task spawner """ if hasattr(self, function_name): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() setattr(self, '__%sTask_s__' % function_name, (x, y)) #this should be faster taskMgr.add(getattr(self, function_name), function_name + 'Task') else: raise KeyError( 'Check your keybinds, there is no function by that name here!') def addEndTask(self, key, function_name): self.__ends__[key].append(function_name) def endTask(self, key, function): for func in self.__ends__[key]: taskMgr.remove(func + 'Task') setattr(self, '__%sTask_s__' % func, None) #this should be faster self.__ch__ = None #FIXME this seems hackish self.__cp__ = None self.__cr__ = None self.__cth__ = None self.__ctp__ = None def getMouseDdDt(self, name): #XXX deprecated """ use gain to adjust pixels per degree this should probably be normalized to screen size actually? or no... but to what? """ if base.mouseWatcherNode.hasMouse(): x, z = base.mouseWatcherNode.getMouse() sx, sz = getattr(self, '__%s_start__' % name) print(x, sx) print(z, sz) if z != sz or x != sx: #watch out for aliasing here... norm = (((x - sx) * self.XGAIN)**2 + ((z - sz) * self.YGAIN)**2)**.5 #norm = ((x - sx) * self.X_GAIN), ((z - sz) * self.Y_GAIN) setattr(self, '__%s_start__' % name, (x, z)) return norm else: #mouse has not moved return 0 def getMouseDdDf(self, name): if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() sx, sy = getattr(self, '__%s_s__' % (name)) dx = (x - sx) * self.XGAIN * self.__winx__ dy = (y - sy) * self.YGAIN * self.__winy__ return dx, dy def getMouseCross( self, name ): #FIXME may need to do this incrementally as we started with... if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() sx, sy = getattr(self, '__%s_s__' % (name)) dx = (x - sx) * self.XGAIN * self.__winx__ dy = (y - sy) * self.YGAIN * self.__winy__ norm = (dx**2 + dy**2)**.5 cross = x * sy - y * sx return cross * norm @event_callback def home(self, task): self.camera.lookAt(self.cameraBase) taskMgr.remove(task.getName()) return task.cont @event_callback def pan(self, task): """ I don't like it, it's weird! """ invert = -1 magic_number = 15 magic_number = 20 if base.mouseWatcherNode.hasMouse(): x, y = base.mouseWatcherNode.getMouse() sx, sy = getattr(self, '__%s_s__' % (task.getName())) dx = (x - sx) * self.XGAIN * self.__winx__ * magic_number * invert dy = (y - sy) * self.YGAIN * self.__winy__ * magic_number * invert #cx,cy,cz = self.camera.getPos() self.camera.setPos(self.camera, dx, 0, dy) setattr( self, '__%s_s__' % task.getName(), (x, y) ) #reset each frame to compensate for moving from own position #nx,ny,nz = self.camera.getPos() #dx2, dy2, dz2 = nx-cx, ny-cy, nz-cz #self.camera.setPos(cx,cz,cy) #self.cameraBase.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera #self.cameraTarget.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera return task.cont @event_callback def zoom_in_slow(self, task, speed=10): return self.zoom_in( task, speed) #hehe this will work because it just passes the task :) @event_callback def zoom_out_slow(self, task, speed=10): return self.zoom_out(task, speed) @event_callback def zoom_in_fast(self, task, speed=1000): return self.zoom_in( task, speed) #hehe this will work because it just passes the task :) @event_callback def zoom_out_fast(self, task, speed=1000): return self.zoom_out(task, speed) @event_callback def zoom_in( self, task, speed=100 ): #FIXME zoom_in and zoom_out still get custom xys even thought they don't use them! self.camera.setPos(self.camera, 0, speed, 0) taskMgr.remove(task.getName()) return task.cont @event_callback def zoom_out(self, task, speed=100): self.camera.setPos(self.camera, 0, -speed, 0) taskMgr.remove( task.getName() ) #we do it this way instead of addOnce because we want to add all the tasks in one go return task.cont @event_callback def rotate(self, task ): #FIXME disregard orientation acqurie proper mouse movements! dx, dy = self.getMouseDdDf(task.getName()) if self.__cth__ == None: self.__cth__ = self.cameraTarget.getH() if self.__ctp__ == None: self.__ctp__ = self.cameraTarget.getP() self.cameraTarget.setH(self.__cth__ - dx * 10) self.cameraTarget.setP(self.__ctp__ + dy * 10) return task.cont #if we are in camera mode @event_callback def pitch(self, task): dx, dy = self.getMouseDdDf(task.getName()) print('got pitch', dy) return task.cont @event_callback def look(self, task): #AKA heading in hpr dx, dy = self.getMouseDdDf(task.getName()) if self.__ch__ == None: self.__ch__ = self.camera.getH() if self.__cp__ == None: self.__cp__ = self.camera.getP() self.camera.setH(self.__ch__ - dx) self.camera.setP( self.__cp__ + dy) #FIXME when we're clicking this might should be inverted? return task.cont @event_callback def roll(self, task): """ ALWAYS roll with respect to axis of rotation""" if self.__cr__ == None: self.__cr__ = self.cameraTarget.getR() #cross product idiot cross = self.getMouseCross(task.getName()) self.cameraTarget.setR(self.__cr__ - cross * 10) return task.cont
class Player(DirectObject): def __init__(self, _main): self.main = _main # Stats self.moveSpeed = 8 self.inventory = [] self.maxCarryWeight = 20.0 #kg ? self.currentInventoryWeight = 0.0 # Inventory GUI self.inventoryGui = Inventory() self.inventoryGui.hide() self.inventoryActive = False self.craftInventory = CraftInventory() self.craftInventory.hide() # enable movements through the level self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} self.player = NodePath("Player")#loader.loadModel("smiley") self.player.setPos(149.032, 329.324, 11.3384) self.player.setH(180) self.player.reparentTo(render) self.accept("w", self.setKey, ["forward",1]) self.accept("w-up", self.setKey, ["forward",0]) self.accept("a", self.setKey, ["left",1]) self.accept("a-up", self.setKey, ["left",0]) self.accept("s", self.setKey, ["backward",1]) self.accept("s-up", self.setKey, ["backward",0]) self.accept("d", self.setKey, ["right",1]) self.accept("d-up", self.setKey, ["right",0]) self.accept("mouse1", self.handleLeftMouse) self.accept("i", self.toggleInventory) self.accept("c", self.toggleCraftInventory) # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 camera.setH(180) camera.reparentTo(self.player) camera.setZ(self.player, 2) base.camLens.setFov(75) base.camLens.setNear(0.8) # Mouse controls self.mouseNode = CollisionNode('mouseRay') self.mouseNodeNP = camera.attachNewNode(self.mouseNode) self.mouseNode.setFromCollideMask(GeomNode.getDefaultCollideMask()) self.mouseRay = CollisionRay() self.mouseNode.addSolid(self.mouseRay) self.mouseRayHandler = CollisionHandlerQueue() # Collision Traverser self.traverser = CollisionTraverser("Player Traverser") base.cTrav = self.traverser self.traverser.addCollider(self.mouseNodeNP, self.mouseRayHandler) def run(self): taskMgr.add(self.move, "moveTask", priority=-4) def pause(self): taskMgr.remove("moveTask") def setKey(self, key, value): self.keyMap[key] = value def move(self, task): if not base.mouseWatcherNode.hasMouse(): return task.cont pointer = base.win.getPointer(0) mouseX = pointer.getX() mouseY = pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): # calculate the looking up/down of the camera. # NOTE: for first person shooter, the camera here can be replaced # with a controlable joint of the player model p = camera.getP() - (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 camera.setP(p) # rotate the player's heading according to the mouse x-axis movement h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) # basic movement of the player if self.keyMap["left"] != 0: self.player.setX(self.player, self.moveSpeed * globalClock.getDt()) if self.keyMap["right"] != 0: self.player.setX(self.player, -self.moveSpeed * globalClock.getDt()) if self.keyMap["forward"] != 0: self.player.setY(self.player, -self.moveSpeed * globalClock.getDt()) if self.keyMap["backward"] != 0: self.player.setY(self.player, self.moveSpeed * globalClock.getDt()) # keep the player on the ground elevation = self.main.t.terrain.getElevation(self.player.getX(), self.player.getY()) self.player.setZ(elevation*self.main.t.zScale) return task.cont def toggleInventory(self): if self.inventoryActive: self.inventoryGui.hide() self.inventoryActive = False self.run() else: self.inventoryGui.show() self.inventoryActive = True self.pause() def toggleCraftInventory(self): if self.inventoryActive: self.craftInventory.hide() self.inventoryActive = False self.run() else: self.craftInventory.updateList(self.inventory) self.craftInventory.show() self.inventoryActive = True self.pause() def handleLeftMouse(self): # Do the mining if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.mouseRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.traverser.traverse(render) # Assume for simplicity's sake that myHandler is a CollisionHandlerQueue. if self.mouseRayHandler.getNumEntries() > 0: # This is so we get the closest object. self.mouseRayHandler.sortEntries() pickedObj = self.mouseRayHandler.getEntry(0).getIntoNodePath() # Range check if (self.player.getPos() - pickedObj.getPos(render)).length() <= 3.0: self.mine(pickedObj) else: print "You are to far, move closer!" def mine(self, _nodeNP): self.nodeNP = _nodeNP # get the object class for node in self.main.nodeGen.currentNodes: if self.main.nodeGen.currentNodes[node] in self.inventory: print "new Loot:", self.main.nodeGen.currentNodes[node].giveLoot() self.inventory.append(self.main.nodeGen.currentNodes[node]) if self.main.nodeGen.currentNodes[node].lootLeft == 0: self.main.nodeGen.currentNodes[node].removeModel() break break # if mining node else: if self.main.nodeGen.currentNodes[node].model and self.main.nodeGen.currentNodes[node].model.getPos() == self.nodeNP.getPos(render): #self.main.nodeGen.currentNodes[node].removeModel() self.inventory.append(self.main.nodeGen.currentNodes[node]) self.currentInventoryWeight += self.main.nodeGen.currentNodes[node].weight self.inventoryGui.updateList(self.inventory) print "You received:", self.main.nodeGen.currentNodes[node].giveLoot(), self.main.nodeGen.currentNodes[node].giveType(), "Ores" print "Inventory:", self.inventory print "Current Weight:", self.currentInventoryWeight break print self.player.getPos()
class Player(object): """ Player is the main actor in the fps game """ FORWARD = Vec3(0,2,0) BACK = Vec3(0,-1,0) LEFT = Vec3(-1,0,0) RIGHT = Vec3(1,0,0) FLYUP = Vec3(0,0,1) FLYDN = Vec3(0,0,-1) STOP = Vec3(0) PORTAL_CYCLE = { 'blue' : 'orange', 'orange' : 'blue', } def __init__(self, base, fps, osd): self.base = base self.fps = fps self.osd = osd self.speed = RUN_SPEED self.walk = self.STOP self.readyToJump = False self.intoPortal = None self.mass = Mass() self.origin = self.fps.level.settings.origin self.bporigin = (999,999,999) self.oporigin = (999,999,999) self.current_target = None self.canPortal = [] self.canSetTarget = True self.selectedCubes = [] self.editorTextureStage = TextureStage('editor') self.editorSelectedTexture = loader.loadTexture('models/tex/selected.png') self.selectingForMulti = False # Init functions self.loadModel() self.makePortals() self.setUpCamera() if self.fps.editor_mode: self.createMouseCollisions() self.speed = self.speed * 5 self.attachEditorControls() self.attachEditorTasks() else: self.createCollisions() self.attachStandardControls() self.attachStandardTasks() def loadModel(self): """ make the nodepath for player """ self.node = NodePath('player') self.node.reparentTo(render) self.node.setPos(*self.origin) self.node.setScale(0.05) self.mass.pos = VBase3(self.node.getX(), self.node.getY(), self.node.getZ()) def makePortals(self): # The BLUE CUBE bpor = loader.loadModel("cube_nocol") bpor.setTag('noportals', '1') bpor.reparentTo(render) bpor.setPos(*self.bporigin) bpor.setScale(0.3,0.02,0.5) # The BLUE CUBE's camera bbuffer = self.base.win.makeTextureBuffer("B Buffer", 512, 512) bbuffer.setSort(-100) bcamera = self.base.makeCamera(bbuffer) bcamera.node().getLens().setAspectRatio(0.3/0.5) bcamera.node().getLens().setFov(15) bcamera.reparentTo(bpor) bcamera.node().setScene(render) # The ORANGE CUBE opor = loader.loadModel("cube_nocol") opor.setTag('noportals', '1') opor.reparentTo(render) opor.setPos(*self.oporigin) opor.setScale(0.3,0.02,0.5) # The ORANGE CUBE's camera obuffer = self.base.win.makeTextureBuffer("O Buffer", 512, 512) obuffer.setSort(-100) ocamera = self.base.makeCamera(obuffer) ocamera.node().getLens().setAspectRatio(0.3/0.5) ocamera.node().getLens().setFov(15) ocamera.reparentTo(opor) ocamera.node().setScene(render) # Assign the textures bpor.setTexture(obuffer.getTexture()) opor.setTexture(bbuffer.getTexture()) # Store the portals and theirs cameras self.bluePortal = bpor self.bluePortal.setHpr(0,90,0) self.orangePortal = opor self.orangePortal.setHpr(0,-90,0) self.bcamera = bcamera self.ocamera = ocamera def setUpCamera(self): """ puts camera at the players node """ pl = self.base.cam.node().getLens() pl.setFov(70) self.base.cam.node().setLens(pl) self.base.camera.reparentTo(self.node) self.base.camLens.setFov(100) if self.fps.editor_mode: self.node.lookAt(self.fps.level.cubes_hash.keys()[0]) def createCollisions(self): self.createPlayerCollisions() self.createMouseCollisions() self.createPortalCollisions() def createPlayerCollisions(self): """ create a collision solid and ray for the player """ cn = CollisionNode('player') cn.setFromCollideMask(COLLISIONMASKS['geometry']) cn.setIntoCollideMask(COLLISIONMASKS['portals'] | COLLISIONMASKS['exit'] | COLLISIONMASKS['lava']) cn.addSolid(CollisionSphere(0,0,0,3)) solid = self.node.attachNewNode(cn) # TODO : find a way to remove that, it's the cause of the little # "push me left" effect we see sometime when exiting a portal self.base.cTrav.addCollider(solid,self.base.pusher) self.base.pusher.addCollider(solid,self.node, self.base.drive.node()) # init players floor collisions ray = CollisionRay() ray.setOrigin(0,0,-.2) ray.setDirection(0,0,-1) cn = CollisionNode('playerRay') cn.setFromCollideMask(COLLISIONMASKS['player']) cn.setIntoCollideMask(BitMask32.allOff()) cn.addSolid(ray) solid = self.node.attachNewNode(cn) self.nodeGroundHandler = CollisionHandlerQueue() self.base.cTrav.addCollider(solid, self.nodeGroundHandler) # init players ceil collisions ray = CollisionRay() ray.setOrigin(0,0,.2) ray.setDirection(0,0,1) cn = CollisionNode('playerUpRay') cn.setFromCollideMask(COLLISIONMASKS['player']) cn.setIntoCollideMask(BitMask32.allOff()) cn.addSolid(ray) solid = self.node.attachNewNode(cn) self.ceilGroundHandler = CollisionHandlerQueue() self.base.cTrav.addCollider(solid, self.ceilGroundHandler) def createMouseCollisions(self): # Fire the portals firingNode = CollisionNode('mouseRay') firingNP = self.base.camera.attachNewNode(firingNode) firingNode.setFromCollideMask(COLLISIONMASKS['geometry']) firingNode.setIntoCollideMask(BitMask32.allOff()) firingRay = CollisionRay() firingRay.setOrigin(0,0,0) firingRay.setDirection(0,1,0) firingNode.addSolid(firingRay) self.firingHandler = CollisionHandlerQueue() self.base.cTrav.addCollider(firingNP, self.firingHandler) def createPortalCollisions(self): # Enter the portals cn = CollisionNode('bluePortal') cn.setFromCollideMask(COLLISIONMASKS['portals']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.bluePortal.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,2)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') self.base.cTrav.addCollider(np, h) cn = CollisionNode('orangePortal') cn.setFromCollideMask(COLLISIONMASKS['portals']) cn.setIntoCollideMask(BitMask32.allOff()) np = self.orangePortal.attachNewNode(cn) cn.addSolid(CollisionSphere(0,0,0,2)) h = CollisionHandlerEvent() h.addInPattern('%fn-into-%in') h.addOutPattern('%fn-outof-%in') self.base.cTrav.addCollider(np, h) def attachCommonControls(self): self.base.accept( "z" if AZERTY else "w" , self.addWalk,[self.FORWARD]) self.base.accept( "z-up" if AZERTY else "w-up" , self.addWalk,[-self.FORWARD] ) self.base.accept( "s" , self.addWalk,[self.BACK] ) self.base.accept( "s-up" , self.addWalk,[-self.BACK] ) self.base.accept( "q" if AZERTY else "a" , self.addWalk,[self.LEFT]) self.base.accept( "q-up" if AZERTY else "a-up" , self.addWalk,[-self.LEFT] ) self.base.accept( "d" , self.addWalk,[self.RIGHT] ) self.base.accept( "d-up" , self.addWalk,[-self.RIGHT] ) self.base.accept( "r-up" , self.resetPosition ) self.base.accept( "p-up" , self.showPosition ) self.base.accept( "b-up" , self.deBug ) def attachStandardControls(self): self.attachCommonControls() self.base.accept( "space" , self.__setattr__,["readyToJump",True]) self.base.accept( "space-up" , self.__setattr__,["readyToJump",False]) self.base.accept( "c-up" , self.__setattr__,["intoPortal",None] ) self.base.accept( "e-up" , self.erasePortals ) self.base.accept( "mouse1" , self.fireBlue ) self.base.accept( "mouse3" , self.fireOrange ) # Events self.base.accept( "bluePortal-into-player" , self.enterPortal, ["blue"] ) self.base.accept( "orangePortal-into-player" , self.enterPortal, ["orange"] ) self.base.accept( "bluePortal-outof-player" , self.exitPortal, ["blue"] ) self.base.accept( "orangePortal-outof-player" , self.exitPortal, ["orange"] ) self.base.accept( "levelExit-into-player" , self.levelExit) self.base.accept( "lava-into-player" , self.fallIntoLava) def attachStandardTasks(self): taskMgr.add(self.mouseUpdate, 'mouse-task') taskMgr.add(self.moveUpdate, 'move-task') taskMgr.add(self.jumpUpdate, 'jump-task') def attachEditorControls(self): self.attachCommonControls() self.base.accept( "space" , self.__setattr__, ['selectingForMulti', 1]) self.base.accept( "space-up" , self.__setattr__, ['selectingForMulti', 0]) self.base.accept( "shift-space" , self.__setattr__, ['selectingForMulti', 2]) self.base.accept( "shift-space-up" , self.__setattr__, ['selectingForMulti', 0]) self.base.accept( "c-up" , self.clearMultiSelectedCubes) self.base.accept( "mouse1" , self.selectCubeForCopy, [1]) self.base.accept( "wheel_up" , self.selectCubeForChange, [1] ) self.base.accept( "wheel_down" , self.selectCubeForChange, [-1] ) self.base.accept( "mouse3" , self.selectCubeForDelete ) self.base.accept("f11", self.saveLevel) self.base.accept("x", self.selectCubeForRectangle) self.base.accept("shift-x", self.selectCubeForRectangle, [True]) self.base.accept("l", self.addLightHere) self.base.accept("u", self.fps.level.undo, [1]) for i in range(1,10): self.base.accept( "%i-up" % (i,), self.selectCubeForCopy, [i]) for key, vec in [("a" if AZERTY else "q", self.FLYUP),("w" if AZERTY else "z", self.FLYDN)]: self.base.accept(key, self.addWalk, [vec]) self.base.accept(key + "-up", self.addWalk, [-vec]) def attachEditorTasks(self): taskMgr.add(self.mouseUpdate, 'mouse-task') taskMgr.add(self.moveInEditor, 'move-task') def deBug(self): import pdb pdb.set_trace() def showPosition(self): print self.node.getPos() print self.mass def fallIntoLava(self, *args, **kwargs): # TODO : sound and message + little delay self.erasePortals() self.resetPosition() def resetPosition(self, *args, **kwargs): self.node.setHpr(VBase3(0,0,0)) self.mass.pos = VBase3(*self.origin) self.mass.vel = VBase3(0,0,0) self.mass.force = VBase3(0,0,0) self.node.setPos(self.mass.pos) def erasePortals(self): self.bluePortal.setPos(*self.bporigin) self.orangePortal.setPos(*self.oporigin) self.bluePortal.detachNode() self.orangePortal.detachNode() self.intoPortal = None self.canPortal = [] #@oldpostracker def mouseUpdate(self,task): """ this task updates the mouse """ md = self.base.win.getPointer(0) x = md.getX() y = md.getY() if self.base.win.movePointer(0, self.base.win.getXSize()/2, self.base.win.getYSize()/2): self.node.setH(self.node.getH() - (x - self.base.win.getXSize()/2)*0.1) if self.fps.editor_mode: self.node.setP(self.node.getP() - (y - self.base.win.getYSize()/2)*0.1) else: self.base.camera.setP(self.base.camera.getP() - (y - self.base.win.getYSize()/2)*0.1) self.canSetTarget = True self.bcamera.lookAt(self.bluePortal, self.node.getPos(self.orangePortal)) self.ocamera.lookAt(self.orangePortal, self.node.getPos(self.bluePortal)) #self.canPortal = ['blue','orange'] if self.fps.editor_mode: cube, point, normal = self.selectCube() self.osd.updateTargetPosition(cube) if self.selectingForMulti: self.selectCubeForMulti() return task.cont def addWalk(self, vec): self.walk += vec def moveUpdate(self,task): """ this task makes the player move """ # move where the keys set it self.node.setPos(self.node, self.walk*globalClock.getDt()*self.speed) return task.cont #@oldpostracker def jumpUpdate(self,task): """ this task simulates gravity and makes the player jump """ # get the highest Z from the down casting ray highestZ = -100 lowestZ = 100 for i in range(self.nodeGroundHandler.getNumEntries()): entry = self.nodeGroundHandler.getEntry(i) z = entry.getSurfacePoint(render).getZ() if z > highestZ and entry.getIntoNode().getName() in ( "CollisionStuff", "Plane", "Cube" ): highestZ = z for i in range(self.ceilGroundHandler.getNumEntries()): entry = self.ceilGroundHandler.getEntry(i) z = entry.getSurfacePoint(render).getZ() if z < lowestZ and entry.getIntoNode().getName() in ( "CollisionStuff", "Plane", "Cube" ): lowestZ = z # gravity effects and jumps self.mass.simulate(globalClock.getDt()) self.node.setZ(self.mass.pos.getZ()) if highestZ > self.node.getZ()-PLAYER_TO_FLOOR_TOLERANCE: self.mass.zero() self.mass.pos.setZ(highestZ+PLAYER_TO_FLOOR_TOLERANCE) self.node.setZ(highestZ+PLAYER_TO_FLOOR_TOLERANCE) if lowestZ < self.node.getZ()+PLAYER_TO_FLOOR_TOLERANCE: self.mass.zero() self.mass.pos.setZ(lowestZ-PLAYER_TO_FLOOR_TOLERANCE) self.node.setZ(lowestZ-PLAYER_TO_FLOOR_TOLERANCE) if self.readyToJump and self.node.getZ() < highestZ + PLAYER_TO_FLOOR_TOLERANCE_FOR_REJUMP: self.mass.jump(JUMP_FORCE) return task.cont def firePortal(self, name, node): def hasTagValue(node, tag, value): if node.getTag(tag) == value: return True for pnum in range(node.getNumParents()): return hasTagValue(node.getParent(pnum), tag, value) return False self.firingHandler.sortEntries() if self.firingHandler.getNumEntries() > 0: closest = self.firingHandler.getEntry(0) if hasTagValue(closest.getIntoNode(), 'noportals', '1'): return point = closest.getSurfacePoint(render) normal = closest.getSurfaceNormal(render) node.setPos(point) node.lookAt(point + normal) node.reparentTo(render) dest = self.PORTAL_CYCLE[name] if dest not in self.canPortal: self.canPortal.append(dest) def fireBlue(self, *arg, **kwargs): self.firePortal("blue", self.bluePortal) def fireOrange(self, *arg, **kwargs): self.firePortal("orange", self.orangePortal) #@oldpostracker def enterPortal(self, color, collision): if self.intoPortal is None and color in self.canPortal: self.intoPortal = color portal = {"orange": self.bluePortal, "blue": self.orangePortal}.get(color) otherportal = {"orange": self.orangePortal, "blue": self.bluePortal}.get(color) # Handle horizontal portals : if portal.getH() == 0: self.node.setP(0) self.node.setR(0) elif otherportal.getH() == 0: self.node.setH(portal.getH()) self.node.setP(0) self.node.setR(0) else: # New HPR is relative to 'new' portal but it the 'same' value # as the old HPR seen from the 'other' portal oldh_fromportal = self.node.getH(otherportal) self.node.setHpr(Vec3(0,0,0)) self.node.setH(portal, 180-oldh_fromportal) newh_fromportal = self.node.getH(portal) self.node.setPos(portal, self.walk * 10.) self.mass.pos = self.node.getPos() # Make half a turn (only if we straffing without walking) if self.walk.getY() == 0 and self.walk.getX() != 0: self.node.setH(self.node, 180) self.node.setPos(self.node, self.walk * 10) #@oldpostracker def exitPortal(self, color, collision): # When you entered the blue portal, you have to exit the orange one if self.intoPortal != color: self.intoPortal = None def levelExit(self, event): if self.fps.level.settings.next_level: self.fps.level.loadlevel(self.fps.level.settings.next_level) self.origin = self.fps.level.settings.origin self.resetPosition() self.erasePortals() self.walk = self.STOP else: print "You won !" sys.exit(0) # EDITOR MODE def selectCube(self): self.firingHandler.sortEntries() if self.firingHandler.getNumEntries() > 0: closest = self.firingHandler.getEntry(0) return closest.getIntoNodePath().getParent().getParent(), closest.getSurfacePoint(render), closest.getSurfaceNormal(render) # render/cube.egg/-PandaNode/-GeomNode else: return None, None, None def clearMultiSelectedCubes(self): for c in self.selectedCubes: c.clearTexture(self.editorTextureStage) self.selectedCubes = [] def selectCubeForMulti(self): cube, point, normal = self.selectCube() if cube: if self.selectingForMulti == 1: cube.setTexture(self.editorTextureStage, self.editorSelectedTexture) if cube not in self.selectedCubes: self.selectedCubes.append(cube) elif cube in self.selectedCubes: cube.clearTexture(self.editorTextureStage) self.selectedCubes.remove(cube) def selectCubeForCopy(self, qty = 1): cube, point, normal = self.selectCube() if not (cube and point and normal): return if self.selectedCubes: for c in self.selectedCubes: self.fps.level.copyCube(c, normal, qty) self.clearMultiSelectedCubes() else: self.fps.level.copyCube(cube, normal, qty) def selectCubeForDelete(self): cube, point, normal = self.selectCube() if not (cube and point and normal): return if self.selectedCubes: for c in self.selectedCubes: self.fps.level.deleteCube(c) self.clearMultiSelectedCubes() else: self.fps.level.deleteCube(cube) def selectCubeForChange(self, step = 1): cube, point, normal = self.selectCube() if not (cube and point and normal): return if self.selectedCubes: for c in self.selectedCubes: self.fps.level.changeCube(c, step) else: self.fps.level.changeCube(cube, step) def selectCubeForRectangle(self, makeRoom = False): cube, point, normal = self.selectCube() if makeRoom: self.fps.level.createRoom(cube, self.node) # creates a room from the selected cube to the player(camera) position else: self.fps.level.createRectangle(cube, self.node) # creates a rectangle from the selected cube to the player(camera) position def saveLevel(self): camerapos = [self.node.getX(), self.node.getY(), self.node.getZ()] levelname = self.fps.levelname self.fps.level.savelevel(levelname, camerapos) def addLightHere(self): camerapos = [self.node.getX(), self.node.getY(), self.node.getZ()] self.fps.level.addLightHere(camerapos) def moveInEditor(self,task): self.node.setPos(self.node, self.walk*globalClock.getDt()*self.speed) self.osd.updatePosition(self.node) return task.cont
class Moving(ShowBase): def __init__(self): ShowBase.__init__(self) # This is used to store which keys are currently pressed. self.keyMap = {"left": 0, "right": 0, "forward": 0, "back": 0, "up": 0} # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("EggMod/SandPlan.egg") self.environ.reparentTo(render) self.environ.setScale(20) StartPos = LVector3(0, 0, 0) self.movint = loader.loadModel("EggMod/HailPar.egg") self.movint.reparentTo(render) self.movint.setScale(2) self.movint.setPos(StartPos + (0, 0, 0.5)) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", True]) self.accept("arrow_right", self.setKey, ["right", True]) self.accept("arrow_up", self.setKey, ["forward", True]) self.accept("arrow_down", self.setKey, ["back", True]) self.accept("f", self.setKey, ["up", True]) self.accept("arrow_left-up", self.setKey, ["left", False]) self.accept("arrow_right-up", self.setKey, ["right", False]) self.accept("arrow_up-up", self.setKey, ["forward", False]) self.accept("arrow_down-up", self.setKey, ["back", False]) self.accept("f-up", self.setKey, ["up", False]) self.mopan = Pmango() self.alin = LinearEulerIntegrator() self.mopan.attachLinearIntegrator(self.alin) self.arin = AngularEulerIntegrator() self.mopan.attachAngularIntegrator(self.arin) taskMgr.add(self.move, "moveTask") self.cTrav = CollisionTraverser() #base.cTrav.setRespectPrevTransform(True) self.actMove = NodePath("ActMove") self.actMove.reparentTo(render) self.actMove.setPos(0, 0, 190) self.an = ActorNode("BMova") self.anp = self.actMove.attachNewNode(self.an) self.mopan.attachPhysicalNode(self.an) self.movint.reparentTo(self.actMove) self.anp.node().getPhysicsObject().setMass(1) #self.an.getPhysicsObject().setTerminalVelocity(1.0) self.dvi = 0 self.grava = ForceNode('GravAll') self.grar = render.attachNewNode(self.grava) self.grdi = LinearVectorForce(0.0, -0.0, -8.0) #self.grdi.setMassDependent(1) self.grava.addForce( self.grdi) #Forces have to be added to force nodes and to # a physics manager self.mopan.addLinearForce(self.grdi) self.BMoveBalance = CollisionSphere(0, 0, -7.0, 1) self.BMoveBalanceNode = CollisionNode('BMove') self.BMoveBalanceNode.addSolid(self.BMoveBalance) #self.BMABalance = CollisionSphere(0, 0, -7.0, 1) #self.BMABalanceNode = CollisionNode('BMAove') #self.BMABalanceNode.addSolid(self.BMABalance) self.BMoveBalancePath = self.actMove.attachNewNode( self.BMoveBalanceNode) #self.BMAoveBalancePath=self.anp.attachNewNode(self.BMABalanceNode) #self.BMAoveBalancePath.setPos(0,0,-8) self.BMAoveBalancePath = self.BMoveBalancePath.copyTo(self.anp) self.BMAoveBalancePath.setPos(0, 0, -5) self.BMoveBalancePath.setPos( self.actMove.getRelativePoint(self.BMoveBalancePath, self.BMoveBalancePath.getPos())) self.DinGro = PhysicsCollisionHandler() self.DinGro.setStaticFrictionCoef(1) self.DinGro.setDynamicFrictionCoef(2) self.DinGro.setAlmostStationarySpeed(0.1) self.DinGro.addCollider( self.BMAoveBalancePath, self.anp) #Colliders use nodepaths for collisions instead of nodes self.cTrav.addCollider(self.BMAoveBalancePath, self.DinGro) self.DinGro.addCollider(self.BMoveBalancePath, self.anp) self.cTrav.addCollider(self.BMoveBalancePath, self.DinGro) # Uncomment this line to see the collision rays self.BMoveBalancePath.show() self.BMAoveBalancePath.show() # Uncomment this line to show a visual representation of the # collisions occuring self.cTrav.showCollisions(render) # Create some lighting directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection((-5, -5, -5)) render.setLight(render.attachNewNode(directionalLight)) self.calrun = 0 self.upcal = None self.anp.setPos(0, 0, 0) # Records the state of the arrow keys def setKey(self, key, value): self.keyMap[key] = value # Accepts arrow keys to move either the player or the menu cursor, # Also deals with grid checking and collision detection def move(self, task): # Get the time that elapsed since last frame. We multiply this with # the desired speed in order to find out with which distance to move # in order to achieve that desired speed. dt = globalClock.getDt() self.dvi += dt self.anr = self.an.getPhysicsObject() self.cTrav.setRespectPrevTransform(True) print(self.anr.getVelocity()) #self.anr.setVelocity(0,0,0) self.mopan.doPhysics(dt) if dt <= .2: self.actMove.setPos(self.actMove, self.anp.getPos()) self.anp.setPos(0, 0, 0.0) #self.anr.setVelocity(0,0,-1) #self.anp.setPos(0,0,0.0) if self.keyMap["left"]: self.actMove.setH(self.actMove.getH() + 200 * dt) if self.keyMap["right"]: self.actMove.setH(self.actMove.getH() - 200 * dt) if self.keyMap["forward"]: self.actMove.setFluidY(self.actMove, -25 * dt) if self.keyMap["back"]: self.actMove.setFluidY(self.actMove, 25 * dt) if self.keyMap["up"]: self.actMove.setFluidZ(self.actMove, 25 * dt) # Normally, we would have to call traverse() to check for collisions. # However, the class ShowBase that we inherit from has a task to do # this for us, if we assign a CollisionTraverser to self.cTrav. #self.cTrav.traverse(render) return task.cont
class PlayWorld(object): def __init__(self, config=None): if config is None: self.config = {} execfile('play_config.py', self.config) else: self.config = config self.reward = None print self.config['pydaq'] if pydaq and self.config.setdefault('pydaq', True) is not None: self.reward = pydaq.GiveReward() self.reward_count = 0 # adjustment to speed so corresponds to gobananas task # 7 seconds to cross original environment # speed needs to be adjusted to both speed in original # environment and c_range of colors # self.speed = 0.05 * (self.c_range[1] - self.c_range[0]) # speed is own variable, so can be changed during training. self.speed = self.config['speed'] # need a multiplier to the joystick output to tolerable speed self.vel_base = 4 self.max_vel = [500, 500, 0] self.base = ShowBase() self.base.disableMouse() # self.base.setFrameRateMeter(True) # assume we are showing windows unless proven otherwise if self.config.get('win', True): # only need inputs if we have a window self.inputs = Inputs(self.base) props = WindowProperties() props.setCursorHidden(True) props.setForeground(True) print self.config.get('resolution') if self.config.get('resolution'): # main window props.set_size(int(self.config['resolution'][0]), int(self.config['resolution'][1])) # props.set_origin(1920, 0) props.set_origin(500, 0) else: props.set_size(600, 600) props.set_origin(400, 50) self.base.win.requestProperties(props) # print 'background color', self.base.getBackgroundColor() # field = self.base.loader.loadModel("../goBananas/models/play_space/field.bam") field = self.base.loader.loadModel("../goBananas/models/play_space/round_courtyard.bam") field.setPos(0, 0, 0) field.reparent_to(self.base.render) field_node_path = field.find('**/+CollisionNode') field_node_path.node().setIntoCollideMask(0) sky = self.base.loader.loadModel("../goBananas/models/sky/sky_kahana2.bam") sky.setPos(0, 0, 0) sky.setScale(1.6) sky.reparentTo(self.base.render) windmill = self.base.loader.loadModel("../goBananas/models/windmill/windmill.bam") windmill.setPos(-10, 30, -1) windmill.setScale(0.03) windmill.reparentTo(self.base.render) # mountain = self.base.loader.loadModel("../goBananas/models/mountain/mountain.bam") # mountain.setScale(0.0005) # mountain.setPos(10, 30, -0.5) # create the avatar self.avatar = NodePath(ActorNode("avatar")) self.avatar.reparentTo(self.base.render) self.avatar.setPos(0, 0, 1) self.avatar.setScale(0.5) pl = self.base.cam.node().getLens() pl.setFov(60) self.base.cam.node().setLens(pl) self.base.camera.reparentTo(self.avatar) # initialize task variables self.frame_task = None self.started_game = None self.showed_match = None self.gave_reward = None # initialize and start the game self.set_next_trial() # print 'end init' def start_loop(self): # need to get new match self.start_play() def start_play(self): print 'start play' # log this # print self.base.render.ls() self.frame_task = self.base.taskMgr.add(self.game_loop, "game_loop") self.frame_task.last = 0 # initiate task time of the last frame def game_loop(self, task): dt = task.time - task.last task.last = task.time velocity = self.inputs.poll_inputs(LVector3(0)) self.move_avatar(dt, velocity) return task.cont def reward_loop(self, task): self.reward_count += 1 if self.reward_count <= self.config['num_beeps']: if self.reward: # log this print 'give a bloody reward already' self.reward.pumpOut() print 'give reward' return task.again else: self.end_loop() return task.done def move_avatar(self, dt, velocity): # print 'velocity', self.velocity self.avatar.setH(self.avatar.getH() - velocity[0] * 1.1) move = LVector3(0, velocity[1], 0) self.avatar.setPos(self.avatar, move * dt * self.vel_base) def give_reward(self): # clear the background self.base.setBackgroundColor(0.41, 0.41, 0.41) print 'give first reward' self.reward_count = 1 if self.reward: # log this self.reward.pumpOut() self.gave_reward = self.base.taskMgr.doMethodLater(self.config['pump_delay'], self.reward_loop, 'reward_loop') def end_loop(self): print 'end loop' # clear avatar map # if there is a match set, return to center of color gradient, # set new match, if applicable self.set_next_trial() def set_next_trial(self): print 'set next trial' # move avatar back to beginning position, only matters for # showing card for next color match # self.avatar.set_pos(-10, -10, 2) # start the game self.start_loop() def check_key_map(self): if self.config['colors'][0]: if self.inputs.key_map['r']: self.config['match_direction'] = ['right'] elif self.inputs.key_map['r'] is not None: self.config['match_direction'] = ['left'] elif self.config['colors'][1]: if self.inputs.key_map['f']: self.config['match_direction'] = ['front'] elif self.inputs.key_map['f'] is not None: self.config['match_direction'] = ['back'] def setup_display2(self, display_node): print 'setup display2' props = WindowProperties() props.set_cursor_hidden(True) props.set_foreground(False) if self.config.get('resolution'): props.setSize(700, 700) props.setOrigin(-int(self.config['resolution'][0] - 5), 5) else: props.setSize(300, 300) props.setOrigin(10, 10) window2 = self.base.openWindow(props=props, aspectRatio=1) lens = OrthographicLens() lens.set_film_size(2, 2) lens.setNearFar(-100, 100) self.render2d = NodePath('render2d') self.render2d.attach_new_node(display_node) camera2d = self.base.makeCamera(window2) camera2d.setPos(0, -10, 0) camera2d.node().setLens(lens) camera2d.reparentTo(self.render2d)
class Golem(FSM, DirectObject): def __init__(self): FSM.__init__(self, "FSM-Golem") random.seed() self.golem = loader.loadModel("Golem") self.golem = Actor("Golem", { "Idle":"Golem-Idle", "Walk":"Golem-Walk", "Attack":"Golem-Attack", "Destroyed":"Golem-Destroyed"}) self.golem.setBlend(frameBlend = True) golemViewSphere = CollisionSphere(0, 0, 0.5, 6) golemViewSphere.setTangible(False) golemViewColNP = self.golem.attachNewNode(CollisionNode('golemViewField')) golemViewColNP.node().addSolid(golemViewSphere) golemHitSphere = CollisionSphere(0, 0, 0.5, 1) golemHitColNP = self.golem.attachNewNode(CollisionNode('golemHitField')) golemHitColNP.node().addSolid(golemHitSphere) # a collision segment to check attacks self.attackCheckSegment = CollisionSegment(0, 0, 1, 0, -1.3, 1) self.golemAttackRay = self.golem.attachNewNode(CollisionNode("golemAttackCollision")) self.golemAttackRay.node().addSolid(self.attackCheckSegment) self.golemAttackRay.node().setIntoCollideMask(0) self.attackqueue = CollisionHandlerQueue() base.cTrav.addCollider(self.golemAttackRay, self.attackqueue) attackAnim = self.golem.actorInterval("Attack", playRate = 2) self.AttackSeq = Parallel( attackAnim, Sequence( Wait(0.5), Func(self.ceckAttack) )) self.lookatFloater = NodePath(PandaNode("golemTracker")) self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.hide() self.lookatFloater.reparentTo(render) self.trackerObject = loader.loadModel("misc/Pointlight") self.trackerObject.setColor(0, 1, 0) self.trackerObject.setScale(0.25) self.trackerObject.reparentTo(self.lookatFloater) def start(self, startPos): self.golem.setPos(startPos.getPos()) self.golem.setHpr(startPos.getHpr()) self.golem.reparentTo(render) self.trackedEnemy = None self.health = 5 self.accept("playerCollision-in-golemViewField", lambda extraArgs: base.messenger.send("golemSeesPlayer", [self.golem])) def stop(self): self.trackedEnemy = None taskMgr.remove("GolemAI_task") self.golem.hide() self.ignoreAll() def cleanup(self): self.stop() self.lookatFloater.removeNode() self.golem.cleanup() self.golem.removeNode() def activate(self, trackedEnemy): self.trackedEnemy = trackedEnemy taskMgr.add(self.aiTask, "GolemAI_task") self.lookatFloater.show() def aiTask(self, task): dt = globalClock.getDt() if self.AttackSeq.isPlaying(): return task.cont self.lookatFloater.setPos(self.golem, 0, 0, 3.4) self.lookatFloater.lookAt(self.trackedEnemy) self.lookatFloater.setH(self.lookatFloater.getH() + 180) self.lookatFloater.setP(0) self.lookatFloater.setR(0) self.golem.lookAt(self.trackedEnemy) self.golem.setH(self.golem.getH() + 180) distanceVec = self.golem.getPos() - self.trackedEnemy.getPos() enemyDist = distanceVec.length() if enemyDist < 2.0: # close enough for combat action = random.choice(["Attack", "Idle"]) if action == "Attack": self.request("Attack") else: if self.state != "Idle": self.request("Idle") else: self.golem.setY(self.golem, -0.5 * dt) if self.state != "Walk": self.request("Walk") return task.cont def hit(self): hitInterval = Sequence( Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15), Func(self.golem.setColorScale, 1, 0, 0, 0.75), Wait(0.15), Func(self.golem.clearColorScale), Wait(0.15)) self.health -= 1 if self.health == 4: self.trackerObject.setColor(0, 1, 0) hitInterval.start() elif self.health == 3: self.trackerObject.setColor(0.25, 0.75, 0) hitInterval.start() elif self.health == 2: self.trackerObject.setColor(0.5, .5, 0) hitInterval.start() elif self.health == 1: self.trackerObject.setColor(0.75, 0.25, 0) hitInterval.start() elif self.health == 0: self.trackerObject.setColor(0, 0, 0) self.request("Destroyed") def ceckAttack(self): for i in range(self.attackqueue.getNumEntries()): entry = self.attackqueue.getEntry(i) into = entry.getIntoNode() if "playerCollision" in into.getName(): if random.random() > .5: base.messenger.send("HitPlayer") def enterIdle(self): self.golem.loop("Idle") def enterWalk(self): self.golem.setPlayRate(2, "Walk") self.golem.loop("Walk") def enterAttack(self): self.AttackSeq.start() def enterDestroyed(self): self.ignoreAll() taskMgr.remove("GolemAI_task") self.AttackSeq.finish() self.golem.play("Destroyed") self.lookatFloater.hide() base.messenger.send("GolemDestroyed")
class Menu(object): ''' ''' def __init__(self, parent): self._notify = DirectNotify().newCategory("Menu") self._notify.info("New Menu-Object created: %s" %(self)) #Font self.font = DynamicTextFont(FONT) self.font.setRenderMode(TextFont.RMSolid) self.KEY_DELAY = 0.15 self.player_buttonpressed = [] self._parent = parent self._players = parent.players self._devices = parent.devices taskMgr.add(self.fetchAnyKey, "fetchAnyKey") def showStartScreen(self): ''' the first screen with "press any Key" the device with the first key press will be the first player ''' self._notify.info("Initializing StartScreen") self.wii = [] #StartScreen Node self.startNode = NodePath("StartNode") self.startNode.reparentTo(render) self.startNode.setPos(-5,15,3) #Headline model headline = loader.loadModel("data/models/logo.egg") headline.setX(4.7) headline.setY(-4) headline.setZ(-2) headline.setP(90) headline.reparentTo(self.startNode) #Press any key text presskey = TextNode("PressAnyKey") presskey.setFont(self.font) presskey.setText(_("Press any key!!")) textNodePath = NodePath("PressAnyNode") textNodePath.attachNewNode(presskey) textNodePath.setPos(0,10,-9.5) textNodePath.reparentTo(self.startNode) #Show the start screen self.startNode.show() #LICHT plight = PointLight('plight') plight.setColor(VBase4(10, 10, 10, 1)) plnp = self.startNode.attachNewNode(plight) plnp.setPos(20, -800, 30) self.startNode.setLight(plnp) #Camera self.camera = base.makeCamera(base.win) self._notify.info("StarScreen initialized") # ----------------------------------------------------------------- def fetchAnyKey(self, task): ''' Return the first device with the first key stroke ''' for i in xrange(len(self._devices.devices)): if self._devices.devices[i].boost: #Kill Camera self.camera.node().setActive(False) #Kill Node self.startNode.removeNode() #Start the menu self.menu = MainMenu(self._parent, self.newGame, self._devices.devices[i], self._devices) self.menu.menuMain() return task.done return task.cont # ----------------------------------------------------------------- def newGame(self): ''' The select vehicle screen ''' base.enableParticles() self.countdown = COUNTDOWN_START #the countdown, when its over the game can be started self._notify.info("Initializing new game") #GlobPattern if we need a Panda Class self.vehicle_list = glob.glob("data/models/vehicles/*.egg") for index in range(len(self.vehicle_list)): self.vehicle_list[index] = Filename.fromOsSpecific(self.vehicle_list[index]).getFullpath() self._notify.debug("Vehicle list: %s" %(self.vehicle_list)) self.platform = loader.loadModel("data/models/platform.egg") #Loading-Text that gets displayed when loading a model text = TextNode("Loading") text.setFont(self.font) text.setText(_("Loading...")) text.setAlign(TextProperties.ACenter) self.loading = NodePath("LoadingNode") self.loading.attachNewNode(text) self.loading.setPos(0,0,2) #The countdown, its possible to start the game when its 0 text = TextNode("Countdown") text.setFont(self.font) text.setAlign(TextProperties.ACenter) text.setText(_(str(COUNTDOWN_START))) self.countdown_node = NodePath("Countdown") self.countdown_node.attachNewNode(text) self.countdown_node.setPos(0,0,4) #PreLoad the description that gets displayed when loading a model text = TextNode("name") text.setFont(self.font) text.setText(_("Loading...")) text.setAlign(TextProperties.ACenter) self.attributes = NodePath("AttributeNode") self.attributes.attachNewNode(text) self.unusedDevices = self._devices.devices[:] taskMgr.add(self.collectPlayer, "collectPlayer") #taskMgr.add(self.collectWii, "collectWii") self.screens = [] taskMgr.add(self.selectVehicle, "selectVehicle") self.color_red = Vec4(1,0,0,0) self.color_green = Vec4(0,1,0,0) self._notify.info("New game initialized") # ----------------------------------------------------------------- def selectVehicle(self, task): ''' The vehicle select and rotate task ''' #Set the countdown and hide, if > 3 self.countdown -= globalClock.getDt() if self.countdown <=0: self.countdown_node.getChild(0).node().setText(_("Go")) self.countdown_node.setColor(self.color_green) elif self.countdown <=3: self.countdown_node.getChild(0).node().setText(str(int(round((self.countdown+0.5))))) self.countdown_node.setColor(self.color_red) self.countdown_node.show() else: self.countdown_node.hide() heading = self.loading.getH() -(30 * globalClock.getDt()) self.loading.setH(heading) for player in self._players: if player.vehicle.model != None: player.vehicle.model.setH(heading) if self.player_buttonpressed[self._players.index(player)] < task.time and not player.vehicle.model_loading: if player.device.directions[0] < -0.8: self._parent.menuselect.play() self.countdown = COUNTDOWN_START self.player_buttonpressed[self._players.index(player)] = task.time + self.KEY_DELAY index = self.vehicle_list.index("data/models/vehicles/%s" %(player.vehicle.model.getName()))-1 self._notify.debug("Previous vehicle selected: %s" %(index)) player.vehicle.model_loading = True player.vehicle.model.hide() player.camera.camera.getParent().find("AttributeNode").hide()#Hide the attributes self.loading.instanceTo(player.camera.camera.getParent()) loader.loadModel(self.vehicle_list[index], callback = player.setVehicle) elif player.device.directions[0] > 0.8: self._parent.menuselect.play() self.countdown = COUNTDOWN_START self.player_buttonpressed[self._players.index(player)] = task.time + self.KEY_DELAY index = self.vehicle_list.index("data/models/vehicles/%s" %(player.vehicle.model.getName()))+1 self._notify.debug("Next vehicle selected: %s" %(index)) if index >= len(self.vehicle_list): index = 0 player.vehicle.model_loading = True player.vehicle.model.hide() player.camera.camera.getParent().find("AttributeNode").hide()#Hide the attributes self.loading.instanceTo(player.camera.camera.getParent()) loader.loadModel(self.vehicle_list[index], callback = player.setVehicle) if player.device.directions[1] > 0.8: self.countdown = COUNTDOWN_START self._parent.menuselect.play() self.player_buttonpressed[self._players.index(player)] = task.time + self.KEY_DELAY self._notify.debug("Next color selected") a = player.vehicle.model.findAllTextures() tex = a.findTexture(player.vehicle.model.getName()[:-4]) self.rotateHue(tex, 0.1) elif player.device.directions[1] < -0.8: self._parent.menuselect.play() self.countdown = COUNTDOWN_START self.player_buttonpressed[self._players.index(player)] = task.time + self.KEY_DELAY self._notify.debug("Next color selected") a = player.vehicle.model.findAllTextures() tex = a.findTexture(player.vehicle.model.getName()[:-4]) self.rotateHue(tex, -0.1) return task.cont # ----------------------------------------------------------------- def rotateHue(self, tex, value=0.1): ''' ''' img = PNMImage() tex.store(img) for y in xrange(img.getReadYSize()): for x in xrange(img.getReadXSize()): r, g, b = img.getXel(x,y) h, s, v = colorsys.rgb_to_hsv(r, g, b) h += value if h < 0: h += 360 r, g, b = colorsys.hsv_to_rgb(h, s, v) img.setXel(x,y,r,g,b) tex.load(img) # ----------------------------------------------------------------- def collectWii(self, task): ''' Collect wiimotes task ''' try: print 'Put Wiimote in discoverable mode now (press 1+2)...' wiimote = cwiid.Wiimote() self.wiimoteX.append(wiimote) print len(self.wiimoteX) except: pass return task.cont # ----------------------------------------------------------------- def collectPlayer(self, task): ''' Wait until all players are ready ''' if len(self._players) > 0 and self.player_buttonpressed[0] < task.time: if self._players[0].device.boost and self.countdown <= 0: loading = False for player in self._players: if player.vehicle.model_loading: loading = True break self._notify.debug("Loading vehicle: %s" %(loading)) if not loading: taskMgr.remove("selectVehicle") self.track = trackgen3d.Track3d(1000, 1800, 1600, 1200, 5)#len(self._players)) self.streetPath = render.attachNewNode(self.track.createRoadMesh()) #self.borderleftPath = render.attachNewNode(self.track.createBorderLeftMesh()) self.borderleftPath = render.attachNewNode(self.track.createBorderLeftMesh()) self.borderrightPath = render.attachNewNode(self.track.createBorderRightMesh()) self.borderleftcollisionPath = NodePath(self.track.createBorderLeftCollisionMesh()) self.borderrightcollisionPath = NodePath(self.track.createBorderRightCollisionMesh()) ##self.borderPath = render.attachNewNode(self.track.createBorderMesh()) textures = ["tube", "tube2", "street"] tex = textures[random.randint(0, len(textures)-1)] roadtex = loader.loadTexture('data/textures/'+tex+'.png') bordertex = loader.loadTexture('data/textures/border.png') self.streetPath.setTexture(roadtex) self.borderleftPath.setTexture(bordertex) self.borderrightPath.setTexture(bordertex) #self.streetPath = loader.loadModel('data/models/Street.egg') ##self.streetPath = loader.loadModel('data/models/Street.egg') #tex = loader.loadTexture('data/models/StreetTex.png') #self.nodePath.setTexture(tex) self._parent.startGame(self.streetPath,self.borderleftPath,self.borderrightPath, self.track.trackpoints, self.borderleftcollisionPath, self.borderrightcollisionPath) return task.done for device in self.unusedDevices: if device.boost: self.countdown = COUNTDOWN_START self.player_buttonpressed.append(0) self._parent.addPlayer(device) #Set the PlayerCam to the Vehicle select menu Node vehicleSelectNode = NodePath("VehicleSelectNode") self._players[-1].camera.camera.reparentTo(vehicleSelectNode) #Light, that casts shadows plight = Spotlight('plight') plight.setColor(VBase4(10.0, 10.0, 10.0, 1)) if (base.win.getGsg().getSupportsBasicShaders() != 0): pass ##plight.setShadowCaster(True, 2048, 2048)#enable shadows for this light ##TODO wegen Linux #Light plight.getLens().setFov(80) plnp = vehicleSelectNode.attachNewNode(plight) plnp.setPos(2, -10, 10) plnp.lookAt(0,0,0) vehicleSelectNode.setLight(plnp) ## vehicleSelectNode.setShaderAuto()#enable autoshader so we can use shadows #Light ambilight = AmbientLight('ambilight') ambilight.setColor(VBase4(0.2, 0.2, 0.2, 1)) vehicleSelectNode.setLight(vehicleSelectNode.attachNewNode(ambilight)) self.platform.instanceTo(vehicleSelectNode) #Load the platform #instance shown text self.countdown_node.instanceTo(vehicleSelectNode) #Instance the Countdown self.loading.instanceTo(vehicleSelectNode) #Show the Loading-Text self.attributes.copyTo(vehicleSelectNode).hide() self._players[-1].vehicle.model_loading = True #start loading the model loader.loadModel(self.vehicle_list[0], callback = self._players[-1].setVehicle) self._notify.debug("Loading initial vehicle: %s" %(self.vehicle_list[0])) self.unusedDevices.remove(device) self.player_buttonpressed[-1] = task.time + self.KEY_DELAY #Add the Skybox skybox = loader.loadModel("data/models/skybox.egg") t = Texture() t.load(PNMImage("data/textures/skybox_hangar.png")) skybox.setTexture(t) skybox.setBin("background", 1) skybox.setDepthWrite(0) skybox.setDepthTest(0) skybox.setLightOff() skybox.setScale(10000) skybox.reparentTo(vehicleSelectNode) for player in self._players: if self.player_buttonpressed[self._players.index(player)] < task.time: if player.device.use_item: self.countdown = COUNTDOWN_START self._notify.debug("Removing player: %s" %(player)) self.unusedDevices.append(player.device) self.player_buttonpressed.pop(self._players.index(player)) self._parent.removePlayer(player) return task.cont
class PlayWorld(object): def __init__(self, config=None): if config is None: self.config = {} execfile('play_config.py', self.config) else: self.config = config self.reward = None print self.config['pydaq'] if pydaq and self.config.setdefault('pydaq', True) is not None: self.reward = pydaq.GiveReward() self.reward_count = 0 # adjustment to speed so corresponds to gobananas task # 7 seconds to cross original environment # speed needs to be adjusted to both speed in original # environment and c_range of colors # self.speed = 0.05 * (self.c_range[1] - self.c_range[0]) # speed is own variable, so can be changed during training. self.speed = self.config['speed'] # need a multiplier to the joystick output to tolerable speed self.vel_base = 4 self.max_vel = [500, 500, 0] self.base = ShowBase() self.base.disableMouse() # self.base.setFrameRateMeter(True) # assume we are showing windows unless proven otherwise if self.config.get('win', True): # only need inputs if we have a window self.inputs = Inputs(self.base) props = WindowProperties() props.setCursorHidden(True) props.setForeground(True) print self.config.get('resolution') if self.config.get('resolution'): # main window props.set_size(int(self.config['resolution'][0]), int(self.config['resolution'][1])) # props.set_origin(1920, 0) props.set_origin(500, 0) else: props.set_size(600, 600) props.set_origin(400, 50) self.base.win.requestProperties(props) # print 'background color', self.base.getBackgroundColor() # field = self.base.loader.loadModel("../goBananas/models/play_space/field.bam") field = self.base.loader.loadModel( "../goBananas/models/play_space/round_courtyard.bam") field.setPos(0, 0, 0) field.reparent_to(self.base.render) field_node_path = field.find('**/+CollisionNode') field_node_path.node().setIntoCollideMask(0) sky = self.base.loader.loadModel( "../goBananas/models/sky/sky_kahana2.bam") sky.setPos(0, 0, 0) sky.setScale(1.6) sky.reparentTo(self.base.render) windmill = self.base.loader.loadModel( "../goBananas/models/windmill/windmill.bam") windmill.setPos(-10, 30, -1) windmill.setScale(0.03) windmill.reparentTo(self.base.render) # mountain = self.base.loader.loadModel("../goBananas/models/mountain/mountain.bam") # mountain.setScale(0.0005) # mountain.setPos(10, 30, -0.5) # create the avatar self.avatar = NodePath(ActorNode("avatar")) self.avatar.reparentTo(self.base.render) self.avatar.setPos(0, 0, 1) self.avatar.setScale(0.5) pl = self.base.cam.node().getLens() pl.setFov(60) self.base.cam.node().setLens(pl) self.base.camera.reparentTo(self.avatar) # initialize task variables self.frame_task = None self.started_game = None self.showed_match = None self.gave_reward = None # initialize and start the game self.set_next_trial() # print 'end init' def start_loop(self): # need to get new match self.start_play() def start_play(self): print 'start play' # log this # print self.base.render.ls() self.frame_task = self.base.taskMgr.add(self.game_loop, "game_loop") self.frame_task.last = 0 # initiate task time of the last frame def game_loop(self, task): dt = task.time - task.last task.last = task.time velocity = self.inputs.poll_inputs(LVector3(0)) self.move_avatar(dt, velocity) return task.cont def reward_loop(self, task): self.reward_count += 1 if self.reward_count <= self.config['num_beeps']: if self.reward: # log this print 'give a bloody reward already' self.reward.pumpOut() print 'give reward' return task.again else: self.end_loop() return task.done def move_avatar(self, dt, velocity): # print 'velocity', self.velocity self.avatar.setH(self.avatar.getH() - velocity[0] * 1.1) move = LVector3(0, velocity[1], 0) self.avatar.setPos(self.avatar, move * dt * self.vel_base) def give_reward(self): # clear the background self.base.setBackgroundColor(0.41, 0.41, 0.41) print 'give first reward' self.reward_count = 1 if self.reward: # log this self.reward.pumpOut() self.gave_reward = self.base.taskMgr.doMethodLater( self.config['pump_delay'], self.reward_loop, 'reward_loop') def end_loop(self): print 'end loop' # clear avatar map # if there is a match set, return to center of color gradient, # set new match, if applicable self.set_next_trial() def set_next_trial(self): print 'set next trial' # move avatar back to beginning position, only matters for # showing card for next color match # self.avatar.set_pos(-10, -10, 2) # start the game self.start_loop() def check_key_map(self): if self.config['colors'][0]: if self.inputs.key_map['r']: self.config['match_direction'] = ['right'] elif self.inputs.key_map['r'] is not None: self.config['match_direction'] = ['left'] elif self.config['colors'][1]: if self.inputs.key_map['f']: self.config['match_direction'] = ['front'] elif self.inputs.key_map['f'] is not None: self.config['match_direction'] = ['back'] def setup_display2(self, display_node): print 'setup display2' props = WindowProperties() props.set_cursor_hidden(True) props.set_foreground(False) if self.config.get('resolution'): props.setSize(700, 700) props.setOrigin(-int(self.config['resolution'][0] - 5), 5) else: props.setSize(300, 300) props.setOrigin(10, 10) window2 = self.base.openWindow(props=props, aspectRatio=1) lens = OrthographicLens() lens.set_film_size(2, 2) lens.setNearFar(-100, 100) self.render2d = NodePath('render2d') self.render2d.attach_new_node(display_node) camera2d = self.base.makeCamera(window2) camera2d.setPos(0, -10, 0) camera2d.node().setLens(lens) camera2d.reparentTo(self.render2d)
class CameraControl(DirectObject, HasKeybinds): """ adds controls to a given camera, usually base.camera""" def __init__(self,camera=None): #camera setup self.camera = camera if self.camera == None: self.camera = base.camera #XXX note, when moving cam target we need to make sure the camera doesnt move too... cameraBase = GeomNode('cameraBase') #utility node for pan targetGeom = makeCameraTarget() cameraBase.addGeom(targetGeom) self.cameraBase = render.attachNewNode(cameraBase) #self.cameraBase.setTwoSided(True) #backface culling issue with my tristrip fail self.cameraTarget = NodePath('cameraTarget') #utility node for rot, zoom, reattach self.cameraTarget.reparentTo(self.cameraBase) #self.cameraTarget.reparentTo(render) self.camera.reparentTo(self.cameraTarget) self.track = self.camera.attachNewNode('track') #hack for pointing vector self.track.setPos(LVecBase3f(0,50,0)) #nn = GeomNode('helper') #ng = makeCameraTarget() #nn.addGeom(targetGeom) #self.track.attachNewNode(nn) #keybind setup self.__ends__=defaultdict(list) #self.accept("escape", sys.exit) #no, exit_cleanup will handle this... for function_name, key in keybinds['view'].items(): #self.accept(key,taskMgr.add,(getattr(self,function),function+'Task')) self.accept(key, self.makeTask, [function_name]) # TODO split out functions that don't require tasks keytest=key.split('-')[-1] #print(keytest) if keytest in {'mouse1','mouse2','mouse3'}: self.addEndTask(keytest,function_name) self.accept(keytest+'-up', self.endTask, [keytest,function_name]) #gains #TODO tweak me! self.XGAIN = .01 self.YGAIN = .01 #window setup self.getWindowSize() self.accept('window-event', self.getWindowSize) #self.accept('mouse1') #mouse 1 by itself does selection? #self.accpet('mouse3') #pan #self.accpet('mouse2') #--camera moves relatvie to arbitrary origin-- #pan in plane #zoom #this needs to be on a log scale, linear is balls #rotate #--camera in place-- #roll camera in place #yaw #pitch #look at selection/origin/center of mass of #--camera lense changes-- #fov (for perspective) #perspective/orthographic #--worldcraft-- #z mode wasd + mouse to orient for zooming #--selection functions we need to leave space for-- #drop origin if we don't have something selected #click select #drag select, logial intersec #right click for menu self.__ch__=None self.__cp__=None self.__cr__=None self.__cth__=None self.__ctp__=None pass def getWindowSize(self,wat=None): self.__winx__ = base.win.getXSize() self.__winy__ = base.win.getYSize() #print(self.__winx__,self.__winy__) def makeTask(self, function_name): """ ye old task spawner """ if hasattr(self, function_name): if base.mouseWatcherNode.hasMouse(): x,y = base.mouseWatcherNode.getMouse() setattr(self, '__%sTask_s__'%function_name, (x,y)) #this should be faster taskMgr.add(getattr(self,function_name), function_name+'Task') else: raise KeyError('Check your keybinds, there is no function by that name here!') def addEndTask(self,key,function_name): self.__ends__[key].append(function_name) def endTask(self, key, function): for func in self.__ends__[key]: taskMgr.remove(func+'Task') setattr(self, '__%sTask_s__'%func, None) #this should be faster self.__ch__=None #FIXME this seems hackish self.__cp__=None self.__cr__=None self.__cth__=None self.__ctp__=None def getMouseDdDt(self, name): #XXX deprecated """ use gain to adjust pixels per degree this should probably be normalized to screen size actually? or no... but to what? """ if base.mouseWatcherNode.hasMouse(): x,z = base.mouseWatcherNode.getMouse() sx,sz = getattr(self,'__%s_start__'%name) print(x,sx) print(z,sz) if z != sz or x != sx: #watch out for aliasing here... norm = (((x - sx) * self.XGAIN)**2 + ((z - sz) * self.YGAIN)**2)**.5 #norm = ((x - sx) * self.X_GAIN), ((z - sz) * self.Y_GAIN) setattr(self, '__%s_start__'%name, (x,z)) return norm else: #mouse has not moved return 0 def getMouseDdDf(self,name): if base.mouseWatcherNode.hasMouse(): x,y = base.mouseWatcherNode.getMouse() sx,sy = getattr(self,'__%s_s__'%(name)) dx = (x - sx) * self.XGAIN * self.__winx__ dy = (y - sy) * self.YGAIN * self.__winy__ return dx, dy def getMouseCross(self,name): #FIXME may need to do this incrementally as we started with... if base.mouseWatcherNode.hasMouse(): x,y = base.mouseWatcherNode.getMouse() sx,sy = getattr(self,'__%s_s__'%(name)) dx = (x - sx) * self.XGAIN * self.__winx__ dy = (y - sy) * self.YGAIN * self.__winy__ norm = (dx**2 + dy**2)**.5 cross = x * sy - y * sx return cross * norm @event_callback def home(self, task): self.camera.lookAt(self.cameraBase) taskMgr.remove(task.getName()) return task.cont @event_callback def pan(self, task): """ I don't like it, it's weird! """ invert = -1 magic_number = 15 magic_number = 20 if base.mouseWatcherNode.hasMouse(): x,y = base.mouseWatcherNode.getMouse() sx,sy = getattr(self,'__%s_s__'%(task.getName())) dx = (x - sx) * self.XGAIN * self.__winx__ * magic_number * invert dy = (y - sy) * self.YGAIN * self.__winy__ * magic_number * invert #cx,cy,cz = self.camera.getPos() self.camera.setPos(self.camera,dx,0,dy) setattr(self, '__%s_s__'%task.getName(), (x,y)) #reset each frame to compensate for moving from own position #nx,ny,nz = self.camera.getPos() #dx2, dy2, dz2 = nx-cx, ny-cy, nz-cz #self.camera.setPos(cx,cz,cy) #self.cameraBase.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera #self.cameraTarget.setPos(self.cameraBase,dx2,dy2,dz2) #a hack to move cameraBase as if it were the camera return task.cont @event_callback def zoom_in_slow(self, task, speed = 10): return self.zoom_in(task, speed) #hehe this will work because it just passes the task :) @event_callback def zoom_out_slow(self, task, speed = 10): return self.zoom_out(task, speed) @event_callback def zoom_in_fast(self, task, speed = 1000): return self.zoom_in(task, speed) #hehe this will work because it just passes the task :) @event_callback def zoom_out_fast(self, task, speed = 1000): return self.zoom_out(task, speed) @event_callback def zoom_in(self, task, speed = 100): #FIXME zoom_in and zoom_out still get custom xys even thought they don't use them! self.camera.setPos(self.camera,0,speed,0) taskMgr.remove(task.getName()) return task.cont @event_callback def zoom_out(self, task, speed = 100): self.camera.setPos(self.camera,0,-speed,0) taskMgr.remove(task.getName()) #we do it this way instead of addOnce because we want to add all the tasks in one go return task.cont @event_callback def rotate(self, task): #FIXME disregard orientation acqurie proper mouse movements! dx,dy = self.getMouseDdDf(task.getName()) if self.__cth__ == None: self.__cth__ = self.cameraTarget.getH() if self.__ctp__ == None: self.__ctp__ = self.cameraTarget.getP() self.cameraTarget.setH(self.__cth__ - dx * 10) self.cameraTarget.setP(self.__ctp__ + dy * 10) return task.cont #if we are in camera mode @event_callback def pitch(self, task): dx,dy = self.getMouseDdDf(task.getName()) print('got pitch',dy) return task.cont @event_callback def look(self, task): #AKA heading in hpr dx,dy = self.getMouseDdDf(task.getName()) if self.__ch__ == None: self.__ch__ = self.camera.getH() if self.__cp__ == None: self.__cp__ = self.camera.getP() self.camera.setH(self.__ch__ - dx) self.camera.setP(self.__cp__ + dy) #FIXME when we're clicking this might should be inverted? return task.cont @event_callback def roll(self, task): """ ALWAYS roll with respect to axis of rotation""" if self.__cr__ == None: self.__cr__ = self.cameraTarget.getR() #cross product idiot cross = self.getMouseCross(task.getName()) self.cameraTarget.setR(self.__cr__ - cross * 10 ) return task.cont
class CogdoFlyingCameraManager: def __init__(self, cam, parent, player, level): self._toon = player.toon self._camera = cam self._parent = parent self._player = player self._level = level self._enabled = False def enable(self): if self._enabled: return self._toon.detachCamera() self._prevToonY = 0.0 levelBounds = self._level.getBounds() l = Globals.Camera.LevelBoundsFactor self._bounds = ((levelBounds[0][0] * l[0], levelBounds[0][1] * l[0]), (levelBounds[1][0] * l[1], levelBounds[1][1] * l[1]), (levelBounds[2][0] * l[2], levelBounds[2][1] * l[2])) self._lookAtZ = self._toon.getHeight() + Globals.Camera.LookAtToonHeightOffset self._camParent = NodePath('CamParent') self._camParent.reparentTo(self._parent) self._camParent.setPos(self._toon, 0, 0, 0) self._camParent.setHpr(180, Globals.Camera.Angle, 0) self._camera.reparentTo(self._camParent) self._camera.setPos(0, Globals.Camera.Distance, 0) self._camera.lookAt(self._toon, 0, 0, self._lookAtZ) self._cameraLookAtNP = NodePath('CameraLookAt') self._cameraLookAtNP.reparentTo(self._camera.getParent()) self._cameraLookAtNP.setPosHpr(self._camera.getPos(), self._camera.getHpr()) self._levelBounds = self._level.getBounds() self._enabled = True self._frozen = False self._initCollisions() def _initCollisions(self): self._camCollRay = CollisionRay() camCollNode = CollisionNode('CameraToonRay') camCollNode.addSolid(self._camCollRay) camCollNode.setFromCollideMask(OTPGlobals.WallBitmask | OTPGlobals.CameraBitmask | ToontownGlobals.FloorEventBitmask | ToontownGlobals.CeilingBitmask) camCollNode.setIntoCollideMask(0) self._camCollNP = self._camera.attachNewNode(camCollNode) self._camCollNP.show() self._collOffset = Vec3(0, 0, 0.5) self._collHandler = CollisionHandlerQueue() self._collTrav = CollisionTraverser() self._collTrav.addCollider(self._camCollNP, self._collHandler) self._betweenCamAndToon = {} self._transNP = NodePath('trans') self._transNP.reparentTo(render) self._transNP.setTransparency(True) self._transNP.setAlphaScale(Globals.Camera.AlphaBetweenToon) self._transNP.setBin('fixed', 10000) def _destroyCollisions(self): self._collTrav.removeCollider(self._camCollNP) self._camCollNP.removeNode() del self._camCollNP del self._camCollRay del self._collHandler del self._collOffset del self._betweenCamAndToon self._transNP.removeNode() del self._transNP def freeze(self): self._frozen = True def unfreeze(self): self._frozen = False def disable(self): if not self._enabled: return self._destroyCollisions() self._camera.wrtReparentTo(render) self._cameraLookAtNP.removeNode() del self._cameraLookAtNP self._camParent.removeNode() del self._camParent del self._prevToonY del self._lookAtZ del self._bounds del self._frozen self._enabled = False def update(self, dt = 0.0): self._updateCam(dt) self._updateCollisions() def _updateCam(self, dt): toonPos = self._toon.getPos() camPos = self._camParent.getPos() x = camPos[0] z = camPos[2] toonWorldX = self._toon.getX(render) maxX = Globals.Camera.MaxSpinX toonWorldX = clamp(toonWorldX, -1.0 * maxX, maxX) spinAngle = Globals.Camera.MaxSpinAngle * toonWorldX * toonWorldX / (maxX * maxX) newH = 180.0 + spinAngle self._camParent.setH(newH) spinAngle = spinAngle * (pi / 180.0) distBehindToon = Globals.Camera.SpinRadius * cos(spinAngle) distToRightOfToon = Globals.Camera.SpinRadius * sin(spinAngle) d = self._camParent.getX() - clamp(toonPos[0], *self._bounds[0]) if abs(d) > Globals.Camera.LeewayX: if d > Globals.Camera.LeewayX: x = toonPos[0] + Globals.Camera.LeewayX else: x = toonPos[0] - Globals.Camera.LeewayX x = self._toon.getX(render) + distToRightOfToon boundToonZ = min(toonPos[2], self._bounds[2][1]) d = z - boundToonZ if d > Globals.Camera.MinLeewayZ: if self._player.velocity[2] >= 0 and toonPos[1] != self._prevToonY or self._player.velocity[2] > 0: z = boundToonZ + d * INVERSE_E ** (dt * Globals.Camera.CatchUpRateZ) elif d > Globals.Camera.MaxLeewayZ: z = boundToonZ + Globals.Camera.MaxLeewayZ elif d < -Globals.Camera.MinLeewayZ: z = boundToonZ - Globals.Camera.MinLeewayZ if self._frozen: y = camPos[1] else: y = self._toon.getY(render) - distBehindToon self._camParent.setPos(x, smooth(camPos[1], y), smooth(camPos[2], z)) if toonPos[2] < self._bounds[2][1]: h = self._cameraLookAtNP.getH() if d >= Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._toon, 0, 0, self._lookAtZ) elif d <= -Globals.Camera.MinLeewayZ: self._cameraLookAtNP.lookAt(self._camParent, 0, 0, self._lookAtZ) self._cameraLookAtNP.setHpr(h, self._cameraLookAtNP.getP(), 0) self._camera.setHpr(smooth(self._camera.getHpr(), self._cameraLookAtNP.getHpr())) self._prevToonY = toonPos[1] def _updateCollisions(self): pos = self._toon.getPos(self._camera) + self._collOffset self._camCollRay.setOrigin(pos) direction = -Vec3(pos) direction.normalize() self._camCollRay.setDirection(direction) self._collTrav.traverse(render) nodesInBetween = {} if self._collHandler.getNumEntries() > 0: self._collHandler.sortEntries() for entry in self._collHandler.getEntries(): name = entry.getIntoNode().getName() if name.find('col_') >= 0: np = entry.getIntoNodePath().getParent() if np not in nodesInBetween: nodesInBetween[np] = np.getParent() for np in nodesInBetween.keys(): if np in self._betweenCamAndToon: del self._betweenCamAndToon[np] else: np.setTransparency(True) np.wrtReparentTo(self._transNP) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').hide() elif np.getName().find('platform') >= 0: np.find('**/*Floor').hide() for np, parent in self._betweenCamAndToon.items(): np.wrtReparentTo(parent) np.setTransparency(False) if np.getName().find('lightFixture') >= 0: np.find('**/*floor_mesh').show() elif np.getName().find('platform') >= 0: np.find('**/*Floor').show() self._betweenCamAndToon = nodesInBetween