class Player: def __init__(self, x, y, z, id): self.health = 100 radius = .15 height = 1 shape = BulletCylinderShape(radius, height, ZUp) self.playerNode = BulletCharacterControllerNode(shape, 0.4, str(id)) self.playerNode.setMaxJumpHeight(2.0) self.playerNode.setJumpSpeed(4.0) self.playerNP = base.render.attachNewNode(self.playerNode) self.playerNP.setPos(x, y, z) self.playerModel = Actor('models/soldier.egg', {"idle": "models/soldier_ani_idle.egg", "walk": "models/soldier_ani_walk.egg", "pistol": "models/soldier_ani_pistol.egg", "death": "models/soldier_ani_death.egg",}) self.playerModel.makeSubpart("legs", ["mixamorig:LeftUpLeg", "mixamorig:RightUpLeg"]) self.playerModel.makeSubpart("hips", ["mixamorig:Hips"], ["mixamorig:LeftUpLeg", "mixamorig:RightUpLeg", "mixamorig:Spine"]) self.playerModel.makeSubpart("upperBody", ["mixamorig:Spine"]) self.playerModel.pose("idle", 0, partName="hips") self.playerModel.setH(90) self.playerModel.setScale(.06) self.playerModel.setZ(-.45) self.playerModel.flattenLight() # self.playerModel.setLightOff()self.playerSpine self.playerModel.reparentTo(self.playerNP) self.playerSpine = self.playerModel.controlJoint(None, 'modelRoot', 'mixamorig:Spine') self.hand = self.playerModel.exposeJoint(None, 'modelRoot', 'mixamorig:RightHand') self.spineExpose = self.playerModel.exposeJoint(None, 'modelRoot', 'mixamorig:Spine') self.playerSpine.setH(-7) # player weapon self.weapon = Ak47(self.hand) # player animation self.xSpeed = 0 self.ySpeed = 0 self.animation = Animation(self) self.model = NodePath("MySpineNode") def bendBody(self): self.model.setPos(self.spineExpose, 0, 0, 0) obj = RayCollider.getObjectHit() self.model.lookAt(obj) self.playerSpine.setP(self.model.getP())
class MachineGun: def __init__(self, cycle, mount): self.cycle = cycle self.actor = Actor("../Models/MGActor.egg") self.model = loader.loadModel("../Models/MachineGun.bam") self.actor.reparentTo(mount) self.model.reparentTo(self.actor) self.flashModel = loader.loadModel("../Models/LaserFlash.bam") self.projModel = loader.loadModel("../Models/LaserProj.bam") self.projModel.setScale(.25, 1, .25) self.refNP = self.cycle.trgtrMount.attachNewNode("MGRefNP") self.muzzle = self.actor.exposeJoint(None, "modelRoot", "Muzzle") reloadTime = .25 self.flashLerp = LerpScaleInterval(self.flashModel, reloadTime * .75, Point3(1, 1, 1), Point3(.1, .1, .1)) self.firePar = Parallel(Func(self.setEffects), self.flashLerp) self.fireSeq = Sequence(self.firePar, Func(self.clearEffects), Wait(reloadTime * .25)) def fire(self): if (self.fireSeq.isPlaying() == False): self.refNP.setPos(0, 15, 0) self.fireSeq.start() return def setEffects(self): self.flashModel.reparentTo(self.muzzle) self.projModel.reparentTo(self.muzzle) self.projModel.lookAt(self.refNP.getPos(self.muzzle)) self.projModel.setSy( trueDist(Point3(0, 0, 0), self.refNP.getPos(self.muzzle)) * 2) return def clearEffects(self): self.flashModel.detachNode() self.projModel.detachNode() return def destroy(self): self.actor.delete() self.model.removeNode() self.flashModel.removeNode() self.projModel.removeNode() self.refNP.removeNode() self.cycle = None self.flashLerp = None self.firePar = None self.fireSeq = None return
class ExposedJointRig: def __init__(self, model_name, animations): self.actor = Actor(model_name, animations) # self.actor.update(force=True) exposed_joint_gen = self.mapJoints(self.actor.getPartBundle('modelRoot')) self.exposed_joints = list(exposed_joint_gen) # self.exposed_joints = filter_joints(exposed_joint_gen, excluded_joints) def mapJoints(self, part, prev=None): if isinstance(part, CharacterJoint): curr = self.actor.exposeJoint(None, 'modelRoot', part.getName()) # if prev is not None: # curr = self.actor.exposeJoint(None, 'modelRoot', part.getName()) # else: # curr = self.actor.controlJoint(None, 'modelRoot', part.getName()) yield curr, prev prev = curr for part_child in part.getChildren(): for next_curr, next_prev in self.mapJoints(part_child, prev): yield next_curr, next_prev def createLines(self, color): create_lines(self.exposed_joints, color) def getNumFrames(self, animation_name): return self.actor.getNumFrames(animation_name) def setPlayRate(self, play_rate, animation_name): self.actor.setPlayRate(play_rate, animation_name) def setScale(self, x, y, z): self.actor.setScale(x, y, z) def setPos(self, x, y, z): self.actor.setPos(x, y, z) def reparentTo(self, other): self.actor.reparentTo(other) def pose(self, animation_name, frame): self.actor.pose(animation_name, frame) self.actor.update(force=True) def play(self, animation_name): self.actor.play(animation_name) def loop(self, animation_name): self.actor.loop(animation_name)
class Cycle(DirectObject): def __init__(self, inputManager, track, audio3D, startPos, name, ai = None): self.inputManager = inputManager # Stores a reference to the InputManager to access user input. self.setupVarsNPs(audio3D, startPos, name) self.setupCollisions() # Sets up initial variables, NodePaths, and collision objects. self.track = track # Stores a reference to the track. self.lanes = self.track.trackLanes.lanes # gets a reference to the lanes on the track, to shorten the variable name. startingLane = self.track.trackLanes.getNearestMarker(self).lane # Gets the lane for the closest marker to the cycle. self.uc1 = self.lanes[startingLane][0] self.uc2 = self.lanes[startingLane][1] self.uc3 = self.lanes[startingLane][2] # Sets up 3 variables to store references to the 3 up-coming markers on the # track, ahead of the cycle. These are used by the AI to steer, and by player # cycles to measure progress along the track. if(ai == True): self.ai = CycleAI(self) # if the ai input is passed anything, it won't default to None, and the cycle will create # an AI to control itself. elif(ai == None): self.ai = None taskMgr.add(self.cycleControl, "Cycle Control", sort = int(self.root.getY() + 100)) # If the cycle isn't using an AI, activate player control. The cycle is also given a unique # sort value based on it's distance from the finish line. The unique sort value fixes a bug # in the AI aim code that can cause jittering in the aim when the tasks that control the # cycles don't execute in the same order every frame. # With this set up, if AI == False, the cycle will be completely uncontrolled. self.setupLight() # Calls the method that creates a light to represent the glow of the cycle's discs and engine. def setupVarsNPs(self, audio3D, startPos, name): self.name = name # Stores a unique name for this cycle. self.audio3D = audio3D # Stores a reference to the audio3DManager the cycle will use. self.root = render.attachNewNode("Root") # Creates and stores the NodePath that will be used as the root of the cycle # for the purpose of movement. self.cycle = self.root.attachNewNode("Cycle") # Creates a dummy node to go between self.root and the actualy cycle model. if(startPos == 1): self.root.setPos(5,0,0) self.model = loader.loadModel("../Models/RedCycle.bam") self.turret = loader.loadModel("../Models/RedTurr.bam") elif(startPos == 2): self.root.setPos(-5,-5,0) self.model = loader.loadModel("../Models/BlueCycle.bam") self.turret = loader.loadModel("../Models/BlueTurr.bam") elif(startPos == 3): self.root.setPos(5,-10,0) self.model = loader.loadModel("../Models/GreenCycle.bam") self.turret = loader.loadModel("../Models/GreenTurr.bam") elif(startPos == 4): self.root.setPos(-5,-15,0) self.model = loader.loadModel("../Models/YellowCycle.bam") self.turret = loader.loadModel("../Models/YellowTurr.bam") # Sets the root to a new position according to what place it is given. # Also loads the model and turret of the appropriate color. self.mounts = Actor("../Models/Mounts.egg") # Loads an actor with 3 mounting joints for the moving parts of the cycle. self.model.reparentTo(self.cycle) self.mounts.reparentTo(self.model) # Attaches the model to the go-between node and attaches the mounts to # the model. turretMount = self.mounts.exposeJoint(None, "modelRoot", "Turret") fdMount = self.mounts.exposeJoint(None, "modelRoot", "FrontDisc") rdMount = self.mounts.exposeJoint(None, "modelRoot", "RearDisc") # exposes the mount joints so pieces can be attached to them. self.fd = loader.loadModel("../Models/Disc.bam") self.rd = loader.loadModel("../Models/Disc.bam") # loads the models for the discs. self.turretActor = Actor("../Models/TurretActor.egg") self.turretActor.reparentTo(turretMount) self.turret.reparentTo(self.turretActor) self.trgtrMount = self.turretActor.exposeJoint(None, "modelRoot", "TargeterMount") self.fd.reparentTo(fdMount) self.rd.reparentTo(rdMount) # Attaches the turret and discs to their mounts. self.LMGMount = self.turretActor.exposeJoint(None, "modelRoot", "LMGMount") self.RMGMount = self.turretActor.exposeJoint(None, "modelRoot", "RMGMount") self.LMG = MachineGun(self, self.LMGMount, self.audio3D) self.RMG = MachineGun(self, self.RMGMount, self.audio3D) self.CannonMount = self.turretActor.exposeJoint(None, "modelRoot", "CannonMount") self.cannon = Cannon(self, self.CannonMount, self.audio3D) self.engineSfx = self.audio3D.loadSfx("../Sound/Engine.wav") self.audio3D.attachSoundToObject(self.engineSfx, self.root) self.engineSfx.setPlayRate(.5) self.engineSfx.setLoop(True) self.engineSfx.setVolume(2) self.engineSfx.play() # loads a sound effect for the engine and sets the starting play rate. self.dirNP = self.root.attachNewNode("DirNP") self.refNP = self.root.attachNewNode("RefNP") # Creates and stores two more NodePaths, one to track the direction the cycle # is moving in and another to use as a reference during various calculations # the cycle performs. self.dirVec = Vec3(0,0,0) self.cycleVec = Vec3(0,0,0) self.refVec = Vec3(0,0,0) # Creates and stores 3 vector objects to be used in simulating drift when the # cycle turns. self.speed = 0 self.throttle = 0 self.maxSpeed = 200 self.maxShield = 500 self.shield = self.maxShield self.accel = 25 self.handling = 25 self.maxEnergy = 100 self.energy = self.maxEnergy self.stability = 25 self.shieldRchrg = 10 self.energyRchrg = 5 self.shutDown = False # Sets basic variables for the cycle's racing attributes. self.turning = None self.lean = 0 # Creates two variables to control the cycle's lean self.markerCount = 0 self.currentLap = 0 # Creates two variables that will be used to track the progress # of the cycle on the track. self.freeFall = False self.fallSpeed = 0 # Creates two variables to assist with managing the cycle's falls from # hills and ramps. self.trackNP = render.attachNewNode(self.name + "_TrackNode") # Creates a NodePath to use when setting the cycle's height above the track. # refNP won't serve for this purpose, because it exists in root's coordinate space. # We need a NodePath in render's coordinate space for this purpose. self.active = False # creates a variable that determines if the cycle can be controlled or not. return # setupVarsNPs: Initializes most of the non-collision variables and NodePaths needed by the cycle. def setupCollisions(self): self.shieldCN = CollisionNode(self.name + "_ShieldCN") # Creates a CollisionNode to store the 3 CollisionSpheres that represent the # invisible energy shield surrounding the cycle. self.shieldCN.setPythonTag("owner", self) # Connects a reference to the instance of this class to the shield CollisionNode. # This will make it much easier to identify this cycle when its shield is struck. CS1 = CollisionSphere(0, -.025, .75, .785) CS2 = CollisionSphere(0, -1.075, .85, .835) CS3 = CollisionSphere(0, 1.125, .6, .61) self.shieldCN.addSolid(CS1) self.shieldCN.addSolid(CS2) self.shieldCN.addSolid(CS3) # Creates the 3 CollisionSpheres that make up the shield and adds them into # the CollisionNode. self.shieldCN.setIntoCollideMask(BitMask32.range(2,3)) self.shieldCN.setFromCollideMask(BitMask32.bit(2)) # Sets the BitMasks on the CollisionNode. The From mask has bit 2 turned on, so # the shield can bump into things on bit 2. The Into mask has bits 2, 3, and 4 turned # on so the shield can be struck by things on bit 2 (other cycles), 3 (guns), and 4 (explosions) self.shieldCNP = self.model.attachNewNode(self.shieldCN) # Connects the shield and its 3 spheres to the cycle model and gets a NodePath to # the shield. self.bumpCTrav = CollisionTraverser() self.bumpHan = CollisionHandlerPusher() # Creates a CollisionTraverser and a Pusher-type handler to detect and manage # collisions caused by the cycle's shield. self.bumpHan.addCollider(self.shieldCNP, self.root) # Tells the pusher handler to push back on self.root when self.shieldCNP is # involved in a collision. self.bumpHan.addAgainPattern("%fn-again") # Tells the pusher handler to create an event using the From CollisionNode's # name when it handles recurring collisions. self.bumpCTrav.addCollider(self.shieldCNP, self.bumpHan) # Registers the shield and the handler with the traverser. self.accept(self.name + "_ShieldCN-again", self.bump) # Registers the event that the pusher handler will generate and connects it to # the bump method. self.gRayCN = CollisionNode(self.name + "_GRayCN") # Creates a second CollisionNode to store the rays that will be used for collision # with the ground. self.fRay = CollisionRay(0, .5, 10, 0, 0, -1) self.bRay = CollisionRay(0, -.5, 10, 0, 0, -1) # Creates two rays 10 meters up and points them downward. This time we keep a # reference to the rays because we will need them when organizing their collision data. self.gRayCN.addSolid(self.fRay) self.gRayCN.addSolid(self.bRay) # Adds the rays to the CollisionNode. self.gRayCN.setFromCollideMask(BitMask32.bit(1)) self.gRayCN.setIntoCollideMask(BitMask32.allOff()) # Sets the BitMasks for gRayCN. The From mask has bit 1 on so it can cause collisions # with the ground. The Into mask is turned off completely, because rays should never # be collided into. self.gRayCNP = self.cycle.attachNewNode(self.gRayCN) # Attaches the gRayCN to the cycle and gets a NodePath to it. self.gCTrav = CollisionTraverser() self.gHan = CollisionHandlerQueue() self.gCTrav.addCollider(self.gRayCNP, self.gHan) # Creates a traverser and a Queue-type handler to detect and manage the rays' collisions. # Then registers gRayCNP and the handler with the traverser. self.trgtrCN = CollisionNode(self.name + "_TargeterCN") self.trgtrRay = CollisionRay(0,0,0,0,1,0) self.trgtrCN.addSolid(self.trgtrRay) self.trgtrCN.setFromCollideMask(BitMask32.bit(3)) self.trgtrCN.setIntoCollideMask(BitMask32.allOff()) self.trgtrCNP = self.trgtrMount.attachNewNode(self.trgtrCN) # creates 1 collision ray to represent the line of fire of the cycle for the purpose shooting. # The ray is added to a collision node which is parented to the targeter mount of the turret. self.trgtrCTrav = CollisionTraverser() self.trgtrCHan = CollisionHandlerQueue() self.trgtrCTrav.addCollider(self.trgtrCNP, self.trgtrCHan) # creates a traverser and Queue-type handler to detect and manage the collisions of the # targeter ray, and registers the ray and handler with the traverser. return # setupCollisions: Preps CollisionNodes, collision solids, traversers, and handlers to get them # ready for use. def setupLight(self): self.glow = self.cycle.attachNewNode( PointLight(self.name + "Glow")) self.glow.node().setColor(Vec4(.2,.6,1,1)) # Creates a point light on the cycle and sets it's color to a blue-white. self.glow.node().setAttenuation(Vec3(0,0,.75)) # Sets the attenuation on the point light. This controls the fall-off. self.cycle.setLight(self.glow) self.track.track.setLight(self.glow) # Sets the light to illuminate the cycle and the track. return # setupLight: Creates a point light to represent the glow of the cycle and sets its attributes. Then # sets the light to illuminate the scene. def cycleControl(self, task): if(self.cycle == None): return task.done # Ends the task if the cycle model is removed. dt = globalClock.getDt() if( dt > .20): return task.cont # Gets the amount of time that has passed since the last frame from the global clock. # If the value is too large, there has been a hiccup and the frame will be skipped. if(self.active == True and self.shutDown == False): # limits player control to only occur when self.active is true and # self.shutDown is false. if(self.inputManager.keyMap["up"] == True): self.adjustThrottle("up", dt) elif(self.inputManager.keyMap["down"] == True): self.adjustThrottle("down", dt) # Checks the InputManager for throttle control initiated by the user and performs # the adjustments. if(self.inputManager.keyMap["right"] == True): self.turn("r", dt) self.turning = "r" elif(self.inputManager.keyMap["left"] == True): self.turn("l", dt) self.turning = "l" else: self.turning = None # Checks the InputManager for turning initiated by the user and performs it. # Also updates the self.turning variable to reflect it. if(self.inputManager.keyMap["mouse1"] == True): self.LMG.fire() self.RMG.fire() # If the left mouse button is pressed, fire the machine guns. if(self.inputManager.keyMap["mouse3"] == True): self.cannon.fire() # If the right mouse button is pressed, fire the cannon. aimPoint = self.inputManager.getMouseAim() if(aimPoint != None): self.turretActor.lookAt(render, aimPoint) self.speedCheck(dt) self.simDrift(dt) self.groundCheck(dt) self.move(dt) self.checkMarkers() self.recharge(dt) # Calls the methods that control cycle behavior frame-by-frame. self.bumpCTrav.traverse(render) # Checks for collisions caused by the cycle's shield. return task.cont # cycleControl: Manages the cycle's behavior when under player control. def cameraZoom(self, dir, dt): if(dir == "in"): base.camera.setY(base.camera, 10 * dt) else: base.camera.setY(base.camera, -10 * dt) return # cameraZoom: Moves the camera toward or away from the cycle at a rate of 10 # meters per second. def turn(self, dir, dt): turnRate = self.handling * (2 - (self.speed / self.maxSpeed)) # Determines the current turn rate of the cycle according to its speed. if(dir == "r"): turnRate = -turnRate self.turning = "r" # If this is a right turn, then turnRate should be negative. self.cycle.setH(self.cycle, turnRate * dt) # Rotates the cycle according to the turnRate and time. return # turn: Rotates the cycle based on its speed to execute turns. def adjustThrottle(self, dir, dt): if(dir == "up"): self.throttle += .25 * dt # Increases the throttle setting at a rate of 25% per second. if(self.throttle > 1 ): self.throttle = 1 # Limits the throttle to a maximum of 100% else: self.throttle -= .25 * dt # Decreases the throttle setting at a rate of 25% per second. if(self.throttle < -1 ): self.throttle = -1 # Limits the throttle to a minimum of 100% return # adjustThrottle: Increases or decreases the throttle. def speedCheck(self, dt): if(self.freeFall == False): # The cycle can't accelerate or deccelerate under it's own power if # it's in freefall, so we check to make sure it isn't. tSetting = (self.maxSpeed * self.throttle) # Gets the KpH value that corresponds to the current throttle setting. if(self.speed < tSetting): # Checks if the speed is too low. if((self.speed + (self.accel * dt)) > tSetting): # If so, check if accelerating at the normal rate would raise speed too high. self.speed = tSetting # If so, just set the speed to the throttle setting. else: self.speed += (self.accel * dt) # If accelerating won't raise the speed too high, go ahead and accelerate. elif(self.speed > tSetting): # Checks if the speed is too high. if((self.speed - (self.accel * dt)) < tSetting): # If so, check if decelerating at the normal rate would lower speed too much. self.speed = tSetting # If so, just set the speed to the throttle setting. else: self.speed -= (self.accel * dt) # If decelerating won't loser the speed too much, go ahead and decelerate. else: self.speed -= (self.speed * .125) * dt # If the cycle is in freefall, lower it's speed by 12.5% per second to simulate loss # of momentum to friction. speedRatio = self.speed / self.maxSpeed self.engineSfx.setPlayRate(.5 + speedRatio) # Adjusts the playrate of the engine sound based on speed. return # speedCheck: Controls the speed at which the cycle is moving by adjusting it according to the # throttle, or degrading it over time when in freefall. def simDrift(self, dt): self.refNP.setPos(self.dirNP, 0, 1, 0) self.dirVec.set(self.refNP.getX(), self.refNP.getY(), 0) # Uses refNP to get a vector that describes the facing of dirNP. The height value is # discarded as it is unnecessary. self.refNP.setPos(self.cycle, 0, 1, 0) self.cycleVec.set(self.refNP.getX(), self.refNP.getY(), 0) # Uses refNP to get a vector that describes the facing of the cycle. The height value is # discarded as it is unnecessary. self.refVec.set(0,0,1) # Sets refVec to point straight up. This vector will be the axis used to determine the # difference in the angle between dirNP and the cycle. vecDiff = self.dirVec.signedAngleDeg(self.cycleVec, self.refVec) # Gets a signed angle that describes the difference between the facing of dirNP and # the cycle. if(vecDiff < .1 and vecDiff > -.1): self.dirNP.setHpr(self.cycle.getH(), 0, 0) # if the difference between the two facings is insignificant, set dirNP to face the # same direction as the cycle. else: self.dirNP.setHpr(self.dirNP, vecDiff * dt * 2.5, 0, 0) # If the difference is significant, tell dirNP to slowly rotate to try and catch up # to the cycle's facing. self.dirNP.setP(self.cycle.getP()) self.dirNP.setR(0) # Constrains dirNP pitch and roll to the cycle and 0, respectively. return # simDrift: This function simulates the cycle drifting when it turns by causing the dirNP, which # faces the direction the cycle is moving in, to slowly catch up to the actual facing of the cycle # over time. def groundCheck(self, dt): self.gCTrav.traverse(render) # Checks for collisions between the ground and the CollisionRays attached to the cycle. points = [None, None] # Preps a list to hold the data from the collisions. if(self.gHan.getNumEntries() > 1): # Verifies that at least 2 collisions occured. If not, there's no point in checking # the collisions because we can't get data from both rays. self.gHan.sortEntries() # Arranges the collision entries in the cues from nearest to furthest. for E in range(self.gHan.getNumEntries()): # Iterates through all the entries in the CollisionHandlerQueue entry = self.gHan.getEntry(E) # Stores the current entry in a temporary variable. if(entry.getFrom() == self.fRay and points[0] == None): # Checks if this entry is a collision caused by the front ray, and # verifies that we don't have front ray data for this frame yet. points[0] = entry.getSurfacePoint(render) # Stores the actual point of collision, in the coordinate system of render, # in the first slot of the points list. elif(entry.getFrom() == self.bRay and points[1] == None): # Checks if this entry is a collision caused by the back ray, and # verifies that we don't have back ray data for this frame yet. points[1] = entry.getSurfacePoint(render) # Stores the actual point of collision, in the coordinate system of render, # in the second slot of the points list. if(points[0] == None or points[1] == None): self.teleport() return # If either ray didn't collide with the track, the cycle is going out of bounds # and needs to be teleported back onto the track. else: # If both rays gave us collision data, we can proceed. ''' The following segment of code controls the pitch of the cycle ''' if(self.freeFall == False): # Checks if the cycle is in freefall. If it's not, we'll need to make the cycle's # pitch match the angle of the track. self.refNP.setPos(points[1]) # Sets refNP to the spot on the track where the back ray collided. self.refNP.lookAt(points[0]) # Tells refNP to point at the spot on the track where the front ray collided. pDiff = self.refNP.getP()- self.cycle.getP() # Finds the difference in pitch between refNP and the cycle, which is equivalent # to the difference between the cycle's pitch and the angle of the track. if(pDiff < .1 and pDiff > -.1): self.cycle.setP(self.refNP.getP()) # If the pitch difference is insignificant, set the cycle to match the pitch of # refNP. else: self.cycle.setP(self.cycle, pDiff * dt * 5) # If the difference is significant, smoothly adjust the cycle's pitch toward the # pitch of refNP. elif((self.cycle.getP() - (dt * 10)) > -15): self.cycle.setP(self.cycle, -(dt * 10)) # If the cycle is in freefall and slowly dropping the pitch won't lower it past -15, # go ahead and slowly lower it. else: self.cycle.setP(-15) # If we're in freefall and the cycle's pitch is to low to drop it any further, lock it # to exactly -15. ''' End pitch control ''' ''' The following section of code will control the height of the cycle above the track. ''' if(self.speed >= 0): self.trackNP.setPos(points[0].getX(), points[0].getY(), points[0].getZ()) else: self.trackNP.setPos(points[1].getX(), points[1].getY(), points[1].getZ()) # Set trackNP at the collision point on the leading end of the cycle. height = self.root.getZ(self.trackNP) # Get the height of root as seen from the trackNP. if(height > 2 and self.freeFall == False): self.freeFall = True self.fallSpeed = 0 # If the height is greater than 2 and we aren't in freefall, # enter a freefall state and prep freefall variables. if(self.freeFall == True): self.fallSpeed += (self.track.gravity * 9.8) * dt newHeight = height - (self.fallSpeed * dt) # In a freefall state, begin accelerating the fall speed and # calculate a new height based on that fall speed. else: hDiff = 1 - height # If not in a freefall state, calculate the difference in the actual height and the # desired height. if(hDiff > .01 or hDiff < -.01): newHeight = height + (hDiff * dt * 5) # If the difference is significant, calculate a new height that drifts toward # the desired height. else: newHeight = 1 # If you're close to the desired height, just set it as the calculated new height. if(newHeight >= 0): self.root.setZ(self.trackNP, newHeight) # If the new height is greater than or equal to zero, set it as root's height. else: self.root.setZ(self.trackNP, 0) self.freeFall = False # Otherwise, set the root node to a height of 0, and turn off the freefall state. ''' end of height control code ''' self.cycle.setR(0) # Constrain the cycle's roll to 0. return # groundCheck: Controls the cycle's pitch and it's height above the track. def move(self, dt): mps = self.speed * 1000 / 3600 # Convert kph to meters per second self.refNP.setPos(self.dirNP, 0, 1, 0) self.dirVec.set(self.refNP.getX(), self.refNP.getY(), self.refNP.getZ()) # Uses refNP to get a vector describing the direction dirNP is facing. self.root.setPos(self.root, self.dirVec.getX() * dt * mps, self.dirVec.getY() * dt * mps, self.dirVec.getZ() * dt * mps) # Moves root forward according to the direction vector, speed, and time. currentLean = self.model.getR() # Get the current amount of lean. if(self.turning == "r"): self.lean += 2.5 if(self.lean > 25): self.lean = 25 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) # If the cycle is turning right, increase lean up to 25 and model the frame to lean the cycle. elif(self.turning == "l"): self.lean -= 2.5 if(self.lean < -25): self.lean = -25 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) # If the cycle is turning left, decrease lean down to -25 and roll the model to lean the cycle. else: self.lean = 0 self.model.setR(self.model, (self.lean - currentLean) * dt * 5) # If the cycle isn't turning, set lean to 0 and roll the model back toward upright. self.fd.setH(self.fd, 5 + (20 * self.throttle)) self.rd.setH(self.rd, -5 + (-20 * self.throttle)) return # move: Controls the forward or backward movement of the cycle. def checkMarkers(self): if(self.uc1.checkInFront(self) == True): # Checks if the cycle has passed in front of uc1. self.uc1 = self.uc2 self.uc2 = self.uc3 self.uc3 = self.uc2.nextMarker # If so, get the next set of markers on the track. self.markerCount += 1 # Update the cycle's marker count by one. if(self.uc1 == self.lanes[0][1] or self.uc1 == self.lanes[1][1]): self.currentLap += 1 # If the cycle just passed the first marker, which is at the finish line, increment the lap count. return # checkMarkers: Checks if the nearest marker has been passed, and if so, # updates all the markers, marker count, and lap count if needed. def recharge(self, dt): if(self.energy < self.maxEnergy and self.shutDown == False): # Checks if the cycle should recharge energy. newEnergy = self.energy + (self.energyRchrg * dt) # determines what the new energy level will be. if(newEnergy > self.maxEnergy): self.energy = self.maxEnergy else: self.energy = newEnergy # if the new energy level exceeds to maximum, set # energy to max. Otherwise set energy to new level. if(self.shield <= 0 and self.shutDown == False): self.shutDown = True self.throttle = 0 self.shield = 0 # Checks if the cycle should enter emergency shut down and sets all # the appropriate values if so. if(self.shutDown == True): newShield = self.shield + (self.shieldRchrg * dt) * 10 # finds the new shield level if the cycle is in emergency shut down. if(newShield >= self.maxShield): self.shutDown = False # Ends the emergency shut down when the shield is recharged. elif(self.shield < self.maxShield): newShield = self.shield + (self.shieldRchrg * dt) # finds the new shield level if the cycle is not in emergency shut # down, and needs to recharge its shield. else: return # If the cycle doesn't need to recharge its shield, we're done and # we can exit the method. if(newShield <= self.maxShield): self.shield = newShield else: self.shield = self.maxShield # if the new energy level exceeds to maximum, set # energy to max. Otherwise set energy to new level. return # recharge: Evaluates the shield and energy levels of the cycle and recharges # them if necessary. Also determines if the cycle needs to enter or exit # emergency shut down. def teleport(self): marker = self.track.trackLanes.getNearestMarker(self) markerPos = marker.getPos() self.root.setPos(markerPos.getX(), markerPos.getY(), self.root.getZ()) # Put the cycle back on the track. self.gCTrav.traverse(render) # Checks for collisions between the ground and the CollisionRays attached to the cycle. points = [None, None] # Preps a list to hold the data from the collisions. if(self.gHan.getNumEntries() > 1): # Verifies that at least 2 collisions occured. If not, there's no point in checking # the collisions because we can't get data from both rays. self.gHan.sortEntries() # Arranges the collision entries in the cues from nearest to furthest. for E in range(self.gHan.getNumEntries()): # Iterates through all the entries in the CollisionHandlerQueue entry = self.gHan.getEntry(E) # Stores the current entry in a temporary variable. if(entry.getFrom() == self.fRay and points[0] == None): # Checks if this entry is a collision caused by the front ray, and # verifies that we don't have front ray data for this frame yet. points[0] = entry.getSurfacePoint(render) # Stores the actual point of collision, in the coordinate system of render, # in the first slot of the points list. elif(entry.getFrom() == self.bRay and points[1] == None): # Checks if this entry is a collision caused by the back ray, and # verifies that we don't have back ray data for this frame yet. points[1] = entry.getSurfacePoint(render) # Stores the actual point of collision, in the coordinate system of render, # in the second slot of the points list. if(self.speed >= 0): self.trackNP.setPos(points[0].getX(), points[0].getY(), points[0].getZ()) else: self.trackNP.setPos(points[1].getX(), points[1].getY(), points[1].getZ()) # Set the track node at the collision point on the leading end of the cycle. self.root.setZ(self.trackNP, 1) # Set the root to a height of 1 above trackNP. self.dirNP.setHpr(marker.getHpr()) self.cycle.setHpr(marker.getHpr()) # Reorients dirNP and the cycle to the same facing as the marker we teleported to. self.speed /= 2 # Cuts the speed by half as a penalty for going off the track. return # teleport: Moves the cycle back onto the track, fixes its height, and fixes its orientation. def bump(self, entry): #print(entry.getFromNodePath().getPythonTag("owner").name) #print("has bumped into:") #print(entry.getIntoNodePath().getPythonTag("owner").name) #print("") return # bump: Prints a message to the command prompt when the cycle bumps into another cycle. def hit(self, damage): self.shield -= damage # reduces the shield strength according to the damage. instability = (damage / 2) - self.stability # calculates the instability caused by the damage. if(instability > 0): self.speed -= instability # if the instability is positive, reduce the cycle speed by # the instability. return # hit: Handles tracking damage for the cycle. def getPos(self, ref = None): if(ref == None): return(self.root.getPos()) else: return(self.root.getPos(ref)) # getPos: returns the position of root in the coordinate system of the given NodePath, if one is given. def destroy(self): self.root.removeNode() self.cycle.removeNode() self.mounts.delete() self.turretActor.delete() self.model.removeNode() self.turret.removeNode() self.fd.removeNode() self.rd.removeNode() self.dirNP.removeNode() self.refNP.removeNode() self.trackNP.removeNode() self.shieldCNP.removeNode() self.gRayCNP.removeNode() self.trgtrCNP.removeNode() self.glow.removeNode() # removes all of the cycle's NodePaths from the scene. self.LMG.destroy() self.LMG = None self.RMG.destroy() self.RMG = None self.cannon.destroy() self.cannon = None # Removes the cycle's weapons. self.audio3D.detachSound(self.engineSfx) self.cycle = None # sets self.cycle to None to end player cycle control and notify # any AI that the cycle is being removed. if(self.ai != None): self.ai = None # removes the cycles reference to the AI, if it has one. return # destroy: Cleans up all of the cycles components so they can be removed # from memory.
class DBoard(DistributedObject): def __init__(self, cr): DistributedObject.__init__(self, cr) self.accept("checkBoardAnimationDone", self.checkBoardAnimationDone) base.messenger.send("registerLoadEvent", ["loadBoardDone"]) base.messenger.send("registerLoadEvent", ["loadTableDone"]) self.modelLoadList = {"board": False, "table": False} self.boardAnimation = None self.boardAnimationStarted = False self.lightSun = DirectionalLight('light_sun') self.lightSun.setColorTemperature(5300) self.lightSun.setShadowCaster(True, 2048, 2048) self.lightSunNP = render.attachNewNode(self.lightSun) self.lightSunNP.setPos(-2, 2, 2) self.lightSunNP.lookAt(2, -2, -0.5) self.lightAmb = AmbientLight('light_ambient') #self.lightAmb.setColor((0.1, 0.1, 0.1, 1)) self.lightAmb.setColorTemperature(4500) c = self.lightAmb.getColor() self.lightAmb.setColor((c.x / 2, c.y / 2, c.z / 2, 1)) self.lightAmbNP = render.attachNewNode(self.lightAmb) self.accept("loadDone", self.loadDone) self.boardSceneLoadTask = loader.loadModel( "assets/models/board/BoardScene.bam", callback=self.boardLoaded) self.tableLoadTask = loader.loadModel("assets/models/table/Table.bam", callback=self.tableLoaded) # render lights render.setLight(self.lightSunNP) render.setLight(self.lightAmbNP) def boardLoaded(self, boardScene): """Callback event for when the board model has fully loaded""" self.boardScene = boardScene self.boardFlip = Actor(self.boardScene.find("**/BoardArmature"), copy=False) self.boardFlip.reparentTo(self.boardScene) self.camFly = Actor(self.boardScene.find("**/CameraArmature"), copy=False) self.camFly.reparentTo(self.boardScene) bone = self.camFly.exposeJoint(None, "modelRoot", "CamHolder") base.camLens.setNear(0.01) base.camLens.setFar(100) base.camera.reparentTo(bone) base.camera.setP(-90) # render board self.boardSceneNP = self.boardScene.reparentTo(render) self.setupCollisions() base.messenger.send("loadBoardDone") base.messenger.send("loadDone", ["board"]) def tableLoaded(self, table): """Callback event for when the table model has fully loaded""" self.table = table # render table self.tableNP = self.table.reparentTo(render) base.messenger.send("loadTableDone") base.messenger.send("loadDone", ["table"]) def loadDone(self, model): """Check function to determine if all models have loaded. If all models have been loaded, the boardDone event will be fired.""" self.modelLoadList[model] = True for key, value in self.modelLoadList.items(): if value == False: return self.ignore("loadDone") base.messenger.send("boardDone") def announceGenerate(self): # tell everyone interested, that the board DO has been generated base.messenger.send(self.cr.uniqueName("board_generated"), [self.doId]) # call the base class method DistributedObject.announceGenerate(self) def disable(self): self.ignoreAll() self.boardScene.detachNode() self.table.detachNode() DistributedObject.disable(self) def delete(self): """Cleanup just before deletion of the DO""" # cleanup events self.ignoreAll() # cleanup models self.boardFlip.cleanup() self.camFly.cleanup() self.boardFlip.removeNode() self.camFly.removeNode() self.table.removeNode() self.boardAnimation = None # cleanup light try: render.clearLight(self.lightSunNP) render.clearLight(self.lightAmbNP) except: print("clear lights failed.") self.lightSunNP.removeNode() self.lightAmbNP.removeNode() # cleanup collisions for field in BoardMap.gameMap: field.collisionNP.removeNode() # cleanup other variables self.modelLoadList = {"board": False, "table": False} self.boardAnimation = None self.boardAnimationStarted = False DistributedObject.delete(self) def start(self): """Start the board animation""" taskMgr.step() self.boardAnimationStarted = True self.boardAnimation = Sequence( Parallel(self.boardFlip.actorInterval("BoardFlipUp"), self.camFly.actorInterval("CamFly")), Func(base.messenger.send, "BoardAnimationDone")) self.boardAnimation.start() def checkBoardAnimationDone(self): """Check if the board animation has been stopped and resend the respective event if it has.""" # check if we have an animation and it has actually been started once if self.boardAnimation is not None and self.boardAnimationStarted: # now check if the animation is done if self.boardAnimation.isStopped(): # resend the event base.messenger.send("BoardAnimationDone") def setupCollisions(self): """Setup the collision solids for all fields. NOTE: This can be removed once blend2bam supports invisible collision model export""" for field in BoardMap.gameMap: # create a sphere collision solid cs = CollisionSphere(0, 0, 0, 0.01) cn = CollisionNode("{}-collision".format(field.name)) cn.addSolid(cs) fieldNP = self.boardScene.find("**/{}".format(field.name)) field.collisionNP = fieldNP.attachNewNode(cn) field.collisionNP.setCollideMask(BitMask32(0x80))
class HL2Shotgun(BaseHitscan, HL2ShotgunShared): ModelPath = "phase_14/hl2/w_shotgun/w_shotgun.bam" ModelOrigin = (-0.03, 1.19, -0.14) ModelAngles = (2.29, 347.01, 45) ModelScale = 2 Name = GagGlobals.HL2Shotgun ID = ATTACK_HL2SHOTGUN Hold = ATTACK_HOLD_RIGHT ShellPath = "phase_14/hl2/casing.bam" ShellContactSoundPath = "phase_14/hl2/shell{0}.wav" ShellContactSoundRange = (1, 3) sgDir = 'phase_14/hl2/v_shotgun/panda/opt/' sgActorDef = [sgDir + 'v_shotgun.bam', {'draw': sgDir + 'v_shotgun-draw.egg', 'idle': sgDir + 'v_shotgun-idle01.egg', 'pump': sgDir + 'v_shotgun-pump.egg', 'fire': sgDir + 'v_shotgun-fire01.egg', 'altfire': sgDir + 'v_shotgun-altfire.egg', 'reload1': sgDir + 'v_shotgun-reload1.egg', 'reload2': sgDir + 'v_shotgun-reload2.egg', 'reload3': sgDir + 'v_shotgun-reload3.egg'}] sgFirePath = 'phase_14/hl2/v_shotgun/shotgun_fire7.wav' sgEmptyPath = 'phase_14/hl2/v_shotgun/shotgun_empty.wav' sgDblFirePath = 'phase_14/hl2/v_shotgun/shotgun_dbl_fire7.wav' sgPumpPath = 'phase_14/hl2/v_shotgun/shotgun_cock.wav' sgReloadPaths = ['phase_14/hl2/v_shotgun/shotgun_reload1.wav', 'phase_14/hl2/v_shotgun/shotgun_reload2.wav', 'phase_14/hl2/v_shotgun/shotgun_reload3.wav'] SpecialVM = True def __init__(self): BaseHitscan.__init__(self) self.sgViewModel = None self.fireSound = base.audio3d.loadSfx(self.sgFirePath) self.dblFireSound = base.audio3d.loadSfx(self.sgDblFirePath) self.pumpSound = base.audio3d.loadSfx(self.sgPumpPath) self.emptySound = base.audio3d.loadSfx(self.sgEmptyPath) self.reloadSounds = [] for rl in self.sgReloadPaths: self.reloadSounds.append(base.audio3d.loadSfx(rl)) self.fpMuzzleAttach = None @classmethod def doPrecache(cls): super(HL2Shotgun, cls).doPrecache() precacheActor(cls.sgActorDef) precacheSound(cls.sgFirePath) precacheSound(cls.sgDblFirePath) precacheSound(cls.sgPumpPath) precacheSound(cls.sgEmptyPath) for rl in cls.sgReloadPaths: precacheSound(rl) precacheModel(cls.ShellPath) for i in xrange(cls.ShellContactSoundRange[0], cls.ShellContactSoundRange[1] + 1): precacheSound(cls.ShellContactSoundPath.format(i)) def addPrimaryPressData(self, dg): CIGlobals.putVec3(dg, camera.getPos(render)) CIGlobals.putVec3(dg, camera.getQuat(render).getForward()) def addSecondaryPressData(self, dg): self.addPrimaryPressData(dg) def __doBob(self): self.setAnimTrack(self.getBobSequence('firehose', 30, 30, 1.0), startNow = True, looping = True) def cleanup(self): if self.sgViewModel: self.sgViewModel.cleanup() self.sgViewModel.removeNode() self.sgViewModel = None self.fpMuzzleAttach = None if self.fireSound: base.audio3d.detachSound(self.fireSound) self.fireSound = None if self.dblFireSound: base.audio3d.detachSound(self.dblFireSound) self.dblFireSound = None if self.pumpSound: base.audio3d.detachSound(self.pumpSound) self.pumpSound = None if self.emptySound: base.audio3d.detachSound(self.emptySound) self.emptySound = None if self.reloadSounds: for snd in self.reloadSounds: base.audio3d.detachSound(snd) self.reloadSounds = None BaseHitscan.cleanup(self) def load(self): BaseHitscan.load(self) base.audio3d.attachSoundToObject(self.fireSound, self.avatar) base.audio3d.attachSoundToObject(self.dblFireSound, self.avatar) base.audio3d.attachSoundToObject(self.pumpSound, self.avatar) base.audio3d.attachSoundToObject(self.emptySound, self.avatar) for s in self.reloadSounds: base.audio3d.attachSoundToObject(s, self.avatar) if self.isLocal(): self.sgViewModel = Actor(self.sgActorDef[0], self.sgActorDef[1]) self.sgViewModel.setPlayRate(self.Speed, "idle") self.sgViewModel.node().setBounds(OmniBoundingVolume()) self.sgViewModel.node().setFinal(1) self.sgViewModel.setBlend(frameBlend = base.config.GetBool('interpolate-frames', False)) self.sgViewModel.setH(180) self.fpMuzzleAttach = self.sgViewModel.exposeJoint(None, "modelRoot", "ValveBiped.Gun") def equip(self): if not BaseHitscan.equip(self): return False if self.isFirstPerson(): fpsCam = self.getFPSCam() fpsCam.swapViewModel(self.sgViewModel, 54.0) toonTrack = Sequence(Func(self.avatar.setForcedTorsoAnim, 'firehose'), self.getAnimationTrack('firehose', endFrame = 30), Func(self.__doBob)) self.setAnimTrack(toonTrack, startNow = True) return True def unEquip(self): if not BaseHitscan.unEquip(self): return False if self.isFirstPerson(): self.getFPSCam().restoreViewModel() return True def __emitShell(self): def __shellThink(shell, task): if task.time > 3.0: base.physicsWorld.remove(shell.node()) shell.removeNode() return task.done if not hasattr(task, 'didHitNoise'): task.didHitNoise = False if not task.didHitNoise: contact = base.physicsWorld.contactTest(shell.node()) if contact.getNumContacts() > 0: task.didHitNoise = True hitNoise = base.loadSfxOnNode(self.ShellContactSoundPath.format(random.randint(*self.ShellContactSoundRange)), shell) hitNoise.play() return task.cont from panda3d.bullet import BulletCylinderShape, BulletRigidBodyNode, ZUp scale = 0.75 shape = BulletCylinderShape(0.07 * scale, 0.47 * scale, ZUp) rbnode = BulletRigidBodyNode('shellrbnode') rbnode.setMass(1.0) rbnode.addShape(shape) rbnode.setCcdMotionThreshold(1e-7) rbnode.setCcdSweptSphereRadius(0.07 * scale) rbnp = render.attachNewNode(rbnode) mdl = loader.loadModel(self.ShellPath) mdl.reparentTo(rbnp) mdl.setScale(0.3 * scale, 0.7 * scale, 0.3 * scale) mdl.setP(90) mdl.setTransparency(True, 1) rbnp.setPos(camera, (1, 2, -0.5)) rbnp.setHpr(camera, (0, -90, 0)) localEjectDir = Vec3(1, 0, 0.3) rbnode.applyCentralImpulse(camera.getQuat(render).xform(localEjectDir) * 7) base.physicsWorld.attach(rbnode) taskMgr.add(__shellThink, 'shellThink', extraArgs = [rbnp], appendTask = True) def onSetAction(self, action): if action == self.StatePump: self.pumpSound.play() elif action == self.StateFire: self.fireSound.play() elif action == self.StateDblFire: self.dblFireSound.play() elif action == self.StateReload: sound = random.choice(self.reloadSounds) sound.play() def onSetAction_firstPerson(self, action): track = Sequence() vm = self.getViewModel() fpsCam = self.getFPSCam() if action in [self.StateFire, self.StateDblFire]: CIGlobals.makeMuzzleFlash(self.fpMuzzleAttach, (-0.03, 0.51, 32.45), (0, -90, 0), 7.5) if action == self.StateIdle: track.append(Func(vm.loop, "idle")) elif action == self.StateDraw: track.append(ActorInterval(vm, "draw", playRate=self.Speed)) elif action == self.StatePump: track.append(Func(self.pumpSound.play)) track.append(Func(self.__emitShell)) track.append(ActorInterval(vm, "pump", playRate=self.Speed)) elif action == self.StateFire: fpsCam.addViewPunch(Vec3(random.uniform(-2, 2), random.uniform(2, 1), 0)) track.append(Func(self.fireSound.play)) track.append(ActorInterval(vm, "fire", playRate=self.Speed)) elif action == self.StateDblFire: fpsCam.addViewPunch(Vec3(0, random.uniform(-5, 5), 0)) track.append(Func(self.dblFireSound.play)) track.append(ActorInterval(vm, "altfire", playRate=self.Speed)) elif action == self.StateReload: sound = random.choice(self.reloadSounds) track.append(Func(sound.play)) track.append(ActorInterval(vm, "reload2", playRate=self.Speed)) elif action == self.StateBeginReload: track.append(ActorInterval(vm, "reload1", playRate=self.Speed)) elif action == self.StateEndReload: track.append(ActorInterval(vm, "reload3", playRate=self.Speed)) fpsCam.setVMAnimTrack(track)
class LookingGrippingDemo(ShowBase): def __init__(self): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) # This code puts the standard title and instruction text on screen self.title = OnscreenText(text="Panda3D: Tutorial - Joint Manipulation", fg=(1, 1, 1, 1), parent=base.a2dBottomRight, align=TextNode.ARight, pos=(-0.1, 0.1), shadow=(0, 0, 0, .5), scale=.08) self.onekeyText = genLabelText("ESC: Quit", 1) self.onekeyText = genLabelText("[1]: Teapot", 2) self.twokeyText = genLabelText("[2]: Candy cane", 3) self.threekeyText = genLabelText("[3]: Banana", 4) self.fourkeyText = genLabelText("[4]: Sword", 5) # Set up key input self.accept('escape', sys.exit) self.accept('1', self.switchObject, [0]) self.accept('2', self.switchObject, [1]) self.accept('3', self.switchObject, [2]) self.accept('4', self.switchObject, [3]) base.disableMouse() # Disable mouse-based camera-control camera.setPos(0, -15, 2) # Position the camera self.eve = Actor("models/eve", # Load our animated charachter {'walk': "models/eve_walk"}) self.eve.reparentTo(render) # Put it in the scene # Now we use controlJoint to get a NodePath that's in control of her neck # This must be done before any animations are played self.eveNeck = self.eve.controlJoint(None, 'modelRoot', 'Neck') # We now play an animation. An animation must be played, or at least posed # for the nodepath we just got from controlJoint to actually effect the # model self.eve.actorInterval("walk", playRate=2).loop() # Now we add a task that will take care of turning the head taskMgr.add(self.turnHead, "turnHead") # Now we will expose the joint the hand joint. ExposeJoint allows us to # get the position of a joint while it is animating. This is different than # controlJonit which stops that joint from animating but lets us move it. # This is particularly usefull for putting an object (like a weapon) in an # actor's hand self.rightHand = self.eve.exposeJoint(None, 'modelRoot', 'RightHand') # This is a table with models, positions, rotations, and scales of objects to # be attached to our exposed joint. These are stock models and so they needed # to be repositioned to look right. positions = [("teapot", (0, -.66, -.95), (90, 0, 90), .4), ("models/candycane", (.15, -.99, -.22), (90, 0, 90), 1), ("models/banana", (.08, -.1, .09), (0, -90, 0), 1.75), ("models/sword", (.11, .19, .06), (0, 0, 90), 1)] self.models = [] # A list that will store our models objects for row in positions: np = loader.loadModel(row[0]) # Load the model np.setPos(row[1][0], row[1][1], row[1][2]) # Position it np.setHpr(row[2][0], row[2][1], row[2][2]) # Rotate it np.setScale(row[3]) # Scale it # Reparent the model to the exposed joint. That way when the joint moves, # the model we just loaded will move with it. np.reparentTo(self.rightHand) self.models.append(np) # Add it to our models list self.switchObject(0) # Make object 0 the first shown self.setupLights() # Put in some default lighting # This is what we use to change which object it being held. It just hides all of # the objects and then unhides the one that was selected def switchObject(self, i): for np in self.models: np.hide() self.models[i].show() # This task gets the position of mouse each frame, and rotates the neck based # on it. def turnHead(self, task): # Check to make sure the mouse is readable if base.mouseWatcherNode.hasMouse(): # get the mouse position as a LVector2. The values for each axis are from -1 to # 1. The top-left is (-1,-1), the bottom right is (1,1) mpos = base.mouseWatcherNode.getMouse() # Here we multiply the values to get the amount of degrees to turn # Restrain is used to make sure the values returned by getMouse are in the # valid range. If this particular model were to turn more than this, # significant tearing would be visable self.eveNeck.setP(clamp(mpos.getX()) * 50) self.eveNeck.setH(clamp(mpos.getY()) * 20) return Task.cont # Task continues infinitely def setupLights(self): # Sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.4, .4, .35, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 8, -2.5)) directionalLight.setColor((0.9, 0.8, 0.9, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class World(DirectObject): def __init__(self): #This code puts the standard title and instuction text on screen self.title = OnscreenText(text="Panda3D: Embots - Joint Manipulation", style=1, fg=(1,1,1,1), pos=(0.8,-0.95), scale = .07) #setup key input self.accept('escape', sys.exit) #base.disableMouse() #Disable mouse-based camera-control #camera.setPos(0,0,-40) #Position the camera #camera.setHpr(0,90,0) #load the agent and parent it to the world self.agent = Actor("models/agent") self.agent.reparentTo(render) self.agent.setScale(1) #load the teapot (representing the IK constraint) #to be parented later on self.teapot = loader.loadModel('models/teapot') self.teapot.setScale(0.2) #instanciate a list in order to keep track of kinematic joints joints #in python runtime #if nothing points towards those joints, they get flushed by #python's garbage collector self.jointList = [] #create the SMR skeleton (IK version of agent skeleton) self.agentSMRIK = SMRPy.SmrKinematicChain(True,True,'agent') self.createKinematicChain(self.agent, self.agentSMRIK, 'rclavicle', '', 0) #expose the beginning of the kinematic chain in order to #reparent the kinematic cosntraint (teapot) rclavicleJoint = self.agent.exposeJoint(None,"modelRoot","spine4") self.teapot.reparentTo(rclavicleJoint) #get a reference towards the end of the kinematic chain to be created myJoint = self.agentSMRIK.getJointByName("rhand") # create one constraint (will be graphicaly represented by a teapot) self.myConstraint = SMRPy.SmrIKConstraint() #attach a joint from which the distance contraint-joint #will be calculated self.myConstraint.setRelatedJointptr(myJoint) #in order to take into account skin layer, an offset #may be specified on the constraint myConstraintOffset = SMRPy.SmrVector3(0.0,0.0,0.0) self.myConstraint.setOffset(myConstraintOffset) #create the kinematic solver and bind the constaint to it self.myKinematicSolver = SMRPy.SmrGSMMSolver(self.agentSMRIK) self.myKinematicSolver.addConstraintPtr(self.myConstraint) self.accept('arrow_up', self.moveTargetUp ) self.accept('arrow_down', self.moveTargetDown ) self.accept('arrow_left', self.moveTargetLeft ) self.accept('arrow_right', self.moveTargetRight ) self.accept('page_up', self.moveTargetToward ) self.accept('page_down', self.moveTargetForward ) #let's rock ! (one IK step every tenth of a second) taskMgr.doMethodLater(0.1, self.ikStep, "ikStep") #----------------------------------------------------------------------------# # and the rest is litterature... # #----------------------------------------------------------------------------# def moveTargetUp(self): tPosX += 0.1 def moveTargetDown(self): tPosX -= 0.1 def moveTargetRight(self): tPosZ += 0.1 def moveTargetLeft(self): tPosZ -= 0.1 def moveTargetToward(self): tPosY += 0.1 def moveTargetForward(self): tPosY -= 0.1 def ikStep(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.myConstraint.setPosition(tPosX , tPosY , tPosZ) self.teapot.setPos(restrain(tPosX,tPosY,tPosZ)) self.myKinematicSolver.process() self.updatePandaSkeleton(self.agent, self.agentSMRIK, 'rclavicle') return Task.again self.setupLights() def setupLights(self): lAttrib = LightAttrib.makeAllOff() ambientLight = AmbientLight( "ambientLight" ) ambientLight.setColor( Vec4(.4, .4, .35, 1) ) lAttrib = lAttrib.addLight( ambientLight ) directionalLight = DirectionalLight( "directionalLight" ) directionalLight.setDirection( Vec3( 0, 8, -2.5 ) ) directionalLight.setColor( Vec4( 0.9, 0.8, 0.9, 1 ) ) lAttrib = lAttrib.addLight( directionalLight ) render.attachNewNode( directionalLight.upcastToPandaNode() ) render.attachNewNode( ambientLight.upcastToPandaNode() ) render.node().setAttrib( lAttrib ) def createKinematicChain(self, _pandaAgent, _smrIKSkel, _initialJointName, _parentName, _weight): #get the agent's currentJoint currentPandaJoint = _pandaAgent.getJoints(_initialJointName) currentPandaCJoint = _pandaAgent.controlJoint(None, 'modelRoot', _initialJointName) #get the first joint's position position = currentPandaCJoint.getPos() if (currentPandaJoint[0].getNumChildren() == 0): newJoint = SMRPy.SmrKinematicJoint(True) newJoint.setEndVect(position.getX(),position.getY(),position.getZ()); else: newJoint = SMRPy.SmrKinematicJoint(False) newJoint.setPos(position.getX(),position.getY(),position.getZ()) #print "position", position.getX(), position.getY(), position.getZ() #newJoint.setRot(0,0,0) newJoint.setParentName(_parentName) newJoint.setName(_initialJointName) rotZ = (currentPandaCJoint.getH()/180.0)*3.14159; rotX = (currentPandaCJoint.getP()/180.0)*3.14159; rotY = (currentPandaCJoint.getR()/180.0)*3.14159; print rotX, rotY, rotZ, currentPandaCJoint.getName() # remove the setRot function reveal in C++, error prone newJoint.addDof(SMRPy.SmrVector3(0.0,0.0,1.0), rotZ - 1.0, rotZ + 1.0, rotZ, 0.05*_weight); newJoint.addDof(SMRPy.SmrVector3(1.0,0.0,0.0), rotX - 1.0, rotX + 1.0, rotX, 0.05*_weight); newJoint.addDof(SMRPy.SmrVector3(0.0,1.0,0.0), rotY, rotY, rotY, 0); _weight += 0.5 #print newJoint.getName() print _initialJointName, 'numchildren : ', currentPandaJoint[0].getNumChildren() self.jointList.append(newJoint) _smrIKSkel.insertJoint(newJoint) for i in range(currentPandaJoint[0].getNumChildren()): childJoint = currentPandaJoint[0].getChild(i) childName = childJoint.getName() #print(childName) self.createKinematicChain(_pandaAgent, _smrIKSkel, childName, _initialJointName, _weight) def updatePandaSkeleton(self, _pandaSkeleton, _smrSkeleton, _startJointName): currentPandaJoint = _pandaSkeleton.getJoints(_startJointName) currentPandaCJoint = _pandaSkeleton.controlJoint(None, 'modelRoot', _startJointName) currentSmrJoint = _smrSkeleton.getJointByName(_startJointName) self.synchronize(currentPandaCJoint, currentSmrJoint) for i in range(currentPandaJoint[0].getNumChildren()): childJoint = currentPandaJoint[0].getChild(i) childName = childJoint.getName() self.updatePandaSkeleton(_pandaSkeleton, _smrSkeleton, childName) def synchronize(self, _pandaCJoint, _smrJoint): #_smrJoint.setRot(3.14/20.0,0,0); smrQuaternion = _smrJoint.getRot() pandaQuaternion = Quat() pandaQuaternion.setI(smrQuaternion.getX()) pandaQuaternion.setJ(smrQuaternion.getY()) pandaQuaternion.setK(smrQuaternion.getZ()) pandaQuaternion.setR(smrQuaternion.getW()) _pandaCJoint.setQuat(pandaQuaternion)
class IsisAgent(kinematicCharacterController, DirectObject): @classmethod def setPhysics(cls, physics): """ This method is set in src.loader when the generators are loaded into the namespace. This frees the environment definitions (in scenario files) from having to pass around the physics parameter that is required for all IsisObjects """ cls.physics = physics def __init__(self, name, queueSize=100): # load the model and the different animations for the model into an Actor object. self.actor = Actor( "media/models/boxman", {"walk": "media/models/boxman-walk", "idle": "media/models/boxman-idle"} ) self.actor.setScale(1.0) self.actor.setH(0) # self.actor.setLODAnimation(10,5,2) # slows animation framerate when actor is far from camera, if you can figure out reasonable params self.actor.setColorScale(random.random(), random.random(), random.random(), 1.0) self.actorNodePath = NodePath("agent-%s" % name) self.activeModel = self.actorNodePath self.actorNodePath.reparentTo(render) self.actor.reparentTo(self.actorNodePath) self.name = name self.isMoving = False # initialize ODE controller kinematicCharacterController.__init__(self, IsisAgent.physics, self.actorNodePath) self.setGeomPos(self.actorNodePath.getPos(render)) """ Additional Direct Object that I use for convenience. """ self.specialDirectObject = DirectObject() """ How high above the center of the capsule you want the camera to be when walking and when crouching. It's related to the values in KCC. """ self.walkCamH = 0.7 self.crouchCamH = 0.2 self.camH = self.walkCamH """ This tells the Player Controller what we're aiming at. """ self.aimed = None self.isSitting = False self.isDisabled = False """ The special direct object is used for trigger messages and the like. """ # self.specialDirectObject.accept("ladder_trigger_enter", self.setFly, [True]) # self.specialDirectObject.accept("ladder_trigger_exit", self.setFly, [False]) self.actor.makeSubpart("arms", ["LeftShoulder", "RightShoulder"]) # Expose agent's right hand joint to attach objects to self.player_right_hand = self.actor.exposeJoint(None, "modelRoot", "Hand.R") self.player_left_hand = self.actor.exposeJoint(None, "modelRoot", "Hand.L") self.right_hand_holding_object = None self.left_hand_holding_object = None # don't change the color of things you pick up self.player_right_hand.setColorScaleOff() self.player_left_hand.setColorScaleOff() self.player_head = self.actor.exposeJoint(None, "modelRoot", "Head") self.neck = self.actor.controlJoint(None, "modelRoot", "Head") self.controlMap = { "turn_left": 0, "turn_right": 0, "move_forward": 0, "move_backward": 0, "move_right": 0, "move_left": 0, "look_up": 0, "look_down": 0, "look_left": 0, "look_right": 0, "jump": 0, } # see update method for uses, indices are [turn left, turn right, move_forward, move_back, move_right, move_left, look_up, look_down, look_right, look_left] # turns are in degrees per second, moves are in units per second self.speeds = [270, 270, 5, 5, 5, 5, 60, 60, 60, 60] self.originalPos = self.actor.getPos() bubble = loader.loadTexture("media/textures/thought_bubble.png") # bubble.setTransparency(TransparencyAttrib.MAlpha) self.speech_bubble = DirectLabel( parent=self.actor, text="", text_wordwrap=10, pad=(3, 3), relief=None, text_scale=(0.3, 0.3), pos=(0, 0, 3.6), frameColor=(0.6, 0.2, 0.1, 0.5), textMayChange=1, text_frame=(0, 0, 0, 1), text_bg=(1, 1, 1, 1), ) # self.myImage= self.speech_bubble.setTransparency(TransparencyAttrib.MAlpha) # stop the speech bubble from being colored like the agent self.speech_bubble.setColorScaleOff() self.speech_bubble.component("text0").textNode.setCardDecal(1) self.speech_bubble.setBillboardAxis() # hide the speech bubble from IsisAgent's own camera self.speech_bubble.hide(BitMask32.bit(1)) self.thought_bubble = DirectLabel( parent=self.actor, text="", text_wordwrap=9, text_frame=(1, 0, -2, 1), text_pos=(0, 0.5), text_bg=(1, 1, 1, 0), relief=None, frameSize=(0, 1.5, -2, 3), text_scale=(0.18, 0.18), pos=(0, 0.2, 3.6), textMayChange=1, image=bubble, image_pos=(0, 0.1, 0), sortOrder=5, ) self.thought_bubble.setTransparency(TransparencyAttrib.MAlpha) # stop the speech bubble from being colored like the agent self.thought_bubble.setColorScaleOff() self.thought_bubble.component("text0").textNode.setFrameColor(1, 1, 1, 0) self.thought_bubble.component("text0").textNode.setFrameAsMargin(0.1, 0.1, 0.1, 0.1) self.thought_bubble.component("text0").textNode.setCardDecal(1) self.thought_bubble.setBillboardAxis() # hide the thought bubble from IsisAgent's own camera self.thought_bubble.hide(BitMask32.bit(1)) # disable by default self.thought_bubble.hide() self.thought_filter = {} # only show thoughts whose values are in here self.last_spoke = 0 # timers to keep track of last thought/speech and self.last_thought = 0 # hide visualizations # put a camera on ralph self.fov = NodePath(Camera("RaphViz")) self.fov.node().setCameraMask(BitMask32.bit(1)) # position the camera to be infront of Boxman's face. self.fov.reparentTo(self.player_head) # x,y,z are not in standard orientation when parented to player-Head self.fov.setPos(0, 0.2, 0) # if P=0, canrea is looking directly up. 90 is back of head. -90 is on face. self.fov.setHpr(0, -90, 0) lens = self.fov.node().getLens() lens.setFov(60) # degree field of view (expanded from 40) lens.setNear(0.2) # self.fov.node().showFrustum() # displays a box around his head # self.fov.place() self.prevtime = 0 self.current_frame_count = 0 self.isSitting = False self.isDisabled = False self.msg = None self.actorNodePath.setPythonTag("agent", self) # Initialize the action queue, with a maximum length of queueSize self.queue = [] self.queueSize = queueSize self.lastSense = 0 def setLayout(self, layout): """ Dummy method called by spatial methods for use with objects. Doesn't make sense for an agent that can move around.""" pass def setPos(self, pos): """ Wrapper to set the position of the ODE geometry, which in turn sets the visual model's geometry the next time the update() method is called. """ self.setGeomPos(pos) def setPosition(self, pos): self.setPos(pos) def reparentTo(self, parent): self.actorNodePath.reparentTo(parent) def setControl(self, control, value): """Set the state of one of the character's movement controls. """ self.controlMap[control] = value def get_objects_in_field_of_vision(self, exclude=["isisobject"]): """ This works in an x-ray style. Fast. Works best if you listen to http://en.wikipedia.org/wiki/Rock_Art_and_the_X-Ray_Style while you use it. needs to exclude isisobjects since they cannot be serialized """ objects = {} for obj in base.render.findAllMatches("**/IsisObject*"): if not obj.hasPythonTag("isisobj"): continue o = obj.getPythonTag("isisobj") bounds = o.activeModel.getBounds() bounds.xform(o.activeModel.getMat(self.fov)) if self.fov.node().isInView(o.activeModel.getPos(self.fov)): pos = o.activeModel.getPos(render) pos = (pos[0], pos[1], pos[2] + o.getHeight() / 2) p1 = self.fov.getRelativePoint(render, pos) p2 = Point2() self.fov.node().getLens().project(p1, p2) p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1])) object_dict = {} if "x_pos" not in exclude: object_dict["x_pos"] = p3[0] if "y_pos" not in exclude: object_dict["y_pos"] = p3[2] if "distance" not in exclude: object_dict["distance"] = o.activeModel.getDistance(self.fov) if "orientation" not in exclude: object_dict["orientation"] = o.activeModel.getH(self.fov) if "actions" not in exclude: object_dict["actions"] = o.list_actions() if "isisobject" not in exclude: object_dict["isisobject"] = o # add item to dinctionary objects[o] = object_dict return objects def get_agents_in_field_of_vision(self): """ This works in an x-ray vision style as well""" agents = {} for agent in base.render.findAllMatches("**/agent-*"): if not agent.hasPythonTag("agent"): continue a = agent.getPythonTag("agent") bounds = a.actorNodePath.getBounds() bounds.xform(a.actorNodePath.getMat(self.fov)) pos = a.actorNodePath.getPos(self.fov) if self.fov.node().isInView(pos): p1 = self.fov.getRelativePoint(render, pos) p2 = Point2() self.fov.node().getLens().project(p1, p2) p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1])) agentDict = { "x_pos": p3[0], "y_pos": p3[2], "distance": a.actorNodePath.getDistance(self.fov), "orientation": a.actorNodePath.getH(self.fov), } agents[a] = agentDict return agents def in_view(self, isisobj): """ Returns true iff a particular isisobject is in view """ return len( filter(lambda x: x["isisobject"] == isisobj, self.get_objects_in_field_of_vision(exclude=[]).values()) ) def get_objects_in_view(self): """ Gets objects through ray tracing. Slow""" return self.picker.get_objects_in_view() def control__turn_left__start(self, speed=None): self.setControl("turn_left", 1) self.setControl("turn_right", 0) if speed: self.speeds[0] = speed return "success" def control__turn_left__stop(self): self.setControl("turn_left", 0) return "success" def control__turn_right__start(self, speed=None): self.setControl("turn_left", 0) self.setControl("turn_right", 1) if speed: self.speeds[1] = speed return "success" def control__turn_right__stop(self): self.setControl("turn_right", 0) return "success" def control__move_forward__start(self, speed=None): self.setControl("move_forward", 1) self.setControl("move_backward", 0) if speed: self.speeds[2] = speed return "success" def control__move_forward__stop(self): self.setControl("move_forward", 0) return "success" def control__move_backward__start(self, speed=None): self.setControl("move_forward", 0) self.setControl("move_backward", 1) if speed: self.speeds[3] = speed return "success" def control__move_backward__stop(self): self.setControl("move_backward", 0) return "success" def control__move_left__start(self, speed=None): self.setControl("move_left", 1) self.setControl("move_right", 0) if speed: self.speeds[4] = speed return "success" def control__move_left__stop(self): self.setControl("move_left", 0) return "success" def control__move_right__start(self, speed=None): self.setControl("move_right", 1) self.setControl("move_left", 0) if speed: self.speeds[5] = speed return "success" def control__move_right__stop(self): self.setControl("move_right", 0) return "success" def control__look_left__start(self, speed=None): self.setControl("look_left", 1) self.setControl("look_right", 0) if speed: self.speeds[9] = speed return "success" def control__look_left__stop(self): self.setControl("look_left", 0) return "success" def control__look_right__start(self, speed=None): self.setControl("look_right", 1) self.setControl("look_left", 0) if speed: self.speeds[8] = speed return "success" def control__look_right__stop(self): self.setControl("look_right", 0) return "success" def control__look_up__start(self, speed=None): self.setControl("look_up", 1) self.setControl("look_down", 0) if speed: self.speeds[6] = speed return "success" def control__look_up__stop(self): self.setControl("look_up", 0) return "success" def control__look_down__start(self, speed=None): self.setControl("look_down", 1) self.setControl("look_up", 0) if speed: self.speeds[7] = speed return "success" def control__look_down__stop(self): self.setControl("look_down", 0) return "success" def control__jump(self): self.setControl("jump", 1) return "success" def control__view_objects(self): """ calls a raytrace to to all objects in view """ objects = self.get_objects_in_field_of_vision() self.control__say("If I were wearing x-ray glasses, I could see %i items" % len(objects)) print "Objects in view:", objects return objects def control__sense(self): """ perceives the world, returns percepts dict """ percepts = dict() # eyes: visual matricies # percepts['vision'] = self.sense__get_vision() # objects in purview (cheating object recognition) percepts["objects"] = self.sense__get_objects() # global position in environment - our robots can have GPS :) percepts["position"] = self.sense__get_position() # language: get last utterances that were typed percepts["language"] = self.sense__get_utterances() # agents: returns a map of agents to a list of actions that have been sensed percepts["agents"] = self.sense__get_agents() print percepts return percepts def control__think(self, message, layer=0): """ Changes the contents of an agent's thought bubble""" # only say things that are checked in the controller if self.thought_filter.has_key(layer): self.thought_bubble.show() self.thought_bubble["text"] = message # self.thought_bubble.component('text0').textNode.setShadow(0.05, 0.05) # self.thought_bubble.component('text0').textNode.setShadowColor(self.thought_filter[layer]) self.last_thought = 0 return "success" def control__say(self, message="Hello!"): self.speech_bubble["text"] = message self.last_spoke = 0 return "success" """ Methods explicitly for IsisScenario files """ def put_in_front_of(self, isisobj): # find open direction pos = isisobj.getGeomPos() direction = render.getRelativeVector(isisobj, Vec3(0, 1.0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], [isisobj.geom]) print "CLOSEST", closestEntry, closestObject if closestObject == None: self.setPosition(pos + Vec3(0, 2, 0)) else: print "CANNOT PLACE IN FRONT OF %s BECAUSE %s IS THERE" % (isisobj, closestObject) direction = render.getRelativeVector(isisobj, Vec3(0, -1.0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], [isisobj.geom]) if closestEntry == None: self.setPosition(pos + Vec3(0, -2, 0)) else: print "CANNOT PLACE BEHIND %s BECAUSE %s IS THERE" % (isisobj, closestObject) direction = render.getRelativeVector(isisobj, Vec3(1, 0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew( "aimRay", 5, [pos, direction], [isisobj.geom] ) if closestEntry == None: self.setPosition(pos + Vec3(2, 0, 0)) else: print "CANNOT PLACE TO LEFT OF %s BECAUSE %s IS THERE" % (isisobj, closestObject) # there's only one option left, do it anyway self.setPosition(pos + Vec3(-2, 0, 0)) # rotate agent to look at it self.actorNodePath.setPos(self.getGeomPos()) self.actorNodePath.lookAt(pos) self.setH(self.actorNodePath.getH()) def put_in_right_hand(self, target): return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand) def put_in_left_hand(self, target): return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand) def __get_object_in_center_of_view(self): direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.fov.getPos(render) exclude = [] # [base.render.find("**/kitchenNode*").getPythonTag("isisobj").geom] closestEntry, closestObject = IsisAgent.physics.doRaycastNew("aimRay", 5, [pos, direction], exclude) return closestObject def pick_object_up_with(self, target, hand_slot, hand_joint): """ Attaches an IsisObject, target, to the hand joint. Does not check anything first, other than the fact that the hand joint is not currently holding something else.""" if hand_slot != None: print "already holding " + hand_slot.getName() + "." return None else: if target.layout: target.layout.remove(target) target.layout = None # store original position target.originalHpr = target.getHpr(render) target.disable() # turn off physics if target.body: target.body.setGravityMode(0) target.reparentTo(hand_joint) target.setPosition(hand_joint.getPos(render)) target.setTag("heldBy", self.name) if hand_joint == self.player_right_hand: self.right_hand_holding_object = target elif hand_joint == self.player_left_hand: self.left_hand_holding_object = target hand_slot = target return target def control__pick_up_with_right_hand(self, target=None): if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return "error: no target in reach" else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") print "attempting to pick up " + target.name + " with right hand.\n" if self.can_grasp(target): # object within distance return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand) else: print "object (" + target.name + ") is not graspable (i.e. in view and close enough)." return "error: object not graspable" def control__pick_up_with_left_hand(self, target=None): if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") print "attempting to pick up " + target.name + " with left hand.\n" if self.can_grasp(target): # object within distance return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand) else: print "object (" + target.name + ") is not graspable (i.e. in view and close enough)." return "error: object not graspable" def control__drop_from_right_hand(self): print "attempting to drop object from right hand.\n" if self.right_hand_holding_object is None: print "right hand is not holding an object." return False if self.right_hand_holding_object.getNetTag("heldBy") == self.name: self.right_hand_holding_object.reparentTo(render) direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.player_right_hand.getPos(render) heldPos = self.right_hand_holding_object.geom.getPosition() self.right_hand_holding_object.setPosition(pos) self.right_hand_holding_object.synchPosQuatToNode() self.right_hand_holding_object.setTag("heldBy", "") self.right_hand_holding_object.setRotation(self.right_hand_holding_object.originalHpr) self.right_hand_holding_object.enable() if self.right_hand_holding_object.body: quat = self.getQuat() # throw object force = 5 self.right_hand_holding_object.body.setGravityMode(1) self.right_hand_holding_object.getBody().setForce(quat.xform(Vec3(0, force, 0))) self.right_hand_holding_object = None return "success" else: return "Error: not being held by agent %s" % (self.name) def control__drop_from_left_hand(self): print "attempting to drop object from left hand.\n" if self.left_hand_holding_object is None: return "left hand is not holding an object." if self.left_hand_holding_object.getNetTag("heldBy") == self.name: self.left_hand_holding_object.reparentTo(render) direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.player_left_hand.getPos(render) heldPos = self.left_hand_holding_object.geom.getPosition() self.left_hand_holding_object.setPosition(pos) self.left_hand_holding_object.synchPosQuatToNode() self.left_hand_holding_object.setTag("heldBy", "") self.left_hand_holding_object.setRotation(self.left_hand_holding_object.originalHpr) self.left_hand_holding_object.enable() if self.left_hand_holding_object.body: quat = self.getQuat() # throw object force = 5 self.left_hand_holding_object.body.setGravityMode(1) self.left_hand_holding_object.getBody().setForce(quat.xform(Vec3(0, force, 0))) self.left_hand_holding_object = None return "success" else: return "Error: not being held by agent %s" % (self.name) def control__use_right_hand(self, target=None, action=None): # TODO, rename this to use object with if not action: if self.msg: action = self.msg else: action = "divide" if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") print "Trying to use object", target if self.can_grasp(target): if target.call(self, action, self.right_hand_holding_object) or ( self.right_hand_holding_object and self.right_hand_holding_object.call(self, action, target) ): return "success" return str(action) + " not associated with either target or object" return "target not within reach" def control__use_left_hand(self, target=None, action=None): if not action: if self.msg: action = self.msg else: action = "divide" if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") if self.can_grasp(target): if target.call(self, action, self.left_hand_holding_object) or ( self.left_hand_holding_object and self.left_hand_holding_object.call(self, action, target) ): return "success" return str(action) + " not associated with either target or object" return "target not within reach" def can_grasp(self, isisobject): distance = isisobject.activeModel.getDistance(self.fov) print "distance = ", distance return distance < 5.0 def is_holding(self, object_name): return ( self.left_hand_holding_object and (self.left_hand_holding_object.getPythonTag("isisobj").name == object_name) ) or ( self.right_hand_holding_object and (self.right_hand_holding_object.getPythonTag("isisobj").name == object_name) ) def empty_hand(self): if self.left_hand_holding_object is None: return self.player_left_hand elif self.right_hand_holding_object is None: return self.player_right_hand return False def has_empty_hand(self): return self.empty_hand() is not False def control__use_aimed(self): """ Try to use the object that we aim at, by calling its callback method. """ target = self.__get_object_in_center_of_view() if target.selectionCallback: target.selectionCallback(self, dir) return "success" def sense__get_position(self): x, y, z = self.actorNodePath.getPos() h, p, r = self.actorNodePath.getHpr() # FIXME # neck is not positioned in Blockman nh,np,nr = self.agents[agent_id].actor_neck.getHpr() left_hand_obj = "" right_hand_obj = "" if self.left_hand_holding_object: left_hand_obj = self.left_hand_holding_object.getName() if self.right_hand_holding_object: right_hand_obj = self.right_hand_holding_object.getName() return { "body_x": x, "body_y": y, "body_z": z, "body_h": h, "body_p": p, "body_r": r, "in_left_hand": left_hand_obj, "in_right_hand": right_hand_obj, } def sense__get_vision(self): self.fov.node().saveScreenshot("temp.jpg") image = Image.open("temp.jpg") os.remove("temp.jpg") return image def sense__get_objects(self): return dict([x.getName(), y] for (x, y) in self.get_objects_in_field_of_vision().items()) def sense__get_agents(self): curSense = time() agents = {} for k, v in self.get_agents_in_field_of_vision().items(): v["actions"] = k.get_other_agents_actions(self.lastSense, curSense) agents[k.name] = v self.lastSense = curSense return agents def sense__get_utterances(self): """ Clear out the buffer of things that the teacher has typed, FIXME: this doesn't work right now """ return [] utterances = self.teacher_utterances self.teacher_utterances = [] return utterances def debug__print_objects(self): text = "Objects in FOV: " + ", ".join(self.sense__get_objects().keys()) print text def add_action_to_history(self, action, args, result=0): self.queue.append((time(), action, args, result)) if len(self.queue) > self.queueSize: self.queue.pop(0) def get_other_agents_actions(self, start=0, end=None): if not end: end = time() actions = [] for act in self.queue: if act[0] >= start: if act[0] < end: actions.append(act) else: break return actions def update(self, stepSize=0.1): self.speed = [0.0, 0.0] self.actorNodePath.setPos(self.geom.getPosition() + Vec3(0, 0, -0.70)) self.actorNodePath.setQuat(self.getQuat()) # the values in self.speeds are used as coefficientes for turns and movements if self.controlMap["turn_left"] != 0: self.addToH(stepSize * self.speeds[0]) if self.controlMap["turn_right"] != 0: self.addToH(-stepSize * self.speeds[1]) if self.verticalState == "ground": # these actions require contact with the ground if self.controlMap["move_forward"] != 0: self.speed[1] = self.speeds[2] if self.controlMap["move_backward"] != 0: self.speed[1] = -self.speeds[3] if self.controlMap["move_left"] != 0: self.speed[0] = -self.speeds[4] if self.controlMap["move_right"] != 0: self.speed[0] = self.speeds[5] if self.controlMap["jump"] != 0: kinematicCharacterController.jump(self) # one jump at a time! self.controlMap["jump"] = 0 if self.controlMap["look_left"] != 0: self.neck.setR(bound(self.neck.getR(), -60, 60) + stepSize * 80) if self.controlMap["look_right"] != 0: self.neck.setR(bound(self.neck.getR(), -60, 60) - stepSize * 80) if self.controlMap["look_up"] != 0: self.neck.setP(bound(self.neck.getP(), -60, 80) + stepSize * 80) if self.controlMap["look_down"] != 0: self.neck.setP(bound(self.neck.getP(), -60, 80) - stepSize * 80) kinematicCharacterController.update(self, stepSize) """ Update the held object position to be in the hands """ if self.right_hand_holding_object != None: self.right_hand_holding_object.setPosition(self.player_right_hand.getPos(render)) if self.left_hand_holding_object != None: self.left_hand_holding_object.setPosition(self.player_left_hand.getPos(render)) # Update the dialog box and thought windows # This allows dialogue window to gradually decay (changing transparancy) and then disappear self.last_spoke += stepSize / 2 self.last_thought += stepSize / 2 self.speech_bubble["text_bg"] = (1, 1, 1, 1 / (self.last_spoke + 0.01)) self.speech_bubble["frameColor"] = (0.6, 0.2, 0.1, 0.5 / (self.last_spoke + 0.01)) if self.last_spoke > 2: self.speech_bubble["text"] = "" if self.last_thought > 1: self.thought_bubble.hide() # If the character is moving, loop the run animation. # If he is standing still, stop the animation. if ( (self.controlMap["move_forward"] != 0) or (self.controlMap["move_backward"] != 0) or (self.controlMap["move_left"] != 0) or (self.controlMap["move_right"] != 0) ): if self.isMoving is False: self.isMoving = True else: if self.isMoving: self.current_frame_count = 5.0 self.isMoving = False total_frame_num = self.actor.getNumFrames("walk") if self.isMoving: self.current_frame_count = self.current_frame_count + (stepSize * 250.0) if self.current_frame_count > total_frame_num: self.current_frame_count = self.current_frame_count % total_frame_num self.actor.pose("walk", self.current_frame_count) elif self.current_frame_count != 0: self.current_frame_count = 0 self.actor.pose("idle", 0) return Task.cont def destroy(self): self.disable() self.specialDirectObject.ignoreAll() self.actorNodePath.removeNode() del self.specialDirectObject kinematicCharacterController.destroy(self) def disable(self): self.isDisabled = True self.geom.disable() self.footRay.disable() def enable(self): self.footRay.enable() self.geom.enable() self.isDisabled = False """ Set camera to correct height above the center of the capsule when crouching and when standing up. """ def crouch(self): kinematicCharacterController.crouch(self) self.camH = self.crouchCamH def crouchStop(self): """ Only change the camera's placement when the KCC allows standing up. See the KCC to find out why it might not allow it. """ if kinematicCharacterController.crouchStop(self): self.camH = self.walkCamH
class Ragdoll(DirectObject): # Ragdoll mode RMRagdoll = 0 RMKinematic = 1 def __init__(self, actor, partName = "modelRoot"): self.actor = actor self.partName = partName self.mode = Ragdoll.RMKinematic self.actorJoints = {} self.joints = [] self.jointsOrder = [] self.limbs = {} self.attached = False self.enabled = False self.lastBlendTime = 0 self.blendParallel = [] self.blendActor = None self.updateTask = None def getMainLimb(self): return "" def applyForce(self, force, pos): for limb in self.limbs.values(): mat = limb.bodyNode.getMat(render) mat.invertInPlace() limb.bodyNode.node().applyImpulse(force, mat.xformPoint(pos)) def cleanup(self): if self.updateTask: self.updateTask.remove() self.updateTask = None if self.blendActor: self.blendActor.cleanup() self.blendActor = None self.blendParallel = None self.lastBlendTime = None self.enabled = None self.attached = None for joint in self.joints: if joint.constraint: base.physicsWorld.removeConstraint(joint.constraint) self.joints = None for limb in self.limbs.values(): if limb.bodyNode: base.physicsWorld.remove(limb.bodyNode.node()) limb.bodyNode.removeNode() self.limbs = None self.jointsOrder = None self.actorJoints = None self.mode = None self.partName = None self.actor = None def setup(self): self.setupLimbs() self.setupJoints() self.mode = Ragdoll.RMKinematic self.createActorJointsDesc(self.actor.getPartBundle(self.partName), None) self.exposeActorJoints() self.updateTask = base.taskMgr.add(self.__updateTask, "ragdoll-update" + str(id(self))) def setupLimbs(self): pass def setupJoints(self): pass def addJoint(self, limbA, limbB, axis0, axis1, swing = (0, 0), twist = 0): self.joints.append(RagdollJointDesc(limbA, limbB, axis0, axis1, swing, twist)) def addLimb(self, jointName, mass = 1, shapes = [RagdollLimbShapeDesc()]): self.limbs[jointName] = RagdollLimbDesc(jointName, mass, shapes) def createActorJointsDesc(self, part, parentPart = None): eNp = None if isinstance(part, CharacterJoint): jointName = part.getName() jointDesc = ActorJointDesc(jointName) self.actorJoints[jointName] = jointDesc for child in part.getChildren(): self.createActorJointsDesc(child, eNp) def exposeActorJoints(self): self.jointsOrder = [] usedJointsTemp = [] for limb in self.limbs.values(): usedJointsTemp.append(limb.jointName) self.exposeActorJointsRec(usedJointsTemp, self.actor.getPartBundle(self.partName), None) def exposeActorJointsRec(self, usedJointsTemp, part, parentPart = None): eNp = None if isinstance(part, CharacterJoint): jointName = part.getName() jointDesc = self.actorJoints[jointName] if jointName in usedJointsTemp: self.jointsOrder.append(jointName) if parentPart is not None: jointDesc.parentName = parentPart.getName() eNp = self.actor.exposeJoint(None, self.partName, jointName) jointDesc.eNp = eNp for child in part.getChildren(): self.exposeActorJointsRec(usedJointsTemp, child, eNp) def createLimbs(self): # For each limbs desc, create a bullet capsule for limb in self.limbs.values(): body = BulletRigidBodyNode("ragdoll-limb-" + limb.jointName) body.setMass(limb.mass) for i in range(len(limb.shapes)): shapeDesc = limb.shapes[i] capsule = BulletCapsuleShape(shapeDesc.radius, shapeDesc.length / 2.0, ZUp) body.addShape(capsule, TransformState.makePosHpr(shapeDesc.localPos, shapeDesc.localHpr)) jointDesc = self.actorJoints[limb.jointName] eNp = jointDesc.eNp jointDesc.limb = limb bodyNp = NodePath(body) bodyNp.reparentTo(render) bodyNp.setTransform(render, eNp.getTransform(render)) bodyNp.node().setTransformDirty() base.physicsWorld.attachRigidBody(body) limb.bodyNode = bodyNp def createJoints(self): for jointDesc in self.joints: limbA = self.limbs[jointDesc.limbA] limbB = self.limbs[jointDesc.limbB] a = self.limbs[jointDesc.limbA].bodyNode b = self.limbs[jointDesc.limbB].bodyNode jointA = self.actorJoints[jointDesc.limbA].eNp jointB = self.actorJoints[jointDesc.limbB].eNp frame0 = TransformState.makePosHpr(jointDesc.axis0[0], jointDesc.axis0[1]) frame1 = TransformState.makePosHpr(jointDesc.axis1[0], jointDesc.axis1[1]) constraint = BulletConeTwistConstraint(a.node(), b.node(), frame0, frame1) constraint.setLimit(float(jointDesc.swing[0]), float(jointDesc.swing[1]), float(jointDesc.twist)) constraint.setEnabled(True) constraint.setDebugDrawSize(1.5) jointDesc.constraint = constraint base.physicsWorld.attachConstraint(constraint) def attachActor(self): if self.attached: for jointName in self.jointsOrder: jointDesc = self.actorJoints[jointName] else: self.attached = True for jointName in self.jointsOrder: jointDesc = self.actorJoints[jointName] if jointDesc.parentName is None: cNp = jointDesc.eNp else: cNp = jointDesc.getParent(self.actorJoints).eNp.attachNewNode(jointName) self.actor.controlJoint(cNp, self.partName, jointName) cNp.setMat(render, jointDesc.eNp.getMat(render)) jointDesc.cNp = cNp def detachActor(self): if not self.attached: return self.attached = False for jointName in self.jointsOrder: jointDesc = self.actorJoints[jointName] if jointDesc.cNp is None: continue self.actor.releaseJoint(self.partName, jointName) if jointDesc.limb.bodyNode is not None: jointDesc.limb.bodyNode.node().removeAllChildren() jointDesc.cNp.removeNode() jointDesc.cNp = None self.exposeActorJoints() def setEnabled(self, flag): if self.enabled and flag: return self.enabled = flag if flag: self.createLimbs() self.createJoints() def setKinematicMode(self): self.mode = Ragdoll.RMKinematic self.setEnabled(True) def __updateTask(self, task): if not self.enabled: return task.cont if self.mode == Ragdoll.RMKinematic: for limb in self.limbs.values(): eNp = self.actorJoints[limb.jointName].eNp limb.bodyNode.setTransform(render, eNp.getTransform(render)) limb.bodyNode.node().setTransformDirty() elif self.mode == Ragdoll.RMRagdoll: for limb in self.limbs.values(): cNp = self.actorJoints[limb.jointName].cNp cNp.setTransform(render, limb.bodyNode.getTransform(render)) return task.cont def blendToKinematicMode(self, blendTime): time = globalClock.getFrameTime() if time - self.lastBlendTime < 0.5: return self.lastBlendTime = time if self.blendParallel is not None: self.blendParallel[0].pause() base.taskMgr.remove(self.blendParallel[1]) self.blendParallel = None self.blendActor = Actor() self.blendActor.copyActor(self.actor, True) self.blendActor.pose(self.actor.getCurrentAnim(), self.actor.getCurrentFrame()) self.blendActor.reparentTo(self.actor.getParent()) for jointName in self.jointsOrder: self.blendActor.releaseJoint(self.partName, jointName) self.setKinematicMode() self.blendParallel = [Parallel(), base.taskMgr.doMethodLater(blendTime, self.__blendFinished, 'blendTask')] for jointName in self.jointsOrder: eNp = self.blendActor.exposeJoint(None, self.partName, jointName) jointDesc = self.actorJoints[jointName] if jointDesc.cNp is None: continue ival = jointDesc.cNp.posInterval(blendTime, eNp.getPos(render), other = render) self.blendParallel[0].append(ival) ival = jointDesc.cNp.quatInterval(blendTime, hpr = eNp.getHpr(render), other = render) self.blendParallel[0].append(ival) self.blendParallel[0].start() self.blendActor.cleanup() self.blendActor.removeNode() self.blendActor = None def __blendFinished(self, task): self.detachActor() return task.done
class Monster(): def __init__(self, id, parent, type, pos): self.id = id self.parent = parent self.hp = 100 self.speed = 1 self.can_move = True if type == 'baby': self.node = Actor( 'models/baby', { 'walk': 'models/baby-walk', 'stand': 'models/baby-stand', 'idle': 'models/baby-idle', 'jump': 'models/baby-jump', 'bite1': 'models/baby-bite1', 'bite2': 'models/baby-bite2', 'head_attack': 'models/baby-head_attack', 'hit1': 'models/baby-hit1', 'hit2': 'models/baby-hit2', 'die': 'models/baby-die' }) self.head_node = self.node.exposeJoint(None, "modelRoot", "Bip01_Head") self.body_node = self.node.exposeJoint(None, "modelRoot", "Bip01_Pelvis") self.node.setH(180) self.node.setScale(0.03) self.node.flattenLight() self.zpos = 0 self.node.setPos(pos[0] * TILE_SIZE, pos[1] * TILE_SIZE, self.zpos) self.node.setTexture(loader.loadTexture('models/Zomby_D.png')) self.ts_normal = TextureStage('ts_normal') self.tex_normal = loader.loadTexture('models/Zomby_N.png') self.ts_normal.setMode(TextureStage.MNormal) self.node.setTexture(self.ts_normal, self.tex_normal) self.ts_gloss = TextureStage('ts_gloss') self.tex_gloss = loader.loadTexture('models/Zomby_S1.png') self.ts_gloss.setMode(TextureStage.MGloss) self.node.setTexture(self.ts_gloss, self.tex_gloss) self.ts_glow = TextureStage('ts_glow') self.tex_glow = loader.loadTexture('models/Zomby_I.png') self.ts_glow.setMode(TextureStage.MGlow) self.node.setTexture(self.ts_glow, self.tex_glow) self.node.reparentTo(render) self.node.loop('walk') elif type == 'nos': self.node = loader.loadModel('models/nos') self.zpos = 5 self.node.setPos(pos[0] * TILE_SIZE, pos[1] * TILE_SIZE, self.zpos) self.node.setScale(2) if self.id == 1: self.node.setColor(1, 0, 0) elif self.id == 2: self.node.setColor(0, 1, 0) elif self.id == 3: self.node.setColor(0, 0, 1) else: self.node.setColor(1, 1, 1) self.node.reparentTo(render) #self.patrol_points = [(1,1), (4,11), (12,20), (18,4), (19,17)] #initialize 3d sound self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], base.camera) self.shot_head = self.audio3d.loadSfx( 'audio/Zombie In Pain-SoundBible.com-134322253.wav') self.shot_body = self.audio3d.loadSfx( 'audio/Zombie Moan-SoundBible.com-565291980.wav') self.moan1 = self.audio3d.loadSfx( 'audio/Mindless Zombie Awakening-SoundBible.com-255444348.wav') self.moan2 = self.audio3d.loadSfx( 'audio/Zombie Brain Eater-SoundBible.com-1076387080.wav') self.aggro_sound = self.audio3d.loadSfx( 'audio/Mummy Zombie-SoundBible.com-1966938763.wav') self.attack_sound = self.audio3d.loadSfx( 'audio/Chopping Off Limb-SoundBible.com-884800545.wav') self.audio3d.attachSoundToObject(self.moan1, self.node) self.audio3d.attachSoundToObject(self.moan2, self.node) self.audio3d.attachSoundToObject(self.shot_head, self.node) self.audio3d.attachSoundToObject(self.shot_body, self.node) self.audio3d.attachSoundToObject(self.aggro_sound, self.node) self.audio3d.attachSoundToObject(self.attack_sound, self.node) delay0 = Wait(d(35)) delay1 = Wait(25 + d(35)) delay2 = Wait(25 + d(35)) self.moan_sequence = Sequence(delay0, SoundInterval(self.moan1), delay1, SoundInterval(self.moan2), delay2) self.moan_sequence.loop() self.parent.collision_manager.createMonsterCollision(self) self.aggro_sound_last_played = 0 #--------------------------brain------------------------- self.node.setH(160) self.pause = False self.action = ACTION_IDLE if percent(20): self.orders = ORDERS_PATROL else: self.orders = ORDERS_IDLE self.last_melee = 0 self.player_last_seen_abs = None self.idle_timer = time.time() self.idle_value = 1 self.current_waypoint = None #self.wait_until = None self.herding_timer = None self.path = None taskMgr.doMethodLater(1, self.behaviourTask, 'MonsterBehaviourTask' + str(self.id)) taskMgr.doMethodLater(1, self.debugMoveTask, 'MonsterMoveTask' + str(self.id)) def getLOS(self): return self.parent.collision_manager.checkMonsterPlayerLos(self) def sensePlayer(self): """Return True if player sensed, and his last known coordinates are stored in self.player_last_seen_abs""" # if the player is dead, do not sense him if self.parent.player.health <= 0: return False #get player's position p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() #--------------------------------SENSE--------------------------------- #if player is within SENSING_RANGE we know he is there if self.distanceToPlayer() < SENSING_RANGE: #print "TOO CLOSE LOOSER!" self.player_last_seen_abs = p_pos_abs return True #---------------------------------HEAR---------------------------------- #if player is within HEARING_RANGE we know he is there effective_hearing_range = HEARING_RANGE if self.parent.player.gunshot_at: effective_hearing_range *= 3 else: if self.parent.player.sprint: effective_hearing_range *= 2 if not self.parent.player.moving: effective_hearing_range = 0 if self.distanceToPlayer() < effective_hearing_range: print "I HEAR U!" self.parent.player.adrenaline() #if we can see go chase him if self.getLOS(): self.player_last_seen_abs = p_pos_abs return True #we cannot see him, build new path to that tile else: dest = getTile(p_pos_abs) path = pathFind(self.parent.level, getTile(self.node.getPos()), dest) if path: self.path = path self.orders = ORDERS_PATROL self.action = ACTION_FOLLOW_PATH return False #-------------------------------SEE--------------------------------- #if player is in front of us if self.angleToPlayerAbs() <= 45: #if he is close enough to see and we can see him if self.distanceToPlayer() <= VIEW_RANGE and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim!" return True #if player has a flashlight lit, and we can see him go after him if self.parent.player.flashlight and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim flashlight" return True #---------------------SEE MY OWN SHADOW--------------------------- #if player is behind us and has a lit up flashlight and we have LOS to him if self.angleToPlayerAbs() > 135 and self.angleToPlayerAbs() < 225: if self.parent.player.flashlight and self.getLOS(): #if he is looking at us my_pos_rel = self.node.getPos(self.parent.player.node) forward = Vec2(0, 1) if math.fabs( forward.signedAngleDeg( Vec2(my_pos_rel[0], my_pos_rel[1]))) <= 30: #go after my own shadow print "herding" self.orders = ORDERS_HERDING self.node.setH(self.parent.player.node.getH()) self.herding_timer = time.time() return False def distanceToPlayer(self): p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() return math.sqrt( math.pow(p_pos_abs[0] - my_pos_abs[0], 2) + math.pow(p_pos_abs[1] - my_pos_abs[1], 2)) def angleToPlayer(self): p_pos_rel = self.parent.player.node.getPos(self.node) forward = Vec2(0, 1) return forward.signedAngleDeg(Vec2(p_pos_rel[0], p_pos_rel[1])) def angleToPlayerAbs(self): return math.fabs(self.angleToPlayer()) def behaviourTask(self, task): if self.pause: return task.again #top priority, if we sense a player, go after him! if self.sensePlayer(): if time.time() - self.aggro_sound_last_played > 5: self.aggro_sound.play() self.aggro_sound_last_played = time.time() self.action = ACTION_CHASE return task.again elif self.orders == ORDERS_IDLE: #percent chance to go on patrol if percent(10): self.orders = ORDERS_PATROL return task.again self.action = ACTION_IDLE elif self.orders == ORDERS_PATROL: #percent chance to get idle if percent(5): self.orders = ORDERS_IDLE return task.again #if we are already patroling, dont change anything if self.action == ACTION_FOLLOW_PATH: return task.again #build a new path for patrol dest = self.getNewPatrolPoint() self.path = pathFind(self.parent.level, getTile(self.node.getPos()), dest) self.action = ACTION_FOLLOW_PATH elif self.orders == ORDERS_HERDING: self.action = ACTION_MOVE if time.time() - self.herding_timer > HERDING_TIMEOUT: self.orders = ORDERS_IDLE return task.again def debugMoveTask(self, task): if self.pause: return task.cont #print "orders:", self.orders if self.action == ACTION_CHASE: self.parent.player.adrenaline() look_pos = Point3(self.player_last_seen_abs.getX(), self.player_last_seen_abs.getY(), self.zpos) self.node.lookAt(look_pos) self.node.setFluidPos(self.node, 0, CHASE_SPEED * globalClock.getDt(), 0) if self.distanceToPlayer( ) <= MELEE_RANGE and self.angleToPlayerAbs() <= 45 and self.getLOS( ): if time.time() - self.last_melee >= MELEE_TIME: self.attack_sound.play() att = random.randint(0, 2) if att == 0: animname = 'bite1' elif att == 1: animname = 'bite2' else: animname = 'head_attack' self.node.play(animname) duration = self.node.getNumFrames( animname) / 24 # animation play rate taskMgr.doMethodLater(duration, self.finishedAnim, 'FinishedAnim', extraArgs=[]) self.parent.player.getDamage() self.last_melee = time.time() elif self.action == ACTION_IDLE: if time.time() - self.idle_timer > IDLE_TIME: #we are standing still and rotating, see on whic side we will rotate now self.idle_timer = time.time() if percent(20): self.idle_value *= -1 self.rotateBy(self.idle_value * IDLE_ROTATE_SPEED) elif self.action == ACTION_FOLLOW_PATH: #if we dont have a waypoint, calculate one if not self.current_waypoint: try: #get next tile from path tile = self.path[0] self.path = self.path[1:] #calculate waypoint varx = 5 - (d(4) + d(4)) vary = 5 - (d(4) + d(4)) self.current_waypoint = (Point3(tile[0] * TILE_SIZE + varx, tile[1] * TILE_SIZE + vary, self.zpos), time.time()) #print "waypoint:", self.current_waypoint self.node.lookAt(self.current_waypoint[0]) except (IndexError, TypeError): #we have reached the end of path self.orders = ORDERS_IDLE self.current_waypoint = None #if we have a waypoint move forward towards it, and check if we arrived at it else: self.node.setFluidPos(self.node, 0, NORMAL_SPEED * globalClock.getDt(), 0) my_pos = self.node.getPos() #if we are close enough to the waypoint or if we didnt get to waypoint in time, delete it so we know we need a new one if math.fabs( my_pos[0] - self.current_waypoint[0][0] ) < 1 and math.fabs( my_pos[1] - self.current_waypoint[0][1] ) < 2 \ or time.time() - self.current_waypoint[1] > WAYPOINT_TIMER: self.current_waypoint = None elif self.action == ACTION_MOVE: self.node.setFluidPos(self.node, 0, NORMAL_SPEED * globalClock.getDt(), 0) return task.cont def finishedAnim(self): if not self.pause: self.node.loop('walk') def rotateBy(self, value): self.node.setH((self.node.getH() + value) % 360) def getNewPatrolPoint(self): lvl = self.parent.level allTiles = lvl.getFloorTiles() while True: t = (d(lvl.getMaxX()), d(lvl.getMaxY())) if t in allTiles: return t def hitWall(self): if self.action == ACTION_CHASE: return #print "lupio!" """self.moan1.play() self.rotateBy( 180 ) self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0) #self.action = IDLE """ """ old = self.node.getH() rnd = 80 + random.randint( 0, 20 ) forward = Vec2( 0, 1 ) impact = Vec2( pos[0], pos[1] ) angle = forward.signedAngleDeg( impact ) #print "angle:", angle if angle < 0: #+ cause angle is negative rnd = 91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) elif angle > 0: rnd = -91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) #print "stari:", old, " novi:", self.node.getH() """ pass def pauze(self): if self.moan_sequence: self.moan_sequence.pause() self.pause = True def resume(self): if self.moan_sequence: self.moan_sequence.resume() self.pause = False def destroy(self): self.audio3d.detachSound(self.moan1) self.audio3d.detachSound(self.moan2) self.audio3d.detachSound(self.shot_head) self.audio3d.detachSound(self.shot_body) self.audio3d.detachSound(self.aggro_sound) self.audio3d.detachSound(self.attack_sound) if self.moan_sequence != None: self.moan_sequence.pause() self.moan_sequence = None taskMgr.remove('MonsterBehaviourTask' + str(self.id)) taskMgr.remove('MonsterMoveTask' + str(self.id)) self.cn_head.node().clearPythonTag('node') self.cn_body.node().clearPythonTag('node') self.cn_pusher.node().clearPythonTag('node') self.cn_ray.node().clearPythonTag('node') self.node.delete() self.node.cleanup() self.node.removeNode() """
class Me(DirectObject): def __init__(self, terrainClass): self.model = Actor("models/ninja", {"walk": "models/ninja"}) self.actorHead = self.model.exposeJoint(None, 'modelRoot', 'Joint8') #self.model.setScale(4) self.playernum = None self.timeSinceLastUpdate = 0 self.model.reparentTo(render) self.model.setScale(0.5) self.isMoving = False self.AnimControl = self.model.getAnimControl('walk') self.AnimControl.setPlayRate(0.05) self.model.setBlend(frameBlend=1) self.model.setPos(244, 188, 0) #STORE TERRAIN SCALE FOR LATER USE# self.terrainScale = terrainClass.terrain.getRoot().getSz() def setPlayerNum(self, int): self.playernum = int def move(self, keyClass, terrainClass): self.meTerrainHeight = terrainClass.terrain.getElevation( self.model.getX(), self.model.getY()) * self.terrainScale self.camTerrainHeight = terrainClass.terrain.getElevation( camera.getX(), camera.getY()) * self.terrainScale self.elapsed = globalClock.getDt() base.camera.lookAt(self.actorHead) if (keyClass.keyMap["left"] != 0): self.model.setH(self.model.getH() + self.elapsed * 300) print str(self.model.getY()), str(self.model.getX()) if (keyClass.keyMap["right"] != 0): self.model.setH(self.model.getH() - self.elapsed * 300) if (keyClass.keyMap["forward"] != 0): self.model.setY(self.model, (self.elapsed * 40)) if (keyClass.keyMap["back"] != 0): self.model.setY(self.model, -(self.elapsed * 40)) if (keyClass.keyMap["forward"] != 0) or (keyClass.keyMap["left"] != 0) or (keyClass.keyMap["right"] != 0): if self.isMoving is False: self.model.loop("walk", fromFrame=1, toFrame=11) self.isMoving = True else: if self.isMoving: self.model.stop() self.model.pose("walk", 5) self.isMoving = False self.model.setZ(self.meTerrainHeight) #CAMERA CONTROL# self.camvec = self.model.getPos() - base.camera.getPos() if (self.camTerrainHeight > self.meTerrainHeight): camera.setZ(self.camTerrainHeight + 5) else: camera.setZ(self.meTerrainHeight + 5) self.camvec.setZ(0) self.camdist = self.camvec.length() self.camvec.normalize() if (self.camdist > 20): base.camera.setPos(base.camera.getPos() + self.camvec * (self.camdist - 20)) self.camdist = 20.0 if (self.camdist < 10): base.camera.setPos(base.camera.getPos() - self.camvec * (10 - self.camdist)) self.camdist = 10.0 return Task.cont
class Character: """A character with an animated avatar that moves left, right or forward according to the controls turned on or off in self.controlMap. Public fields: self.controlMap -- The character's movement controls self.actor -- The character's Actor (3D animated model) Public functions: __init__ -- Initialise the character move -- Move and animate the character for one frame. This is a task function that is called every frame by Panda3D. setControl -- Set one of the character's controls on or off. """ def __init__(self, agent_simulator, model, actions, startPos, scale): """Initialize the character. Arguments: model -- The path to the character's model file (string) run : The path to the model's run animation (string) walk : The path to the model's walk animation (string) startPos : Where in the world the character will begin (pos) scale : The amount by which the size of the model will be scaled (float) """ self.agent_simulator = agent_simulator self.controlMap = {"turn_left":0, "turn_right":0, "move_forward":0, "move_backward":0,\ "look_up":0, "look_down":0, "look_left":0, "look_right":0} self.actor = Actor(model,actions) self.actor.reparentTo(render) self.actor.setScale(scale) self.actor.setPos(startPos) self.actor.setHpr(0,0,0) # Expose agent's right hand joint to attach objects to self.actor_right_hand = self.actor.exposeJoint(None, 'modelRoot', 'RightHand') self.actor_left_hand = self.actor.exposeJoint(None, 'modelRoot', 'LeftHand') self.right_hand_holding_object = False self.left_hand_holding_object = False # speech bubble self.last_spoke = 0 self.speech_bubble=DirectLabel(parent=self.actor, text="", text_wordwrap=10, pad=(3,3), relief=None, text_scale=(.5,.5), pos = (0,0,6), frameColor=(.6,.2,.1,.5), textMayChange=1, text_frame=(0,0,0,1), text_bg=(1,1,1,1)) self.speech_bubble.component('text0').textNode.setCardDecal(1) self.speech_bubble.setBillboardAxis() # visual processing self.actor_eye = self.actor.exposeJoint(None, 'modelRoot', 'LeftEyeLid') # put a camera on ralph self.fov = NodePath(Camera('RaphViz')) self.fov.reparentTo(self.actor_eye) self.fov.setHpr(180,0,0) #lens = OrthographicLens() #lens.setFilmSize(20,15) #self.fov.node().setLens(lens) lens = self.fov.node().getLens() lens.setFov(60) # degree field of view (expanded from 40) lens.setNear(0.2) #self.fov.node().showFrustum() # displays a box around his head self.actor_neck = self.actor.controlJoint(None, 'modelRoot', 'Neck') # Define subpart of agent for when he's standing around self.actor.makeSubpart("arms", ["LeftShoulder", "RightShoulder"]) taskMgr.add(self.move,"moveTask") # Note: deriving classes DO NOT need # to add their own move tasks to the # task manager. If they override # self.move, then their own self.move # function will get called by the # task manager (they must then # explicitly call Character.move in # that function if they want it). self.prevtime = 0 self.isMoving = False self.current_frame_count = 0.0 # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.initialize_collision_handling() def initialize_collision_handling(self): self.collision_handling_mutex = Lock() self.cTrav = CollisionTraverser() self.groundRay = CollisionRay() self.groundRay.setOrigin(0,0,1000) self.groundRay.setDirection(0,0,-1) self.groundCol = CollisionNode('ralphRay') self.groundCol.setIntoCollideMask(BitMask32.bit(0)) self.groundCol.setFromCollideMask(BitMask32.bit(0)) self.groundCol.addSolid(self.groundRay) self.groundColNp = self.actor.attachNewNode(self.groundCol) self.groundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.groundColNp, self.groundHandler) # Uncomment this line to see the collision rays # self.groundColNp.show() #Uncomment this line to show a visual representation of the #collisions occuring # self.cTrav.showCollisions(render) def destroy_collision_handling(self): self.collision_handling_mutex.acquire() def handle_collisions(self): self.collision_handling_mutex.acquire() self.groundCol.setIntoCollideMask(BitMask32.bit(0)) self.groundCol.setFromCollideMask(BitMask32.bit(1)) # Now check for collisions. self.cTrav.traverse(render) # Adjust the character's Z coordinate. If the character's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.groundHandler.getNumEntries()): entry = self.groundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x,y: cmp(y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries)>0) and (entries[0].getIntoNode().getName() == "terrain"): self.actor.setZ(entries[0].getSurfacePoint(render).getZ()) else: self.actor.setPos(self.startpos) self.groundCol.setIntoCollideMask(BitMask32.bit(0)) self.groundCol.setFromCollideMask(BitMask32.bit(0)) self.collision_handling_mutex.release() def position(self): return self.actor.getPos() def forward_normal_vector(self): backward = self.actor.getNetTransform().getMat().getRow3(1) backward.setZ(0) backward.normalize() return -backward def step_simulation_time(self, seconds): # save the character's initial position so that we can restore it, # in case he falls off the map or runs into something. self.startpos = self.actor.getPos() def bound(i, mn = -1, mx = 1): return min(max(i, mn), mx) # enforces bounds on a numeric value # move the character if any of the move controls are activated. if (self.controlMap["turn_left"]!=0): self.actor.setH(self.actor.getH() + seconds*30) if (self.controlMap["turn_right"]!=0): self.actor.setH(self.actor.getH() - seconds*30) if (self.controlMap["move_forward"]!=0): self.actor.setPos(self.actor.getPos() + self.forward_normal_vector() * (seconds*0.5)) if (self.controlMap["move_backward"]!=0): self.actor.setPos(self.actor.getPos() - self.forward_normal_vector() * (seconds*0.5)) if (self.controlMap["look_left"]!=0): self.actor_neck.setP(bound(self.actor_neck.getP(),-60,60)+1*(seconds*50)) if (self.controlMap["look_right"]!=0): self.actor_neck.setP(bound(self.actor_neck.getP(),-60,60)-1*(seconds*50)) if (self.controlMap["look_up"]!=0): self.actor_neck.setH(bound(self.actor_neck.getH(),-60,80)+1*(seconds*50)) if (self.controlMap["look_down"]!=0): self.actor_neck.setH(bound(self.actor_neck.getH(),-60,80)-1*(seconds*50)) # allow dialogue window to gradually decay (changing transparancy) and then disappear self.last_spoke += seconds self.speech_bubble['text_bg']=(1,1,1,1/(2*self.last_spoke+0.01)) self.speech_bubble['frameColor']=(.6,.2,.1,.5/(2*self.last_spoke+0.01)) if self.last_spoke > 2: self.speech_bubble['text'] = "" # If the character is moving, loop the run animation. # If he is standing still, stop the animation. if (self.controlMap["move_forward"]!=0) or (self.controlMap["move_backward"]!=0): if self.isMoving is False: self.isMoving = True else: if self.isMoving: self.current_frame_count = 5.0 self.isMoving = False total_frame_num = self.actor.getNumFrames('walk') if self.isMoving: self.current_frame_count = self.current_frame_count + (seconds*10.0) while (self.current_frame_count >= total_frame_num + 1): self.current_frame_count -= total_frame_num while (self.current_frame_count < 0): self.current_frame_count += total_frame_num self.actor.pose('walk', self.current_frame_count) self.handle_collisions() def move(self, task): """Move and animate the character for one frame. This is a task function that is called every frame by Panda3D. The character is moved according to which of it's movement controls are set, and the function keeps the character's feet on the ground and stops the character from moving if a collision is detected. This function also handles playing the characters movement animations. Arguments: task -- A direct.task.Task object passed to this function by Panda3D. Return: Task.cont -- To tell Panda3D to call this task function again next frame. """ elapsed = task.time - self.prevtime # Store the task time and continue. self.prevtime = task.time return Task.cont def setControl(self, control, value): """Set the state of one of the character's movement controls. Arguments See self.controlMap in __init__. control -- The control to be set, must be a string matching one of the strings in self.controlMap. value -- The value to set the control to. """ # FIXME: this function is duplicated in Camera and Character, and # keyboard control settings are spread throughout the code. Maybe # add a Controllable class? self.controlMap[control] = value # these are simple commands that can be exported over xml-rpc (or attached to the keyboard) def get_objects(self): """ Looks up all of the model nodes that are 'isInView' of the camera and returns them in the in_view dictionary (as long as they are also in the self.world_objects -- otherwise this includes points defined within the environment/terrain). TODO: 1) include more geometric information about the object (size, mass, etc) """ def map3dToAspect2d(node, point): """Maps the indicated 3-d point (a Point3), which is relative to the indicated NodePath, to the corresponding point in the aspect2d scene graph. Returns the corresponding Point3 in aspect2d. Returns None if the point is not onscreen. """ # Convert the point to the 3-d space of the camera p3 = self.fov.getRelativePoint(node, point) # Convert it through the lens to render2d coordinates p2 = Point2() if not self.fov.node().getLens().project(p3, p2): return None r2d = Point3(p2[0], 0, p2[1]) # And then convert it to aspect2d coordinates a2d = aspect2d.getRelativePoint(render2d, r2d) return a2d objs = render.findAllMatches("**/+ModelNode") in_view = {} for o in objs: o.hideBounds() # in case previously turned on o_pos = o.getPos(self.fov) if self.fov.node().isInView(o_pos): if self.agent_simulator.world_objects.has_key(o.getName()): b_min, b_max = o.getTightBounds() a_min = map3dToAspect2d(render, b_min) a_max = map3dToAspect2d(render, b_max) if a_min == None or a_max == None: continue x_diff = math.fabs(a_max[0]-a_min[0]) y_diff = math.fabs(a_max[2]-a_min[2]) area = 100*x_diff*y_diff # percentage of screen object_dict = {'x_pos': (a_min[2]+a_max[2])/2.0,\ 'y_pos': (a_min[0]+a_max[0])/2.0,\ 'distance':o.getDistance(self.fov), \ 'area':area,\ 'orientation': o.getH(self.fov)} in_view[o.getName()]=object_dict print o.getName(), object_dict return in_view def control__turn_left__start(self): self.setControl("turn_left", 1) self.setControl("turn_right", 0) def control__turn_left__stop(self): self.setControl("turn_left", 0) def control__turn_right__start(self): self.setControl("turn_left", 0) self.setControl("turn_right", 1) def control__turn_right__stop(self): self.setControl("turn_right", 0) def control__move_forward__start(self): self.setControl("move_forward", 1) self.setControl("move_backward", 0) def control__move_forward__stop(self): self.setControl("move_forward", 0) def control__move_backward__start(self): self.setControl("move_forward", 0) self.setControl("move_backward", 1) def control__move_backward__stop(self): self.setControl("move_backward", 0) def control__look_left__start(self): self.setControl("look_left", 1) self.setControl("look_right", 0) def control__look_left__stop(self): self.setControl("look_left", 0) def control__look_right__start(self): self.setControl("look_right", 1) self.setControl("look_left", 0) def control__look_right__stop(self): self.setControl("look_right", 0) def control__look_up__start(self): self.setControl("look_up", 1) self.setControl("look_down", 0) def control__look_up__stop(self): self.setControl("look_up", 0) def control__look_down__start(self): self.setControl("look_down", 1) self.setControl("look_up", 0) def control__look_down__stop(self): self.setControl("look_down", 0) def can_grasp(self, object_name): objects = self.get_objects() if objects.has_key(object_name): object_view = objects[object_name] distance = object_view['distance'] if (distance < 5.0): return True return False def control__say(self, message): self.speech_bubble['text'] = message self.last_spoke = 0 def control__pick_up_with_right_hand(self, pick_up_object): print "attempting to pick up " + pick_up_object + " with right hand.\n" if self.right_hand_holding_object: return 'right hand is already holding ' + self.right_hand_holding_object.getName() + '.' if self.can_grasp(pick_up_object): world_object = self.agent_simulator.world_objects[pick_up_object] object_parent = world_object.getParent() if (object_parent == self.agent_simulator.env): world_object.wrtReparentTo(self.actor_right_hand) world_object.setPos(0, 0, 0) world_object.setHpr(0, 0, 0) self.right_hand_holding_object = world_object return 'success' else: return 'object (' + pick_up_object + ') is already held by something or someone.' else: return 'object (' + pick_up_object + ') is not graspable (i.e. in view and close enough).' def put_object_in_empty_left_hand(self, object_name): if (self.left_hand_holding_object is not False): return False world_object = self.agent_simulator.world_objects[object_name] world_object.wrtReparentTo(self.actor_left_hand) world_object.setPos(0, 0, 0) world_object.setHpr(0, 0, 0) self.left_hand_holding_object = world_object return True def control__pick_up_with_left_hand(self, pick_up_object): print "attempting to pick up " + pick_up_object + " with left hand.\n" if self.left_hand_holding_object: return 'left hand is already holding ' + self.left_hand_holding_object.getName() + '.' if self.can_grasp(pick_up_object): world_object = self.agent_simulator.world_objects[pick_up_object] object_parent = world_object.getParent() if (object_parent == self.agent_simulator.env): self.put_object_in_empty_left_hand(pick_up_object) return 'success' else: return 'object (' + pick_up_object + ') is already held by something or someone.' else: return 'object (' + pick_up_object + ') is not graspable (i.e. in view and close enough).' def control__drop_from_right_hand(self): print "attempting to drop object from right hand.\n" if self.right_hand_holding_object is False: return 'right hand is not holding an object.' world_object = self.right_hand_holding_object self.right_hand_holding_object = False world_object.wrtReparentTo(self.agent_simulator.env) world_object.setHpr(0, 0, 0) world_object.setPos(self.position() + self.forward_normal_vector() * 0.5) world_object.setZ(world_object.getZ() + 1.0) return 'success' def control__drop_from_left_hand(self): print "attempting to drop object from left hand.\n" if self.left_hand_holding_object is False: return 'left hand is not holding an object.' world_object = self.left_hand_holding_object self.left_hand_holding_object = False world_object.wrtReparentTo(self.agent_simulator.env) world_object.setHpr(0, 0, 0) world_object.setPos(self.position() + self.forward_normal_vector() * 0.5) world_object.setZ(world_object.getZ() + 1.0) return 'success' def is_holding(self, object_name): return ((self.left_hand_holding_object and (self.left_hand_holding_object.getName() == object_name)) or (self.right_hand_holding_object and (self.right_hand_holding_object.getName() == object_name))) def empty_hand(self): if (self.left_hand_holding_object is False): return self.actor_left_hand elif (self.right_hand_holding_object is False): return self.actor_right_hand return False def has_empty_hand(self): return (self.empty_hand() is not False) def control__use_object_with_object(self, use_object, with_object): if ((use_object == 'knife') and (with_object == 'loaf_of_bread')): if self.is_holding('knife'): if self.can_grasp('loaf_of_bread'): if self.has_empty_hand(): empty_hand = self.empty_hand() new_object_name = self.agent_simulator.create_object__slice_of_bread([float(x) for x in empty_hand.getPos()]) if (empty_hand == self.actor_left_hand): self.put_object_in_empty_left_hand(new_object_name) elif (empty_hand == self.actor_right_hand): self.put_object_in_empty_right_hand(new_object_name) else: return "simulator error: empty hand is not left or right. (are there others?)" return 'success' else: return 'failure: one hand must be empty to hold loaf_of_bread in place while using knife.' else: return 'failure: loaf of bread is not graspable (in view and close enough)' else: return 'failure: must be holding knife object to use it.' return 'failure: don\'t know how to use ' + use_object + ' with ' + with_object + '.'
class ToonFPS(DirectObject): notify = directNotify.newCategory("ToonFPS") WeaponName2DamageData = {"pistol": (30.0, 10.0, 150.0, 0.3), "shotgun": (40.0, 15.0, 155.0, 0.5), "sniper": (40.0, 15.0, 155.0, 0.5)} def __init__(self, mg, weaponName = "pistol"): self.mg = mg self.weaponName = weaponName self.v_model_root = None self.v_model = None self.weapon = None self.track = None self.draw = None self.shoot = None self.reload = None self.empty = None self.cockBack = None self.cockFwd = None self.player_node = None # blach (02Aug15) # Drastically improved the accuracy of bullets... DRASTICALLY self.shooterTrav = None self.shooterRay = None self.shooterRayNode = None self.shooterHandler = None self.gui = ToonFPSGui(self) self.fsm = ClassicFSM('ToonFPS', [State('off', self.enterOff, self.exitOff), State('alive', self.enterAlive, self.exitAlive), State('dead', self.enterDead, self.exitDead)], 'off', 'off') #self.deadFSM = ClassicFSM('dead', [State('off', self.enterOff, self.exitOff), # State(']) self.aliveFSM = ClassicFSM('alive', [State('off', self.enterOff, self.exitOff), State('draw', self.enterDraw, self.exitDraw, ['idle']), State('idle', self.enterIdle, self.exitIdle, ['shoot', 'reload']), State('shoot', self.enterShoot, self.exitShoot, ['idle']), State('reload', self.enterReload, self.exitReload, ['idle'])], 'off', 'off') self.fsm.getStateNamed('alive').addChild(self.aliveFSM) #self.fsm.getStateNamed('dead').addChild(self.deadFSM) self.fsm.enterInitialState() self.aliveFSM.enterInitialState() if self.weaponName == "pistol": self.ammo = 14 elif self.weaponName == "shotgun": self.ammo = 7 self.hp = 125 self.max_hp = 125 self.firstPerson = FirstPerson() def movementTask(self, task): if (inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne): if base.localAvatar.getAnimState() != "jump": base.localAvatar.setAnimState("jump") base.localAvatar.playMovementSfx(None) self.mg.sendUpdate("jumpingAvatar", [base.localAvatar.doId]) return Task.cont def enterAlive(self): if not self.mg.fsm.getCurrentState().getName() in ['gameOver', 'announceGameOver', 'finalScores']: self.start() self.resetHp() self.resetAmmo() if self.mg.fsm.getCurrentState().getName() == "play": self.reallyStart() def exitAlive(self): self.end() self.v_model.reparentTo(hidden) if self.mg.fsm.getCurrentState().getName() != "play": self.reallyEnd() def updatePoints(self): self.points = self.kills - self.deaths def enterDead(self, killer): base.localAvatar.getGeomNode().show() self.gui.end() base.localAvatar.attachCamera() self.freezeCamSfx = base.loadSfx("phase_4/audio/sfx/freeze_cam.ogg") self.freezeCamImage = None self.freezeCamImageFile = None base.camera.setZ(base.camera.getZ() + 2.0) taskMgr.add( self.cameraLookAtKillerTask, "lookAtKiller", extraArgs = [killer], appendTask = True ) taskMgr.doMethodLater( 2.0, self.startZoomOnKiller, "startFreezeCam", extraArgs = [killer], appendTask = True ) def startZoomOnKiller(self, killer, task): taskMgr.add( self.__zoomOnKillerTask, "zoomOnKiller", extraArgs = [killer], appendTask = True ) return task.done def __zoomOnKillerTask(self, killer, task): if base.camera.getDistance(killer) <= 10.0 and self.freezeCamSfx.status() == self.freezeCamSfx.READY: base.playSfx(self.freezeCamSfx) if base.camera.getDistance(killer) < 7.0: self.doFreezeCam() return task.done base.camera.setY(base.camera, 60 * globalClock.getDt()) return task.again def doFreezeCam(self): taskMgr.remove("lookAtKiller") self.frameBuffer = PNMImage() base.win.getScreenshot(self.frameBuffer) self.freezeCamTex = Texture() self.freezeCamTex.load(self.frameBuffer) self.freezeCamImage = OnscreenImage(image = self.freezeCamTex, parent=render2d) def cameraLookAtKillerTask(self, killer, task): try: base.camera.lookAt(killer, 0, 0, 3) except AssertionError: pass return task.cont def exitDead(self): taskMgr.remove("zoomOnKiller") taskMgr.remove("lookAtKiller") taskMgr.remove("startFreezeCam") del self.freezeCamSfx if self.freezeCamImage: self.freezeCamImage.destroy() del self.freezeCamImage self.frameBuffer.clear() self.freezeCamTex.clear() del self.frameBuffer del self.freezeCamTex base.localAvatar.detachCamera() base.localAvatar.getGeomNode().hide() self.gui.start() def load(self): if self.weaponName == "pistol": self.draw = base.loadSfx("phase_4/audio/sfx/draw_secondary.ogg") self.shoot = base.loadSfx("phase_4/audio/sfx/pistol_shoot.ogg") self.reload = base.loadSfx("phase_4/audio/sfx/pistol_worldreload.ogg") elif self.weaponName == "sniper": self.draw = base.loadSfx("phase_4/audio/sfx/draw_primary.ogg") self.shoot = base.loadSfx("phase_4/audio/sfx/shotgun_shoot.ogg") self.cockBack = base.loadSfx("phase_4/audio/sfx/shotgun_cock_back.ogg") self.cockFwd = base.loadSfx("phase_4/audio/sfx/shotgun_cock_forward.ogg") elif self.weaponName == "shotgun": self.draw = base.loadSfx("phase_4/audio/sfx/draw_primary.ogg") self.shoot = base.loadSfx("phase_4/audio/sfx/shotgun_shoot.ogg") self.cockBack = base.loadSfx("phase_4/audio/sfx/shotgun_cock_back.ogg") self.cockFwd = base.loadSfx("phase_4/audio/sfx/shotgun_cock_forward.ogg") self.empty = base.loadSfx("phase_4/audio/sfx/shotgun_empty.ogg") self.v_model_root = base.camera.attachNewNode('v_model_root') self.v_model = Actor('phase_4/models/minigames/v_dgm.egg', {'pidle': 'phase_4/models/minigames/v_dgm-pistol-idle.egg', 'pshoot': 'phase_4/models/minigames/v_dgm-pistol-shoot.egg', 'preload': 'phase_4/models/minigames/v_dgm-pistol-reload.egg', 'pdraw': 'phase_4/models/minigames/v_dgm-pistol-draw.egg', 'sidle': 'phase_4/models/minigames/v_dgm-shotgun-idle.egg', 'sshoot': 'phase_4/models/minigames/v_dgm-shotgun-shoot.egg'}) if self.weaponName == "pistol": self.weapon = loader.loadModel("phase_4/models/props/water-gun.bam") self.weapon.reparentTo(self.v_model.exposeJoint(None, "modelRoot", "Bone.011")) self.weapon.setX(-0.125) self.weapon.setY(0.5) self.weapon.setScale(0.65) elif self.weaponName == "sniper": self.weapon = loader.loadModel("phase_4/models/props/sniper.egg") self.weapon.reparentTo(self.v_model.exposeJoint(None, "modelRoot", "Bone.029")) self.weapon.setScale(0.75) self.weapon.setPos(0.45, -1.03, -1.17) self.weapon.setHpr(9.46, 308.19, 75.78) elif self.weaponName == "shotgun": self.weapon = loader.loadModel("phase_4/models/props/shotgun.egg") self.weapon.reparentTo(self.v_model.exposeJoint(None, "modelRoot", "Bone.029")) self.weapon.setScale(0.75) self.weapon.setPos(0.45, -1.03, -1.17) self.weapon.setHpr(9.46, 308.19, 75.78) self.gui.load() def start(self): base.camLens.setNear(0.1) self.shooterTrav = CollisionTraverser('ToonFPS.shooterTrav') ray = CollisionRay() rayNode = CollisionNode('ToonFPS.rayNode') rayNode.addSolid(ray) rayNode.setCollideMask(BitMask32(0)) rayNode.setFromCollideMask(CIGlobals.WallBitmask | CIGlobals.FloorBitmask) self.shooterRay = ray self.shooterRayNode = base.camera.attachNewNode(rayNode) self.shooterHandler = CollisionHandlerQueue() self.shooterTrav.addCollider(self.shooterRayNode, self.shooterHandler) self.firstPerson.start() self.v_model_root.reparentTo(base.camera) self.v_model.reparentTo(self.v_model_root) if self.weaponName == "pistol": self.v_model_root.setZ(-1.8) self.v_model_root.setY(0.3) self.v_model_root.setX(-0.1) self.v_model_root.setH(2) elif self.weaponName == "sniper": self.v_model_root.setPos(-0.42, -0.81, -1.7) self.v_model_root.setHpr(359, 352.87, 0.00) elif self.weaponName == "shotgun": self.v_model_root.setPos(-0.42, -0.81, -1.7) self.v_model_root.setHpr(359, 352.87, 0.00) self.gui.start() self.firstPerson.disableMouse() self.aliveFSM.request('draw') def reallyStart(self): self.firstPerson.reallyStart() base.localAvatar.startTrackAnimToSpeed() #taskMgr.add(self.movementTask, "toonBattleMovement") def end(self): if self.aliveFSM.getCurrentState().getName() != 'off': self.aliveFSM.request('off') if self.firstPerson: self.firstPerson.enableMouse() self.firstPerson.end() taskMgr.remove("toonBattleMovement") if self.mg.fsm.getCurrentState().getName() != "play": self.fsm.request('off') def reallyEnd(self): try: self.ToonFPS_reallyEnded return except: self.ToonFPS_reallyEnded = 1 if self.shooterRayNode: self.shooterRayNode.removeNode() self.shooterRayNode = None self.shooterRay = None self.shooterTrav = None self.shooterHandler = None if self.firstPerson: self.firstPerson.reallyEnd() if self.v_model_root: self.v_model_root.reparentTo(hidden) if self.v_model: self.v_model.reparentTo(hidden) self.v_model.setPosHpr(0, 0, 0, 0, 0, 0) if self.gui: self.gui.end() base.camLens.setNear(1.0) def cleanup(self): try: self.ToonFPS_cleanedUp return except: self.ToonFPS_cleanedUp = 1 taskMgr.remove("lookAtKiller") taskMgr.remove("toonBattleMovement") if self.firstPerson: self.firstPerson.cleanup() self.firstPerson = None self.draw = None self.shoot = None self.reload = None self.empty = None self.ammo = None try: self.aliveFSM.requestFinalState() self.fsm.requestFinalState() except: self.notify.warning('Redundant call to enter the final state.') self.fsm = None self.aliveFSM = None self.player_node = None self.min_camerap = None self.max_camerap = None self.hp = None self.max_hp = None if self.v_model: self.v_model.cleanup() self.v_model = None if self.weapon: self.weapon.removeNode() self.weapon = None if self.weapon: self.v_model_root.removeNode() self.v_model_root = None if self.gui: self.gui.cleanup() def damageTaken(self, amount, avId): if self.hp <= 0.0: killer = self.mg.cr.doId2do.get(avId, None) self.fsm.request('dead', [killer]) self.gui.adjustHpMeter() def enterDraw(self): self.draw.play() if self.weaponName == "pistol": self.track = ActorInterval(self.v_model, 'pdraw', playRate = 1.6, name = 'drawTrack') elif self.weaponName == "shotgun": self.v_model.pose('sidle', 15) self.track = LerpQuatInterval(self.v_model, duration = 0.5, quat = (0, 0, 0), startHpr = (70, -50, 0), blendType = 'easeOut', name = 'drawTrack') elif self.weaponName == "sniper": self.v_model.pose('sidle', 15) self.track = LerpQuatInterval(self.v_model, duration = 0.5, quat = (0, 0, 0), startHpr = (70, -50, 0), blendType = 'easeOut', name = 'drawTrack') self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitDraw(self): #self.draw.stop() if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None def enterIdle(self): if self.weaponName == "pistol": self.v_model.loop('pidle') elif self.weaponName == "shotgun": self.track = Sequence(LerpQuatInterval(self.v_model, duration = 2.0, quat = (0, 1, 0), startHpr = (0, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.v_model, duration = 2.0, quat = (0, 0, 0), startHpr = (0, 1, 0), blendType = 'easeInOut')) self.track.loop() elif self.weaponName == "sniper": self.track = Sequence(LerpQuatInterval(self.v_model, duration = 2.0, quat = (0, 1, 0), startHpr = (0, 0, 0), blendType = 'easeInOut'), LerpQuatInterval(self.v_model, duration = 2.0, quat = (0, 0, 0), startHpr = (0, 1, 0), blendType = 'easeInOut')) self.track.loop() self.accept('mouse1', self.requestShoot) if self.ammo <= 0: self.gui.notifyNoAmmo() if self.ammo < 14: self.accept('r', self.aliveFSM.request, ['reload']) def requestShoot(self): if self.mg.fsm.getCurrentState().getName() != "play": return if self.ammo > 0: self.aliveFSM.request('shoot') else: self.empty.play() def exitIdle(self): self.v_model.stop() if self.track: self.track.finish() self.track = None self.ignore('mouse1') self.ignore('r') def enterShoot(self): self.shoot.play() if self.weaponName == "pistol": self.track = ActorInterval(self.v_model, 'pshoot', playRate = 2, name = 'shootTrack') elif self.weaponName == "shotgun": self.track = Parallel( Sequence( LerpQuatInterval(self.v_model, duration = 0.05, quat = (0, 3, 0), startHpr = (0, 0, 0)), LerpQuatInterval(self.v_model, duration = 0.1, quat = (0, 0, 0), startHpr = (0, 3, 0)) ), Sequence( LerpPosInterval(self.v_model, duration = 0.05, pos = (0, -0.3, 0), startPos = (0, 0, 0)), LerpPosInterval(self.v_model, duration = 0.1, pos = (0, 0, 0), startPos = (0, -0.3, 0)), Wait(0.1) ), ) elif self.weaponName == "sniper": self.track = Parallel( Sequence( LerpQuatInterval(self.v_model, duration = 0.05, quat = (0, 3, 0), startHpr = (0, 0, 0)), LerpQuatInterval(self.v_model, duration = 0.1, quat = (0, 0, 0), startHpr = (0, 3, 0)) ), Sequence( LerpPosInterval(self.v_model, duration = 0.05, pos = (0, -0.3, 0), startPos = (0, 0, 0)), LerpPosInterval(self.v_model, duration = 0.1, pos = (0, 0, 0), startPos = (0, -0.3, 0)), Wait(0.1) ), ) self.track.setDoneEvent('shootTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() self.ammo -= 1 self.gui.adjustAmmoGui() self.mg.makeSmokeEffect(self.weapon.find('**/joint_nozzle').getPos(render)) self.traverse() def traverse(self): mpos = base.mouseWatcherNode.getMouse() self.shooterRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.shooterTrav.traverse(render) def calcDamage(self, avatar): dmgData = self.WeaponName2DamageData[self.weaponName] maxDamage = dmgData[0] minDistance = dmgData[1] maxDistance = dmgData[2] factor = dmgData[3] distance = base.localAvatar.getDistance(avatar) if distance < minDistance: distance = minDistance elif distance > maxDistance: distance = maxDistance damage = maxDamage - ((distance - minDistance) * factor) return damage def exitShoot(self): #self.shoot.stop() self.ignore('shootTrack') if self.track: self.track.finish() self.track = None def enterReload(self): self.gui.deleteNoAmmoLabel() if self.weaponName == "pistol": self.track = Parallel(Sequence(Wait(0.3), Func(self.reload.play), Func(self.resetAmmo)), ActorInterval(self.v_model, 'preload', playRate = 1.5), name = 'reloadTrack') elif self.weaponName == "shotgun": self.track = Sequence(Func(self.draw.play), LerpQuatInterval(self.v_model, duration = 0.5, quat = (70, -50, 0), startHpr = (0, 0, 0), blendType = 'easeIn'), SoundInterval(self.cockBack), SoundInterval(self.cockFwd), Func(self.resetAmmo), Func(self.draw.play), LerpQuatInterval(self.v_model, duration = 0.5, quat = (0, 0, 0), startHpr = (70, -50, 0), blendType = 'easeOut'), name = 'reloadTrack') elif self.weaponName == "sniper": self.track = Sequence(Func(self.draw.play), LerpQuatInterval(self.v_model, duration = 0.5, quat = (70, -50, 0), startHpr = (0, 0, 0), blendType = 'easeIn'), SoundInterval(self.cockBack), SoundInterval(self.cockFwd), Func(self.resetAmmo), Func(self.draw.play), LerpQuatInterval(self.v_model, duration = 0.5, quat = (0, 0, 0), startHpr = (70, -50, 0), blendType = 'easeOut'), name = 'reloadTrack') self.track.setDoneEvent('reloadTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitReload(self): #self.reload.stop() self.ignore('reloadTrack') if self.track: self.track.finish() self.track = None def resetAmmo(self): if self.weaponName == "pistol": self.ammo = 14 elif self.weaponName == "shotgun": self.ammo = 7 elif self.weaponName == "sniper": self.ammo = 7 self.gui.resetAmmo() def resetHp(self): self.hp = self.max_hp self.gui.adjustHpMeter() def enterOff(self): pass def exitOff(self): pass
class Monster(): def __init__(self, id, parent, type, pos): self.id = id self.parent = parent self.hp = 100 self.speed = 1 self.can_move = True if type == 'baby': self.node = Actor('models/baby', {'walk':'models/baby-walk', 'stand':'models/baby-stand', 'idle':'models/baby-idle', 'jump':'models/baby-jump', 'bite1':'models/baby-bite1', 'bite2':'models/baby-bite2', 'head_attack':'models/baby-head_attack', 'hit1':'models/baby-hit1', 'hit2':'models/baby-hit2', 'die':'models/baby-die'}) self.head_node = self.node.exposeJoint(None,"modelRoot","Bip01_Head") self.body_node = self.node.exposeJoint(None,"modelRoot","Bip01_Pelvis") self.node.setH(180) self.node.setScale(0.03) self.node.flattenLight() self.zpos = 0 self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos) self.node.setTexture(loader.loadTexture('models/Zomby_D.png')) self.ts_normal = TextureStage('ts_normal') self.tex_normal = loader.loadTexture('models/Zomby_N.png') self.ts_normal.setMode(TextureStage.MNormal) self.node.setTexture(self.ts_normal, self.tex_normal) self.ts_gloss = TextureStage('ts_gloss') self.tex_gloss = loader.loadTexture('models/Zomby_S1.png') self.ts_gloss.setMode(TextureStage.MGloss) self.node.setTexture(self.ts_gloss, self.tex_gloss) self.ts_glow = TextureStage('ts_glow') self.tex_glow = loader.loadTexture('models/Zomby_I.png') self.ts_glow.setMode(TextureStage.MGlow) self.node.setTexture(self.ts_glow, self.tex_glow) self.node.reparentTo(render) self.node.loop('walk') elif type == 'nos': self.node = loader.loadModel('models/nos') self.zpos = 5 self.node.setPos(pos[0]*TILE_SIZE,pos[1]*TILE_SIZE,self.zpos) self.node.setScale(2) if self.id == 1: self.node.setColor(1,0,0) elif self.id == 2: self.node.setColor(0,1,0) elif self.id == 3: self.node.setColor(0,0,1) else: self.node.setColor(1,1,1) self.node.reparentTo(render) #self.patrol_points = [(1,1), (4,11), (12,20), (18,4), (19,17)] #initialize 3d sound self.audio3d = Audio3DManager.Audio3DManager(base.sfxManagerList[0], base.camera) self.shot_head = self.audio3d.loadSfx('audio/Zombie In Pain-SoundBible.com-134322253.wav') self.shot_body = self.audio3d.loadSfx('audio/Zombie Moan-SoundBible.com-565291980.wav') self.moan1 = self.audio3d.loadSfx('audio/Mindless Zombie Awakening-SoundBible.com-255444348.wav') self.moan2 = self.audio3d.loadSfx('audio/Zombie Brain Eater-SoundBible.com-1076387080.wav') self.aggro_sound = self.audio3d.loadSfx('audio/Mummy Zombie-SoundBible.com-1966938763.wav') self.attack_sound = self.audio3d.loadSfx('audio/Chopping Off Limb-SoundBible.com-884800545.wav') self.audio3d.attachSoundToObject(self.moan1, self.node) self.audio3d.attachSoundToObject(self.moan2, self.node) self.audio3d.attachSoundToObject(self.shot_head, self.node) self.audio3d.attachSoundToObject(self.shot_body, self.node) self.audio3d.attachSoundToObject(self.aggro_sound, self.node) self.audio3d.attachSoundToObject(self.attack_sound, self.node) delay0 = Wait(d(35)) delay1 = Wait(25+d(35)) delay2 = Wait(25+d(35)) self.moan_sequence = Sequence(delay0, SoundInterval(self.moan1), delay1, SoundInterval(self.moan2), delay2) self.moan_sequence.loop() self.parent.collision_manager.createMonsterCollision(self) self.aggro_sound_last_played = 0 #--------------------------brain------------------------- self.node.setH( 160 ) self.pause = False self.action = ACTION_IDLE if percent(20): self.orders = ORDERS_PATROL else: self.orders = ORDERS_IDLE self.last_melee = 0 self.player_last_seen_abs = None self.idle_timer = time.time() self.idle_value = 1 self.current_waypoint = None #self.wait_until = None self.herding_timer = None self.path = None taskMgr.doMethodLater(1, self.behaviourTask, 'MonsterBehaviourTask'+str(self.id) ) taskMgr.doMethodLater(1, self.debugMoveTask, 'MonsterMoveTask'+str(self.id)) def getLOS(self): return self.parent.collision_manager.checkMonsterPlayerLos(self) def sensePlayer(self): """Return True if player sensed, and his last known coordinates are stored in self.player_last_seen_abs""" # if the player is dead, do not sense him if self.parent.player.health <= 0: return False #get player's position p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() #--------------------------------SENSE--------------------------------- #if player is within SENSING_RANGE we know he is there if self.distanceToPlayer() < SENSING_RANGE: #print "TOO CLOSE LOOSER!" self.player_last_seen_abs = p_pos_abs return True #---------------------------------HEAR---------------------------------- #if player is within HEARING_RANGE we know he is there effective_hearing_range = HEARING_RANGE if self.parent.player.gunshot_at: effective_hearing_range *= 3 else: if self.parent.player.sprint: effective_hearing_range *= 2 if not self.parent.player.moving: effective_hearing_range = 0 if self.distanceToPlayer() < effective_hearing_range: print "I HEAR U!" self.parent.player.adrenaline() #if we can see go chase him if self.getLOS(): self.player_last_seen_abs = p_pos_abs return True #we cannot see him, build new path to that tile else: dest = getTile( p_pos_abs ) path = pathFind(self.parent.level, getTile( self.node.getPos()), dest) if path: self.path = path self.orders = ORDERS_PATROL self.action = ACTION_FOLLOW_PATH return False #-------------------------------SEE--------------------------------- #if player is in front of us if self.angleToPlayerAbs() <= 45: #if he is close enough to see and we can see him if self.distanceToPlayer() <= VIEW_RANGE and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim!" return True #if player has a flashlight lit, and we can see him go after him if self.parent.player.flashlight and self.getLOS(): self.player_last_seen_abs = p_pos_abs #print "vidim flashlight" return True #---------------------SEE MY OWN SHADOW--------------------------- #if player is behind us and has a lit up flashlight and we have LOS to him if self.angleToPlayerAbs() > 135 and self.angleToPlayerAbs() < 225: if self.parent.player.flashlight and self.getLOS(): #if he is looking at us my_pos_rel = self.node.getPos( self.parent.player.node ) forward = Vec2( 0, 1 ) if math.fabs( forward.signedAngleDeg( Vec2( my_pos_rel[0], my_pos_rel[1] ) ) ) <= 30: #go after my own shadow print "herding" self.orders = ORDERS_HERDING self.node.setH( self.parent.player.node.getH() ) self.herding_timer = time.time() return False def distanceToPlayer(self): p_pos_abs = self.parent.player.node.getPos() my_pos_abs = self.node.getPos() return math.sqrt( math.pow( p_pos_abs[0] - my_pos_abs[0], 2) + math.pow( p_pos_abs[1] - my_pos_abs[1], 2) ) def angleToPlayer(self): p_pos_rel = self.parent.player.node.getPos( self.node ) forward = Vec2( 0, 1 ) return forward.signedAngleDeg( Vec2( p_pos_rel[0], p_pos_rel[1] ) ) def angleToPlayerAbs(self): return math.fabs( self.angleToPlayer() ) def behaviourTask(self, task): if self.pause: return task.again #top priority, if we sense a player, go after him! if self.sensePlayer(): if time.time() - self.aggro_sound_last_played > 5: self.aggro_sound.play() self.aggro_sound_last_played = time.time() self.action = ACTION_CHASE return task.again elif self.orders == ORDERS_IDLE: #percent chance to go on patrol if percent( 10 ): self.orders = ORDERS_PATROL return task.again self.action = ACTION_IDLE elif self.orders == ORDERS_PATROL: #percent chance to get idle if percent( 5 ): self.orders = ORDERS_IDLE return task.again #if we are already patroling, dont change anything if self.action == ACTION_FOLLOW_PATH: return task.again #build a new path for patrol dest = self.getNewPatrolPoint() self.path = pathFind(self.parent.level, getTile(self.node.getPos()), dest) self.action = ACTION_FOLLOW_PATH elif self.orders == ORDERS_HERDING: self.action = ACTION_MOVE if time.time() - self.herding_timer > HERDING_TIMEOUT: self.orders = ORDERS_IDLE return task.again def debugMoveTask(self, task): if self.pause: return task.cont #print "orders:", self.orders if self.action == ACTION_CHASE: self.parent.player.adrenaline() look_pos = Point3(self.player_last_seen_abs.getX(), self.player_last_seen_abs.getY(), self.zpos) self.node.lookAt( look_pos ) self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0) if self.distanceToPlayer() <= MELEE_RANGE and self.angleToPlayerAbs() <= 45 and self.getLOS(): if time.time() - self.last_melee >= MELEE_TIME: self.attack_sound.play() att = random.randint(0,2) if att == 0: animname = 'bite1' elif att == 1: animname = 'bite2' else: animname = 'head_attack' self.node.play(animname) duration = self.node.getNumFrames(animname) / 24 # animation play rate taskMgr.doMethodLater(duration, self.finishedAnim, 'FinishedAnim', extraArgs = []) self.parent.player.getDamage() self.last_melee = time.time() elif self.action == ACTION_IDLE: if time.time() - self.idle_timer > IDLE_TIME: #we are standing still and rotating, see on whic side we will rotate now self.idle_timer = time.time() if percent(20): self.idle_value *= -1 self.rotateBy( self.idle_value * IDLE_ROTATE_SPEED ) elif self.action == ACTION_FOLLOW_PATH: #if we dont have a waypoint, calculate one if not self.current_waypoint: try: #get next tile from path tile = self.path[0] self.path = self.path[1:] #calculate waypoint varx= 5 - (d(4) + d(4)) vary= 5 - (d(4) + d(4)) self.current_waypoint = (Point3( tile[0] * TILE_SIZE + varx, tile[1] * TILE_SIZE + vary, self.zpos ), time.time() ) #print "waypoint:", self.current_waypoint self.node.lookAt( self.current_waypoint[0] ) except (IndexError, TypeError): #we have reached the end of path self.orders = ORDERS_IDLE self.current_waypoint = None #if we have a waypoint move forward towards it, and check if we arrived at it else: self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0) my_pos = self.node.getPos() #if we are close enough to the waypoint or if we didnt get to waypoint in time, delete it so we know we need a new one if math.fabs( my_pos[0] - self.current_waypoint[0][0] ) < 1 and math.fabs( my_pos[1] - self.current_waypoint[0][1] ) < 2 \ or time.time() - self.current_waypoint[1] > WAYPOINT_TIMER: self.current_waypoint = None elif self.action == ACTION_MOVE: self.node.setFluidPos(self.node, 0, NORMAL_SPEED*globalClock.getDt(), 0) return task.cont def finishedAnim(self): if not self.pause: self.node.loop('walk') def rotateBy(self, value): self.node.setH( (self.node.getH() + value) % 360 ) def getNewPatrolPoint(self): lvl = self.parent.level allTiles = lvl.getFloorTiles() while True: t = ( d(lvl.getMaxX()), d(lvl.getMaxY()) ) if t in allTiles: return t def hitWall(self): if self.action == ACTION_CHASE: return #print "lupio!" """self.moan1.play() self.rotateBy( 180 ) self.node.setFluidPos(self.node, 0, CHASE_SPEED*globalClock.getDt(), 0) #self.action = IDLE """ """ old = self.node.getH() rnd = 80 + random.randint( 0, 20 ) forward = Vec2( 0, 1 ) impact = Vec2( pos[0], pos[1] ) angle = forward.signedAngleDeg( impact ) #print "angle:", angle if angle < 0: #+ cause angle is negative rnd = 91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) elif angle > 0: rnd = -91 + angle self.node.setH( (self.node.getH() + rnd)%360 ) #print "stari:", old, " novi:", self.node.getH() """ pass def pauze(self): if self.moan_sequence: self.moan_sequence.pause() self.pause = True def resume(self): if self.moan_sequence: self.moan_sequence.resume() self.pause = False def destroy(self): self.audio3d.detachSound(self.moan1) self.audio3d.detachSound(self.moan2) self.audio3d.detachSound(self.shot_head) self.audio3d.detachSound(self.shot_body) self.audio3d.detachSound(self.aggro_sound) self.audio3d.detachSound(self.attack_sound) if self.moan_sequence != None: self.moan_sequence.pause() self.moan_sequence = None taskMgr.remove('MonsterBehaviourTask'+str(self.id)) taskMgr.remove('MonsterMoveTask'+str(self.id)) self.cn_head.node().clearPythonTag('node') self.cn_body.node().clearPythonTag('node') self.cn_pusher.node().clearPythonTag('node') self.cn_ray.node().clearPythonTag('node') self.node.delete() self.node.cleanup() self.node.removeNode() """
class World(DirectObject): def __init__(self): self.keyMap = { "left": 0, "right": 0, "forward": 0, "cam-left": 0, "cam-right": 0, "grab": 0, "jump": 0, "run": 0, "walk": 0 } base.win.setClearColor(Vec4(0, 0, 0, 1)) # Post the instructions self.title = addTitle("RC-Soft: Catch the butterfly") self.inst1 = addInstructions(0.95, "[ESC]: Quit") self.inst2 = addInstructions(0.90, "[Left Arrow]: Rotate Ralph Left") self.inst3 = addInstructions(0.85, "[Right Arrow]: Rotate Ralph Right") self.inst4 = addInstructions(0.80, "[Up Arrow]: Run Ralph Forward") self.inst6 = addInstructions(0.70, "[A]: Rotate Camera Left") self.inst7 = addInstructions(0.65, "[S]: Rotate Camera Right") self.inst8 = addInstructions(0.60, "[G]: Grab") self.inst9 = addInstructions(0.55, "[J]: Jump [R]: Run [W]:Walk") # Set up the environment # # This environment model contains collision meshes. If you look # in the egg file, you will see the following: # # <Collide> { Polyset keep descend } # # This tag causes the following mesh to be converted to a collision # mesh -- a mesh which is optimized for collision, not rendering. # It also keeps the original mesh, so there are now two copies --- # one optimized for rendering, one for collisions. self.environ = loader.loadModel("models/world") self.environ.reparentTo(render) self.environ.setPos(0, 0, 0) # Create the main character, Ralph ralphStartPos = self.environ.find("**/start_point").getPos() self.ralph = Actor( "models/ralph", { "run": "models/ralph-run", "walk": "models/ralph-walk", "grab": "models/ralph-run" }) ## TODO : create model grab action self.ralph.reparentTo(render) self.ralph.setScale(.2) self.ralph.setPos(ralphStartPos) #show my fly self.fly = Actor("models/fluture", { "run": "models/fluture-anim1", "walk": "models/fluture-anim1" }) self.fly.reparentTo(render) self.fly.setScale(.08) self.fly.setPos(ralphStartPos) self.fly.loop("run") #start fly animation # Create a floater object. We use the "floater" as a temporary # variable in a variety of calculations. self.floater = NodePath(PandaNode("floater")) self.floater.reparentTo(render) # Accept the control keys for movement and rotation self.accept("escape", sys.exit) self.accept("arrow_left", self.setKey, ["left", 1]) self.accept("arrow_right", self.setKey, ["right", 1]) self.accept("arrow_up", self.setKey, ["forward", 1]) self.accept("a", self.setKey, ["cam-left", 1]) self.accept("s", self.setKey, ["cam-right", 1]) self.accept("arrow_left-up", self.setKey, ["left", 0]) self.accept("arrow_right-up", self.setKey, ["right", 0]) self.accept("arrow_up-up", self.setKey, ["forward", 0]) self.accept("a-up", self.setKey, ["cam-left", 0]) self.accept("s-up", self.setKey, ["cam-right", 0]) self.accept('1', self.setObject, [0]) self.accept('2', self.setObject, [1]) self.accept('3', self.setObject, [2]) self.accept('4', self.setObject, [3]) self.accept('g', self.setKey, ["grab", 1]) self.accept('j', self.setKey, ["jump", 1]) self.accept('j-up', self.setKey, ["jump", 0]) self.accept('r', self.setKey, ["run", 1]) self.accept('w', self.setKey, ["walk", 1]) taskMgr.add(self.move, "moveTask") # Game state variables self.isMoving = False # Set up the camera base.disableMouse() base.camera.setPos(self.ralph.getX(), self.ralph.getY() + 10, 2) # We will detect the height of the terrain by creating a collision # ray and casting it downward toward the terrain. One ray will # start above ralph's head, and the other will start above the camera. # A ray may hit the terrain, or it may hit a rock or a tree. If it # hits the terrain, we can detect the height. If it hits anything # else, we rule that the move is illegal. self.cTrav = CollisionTraverser() self.ralphGroundRay = CollisionRay() self.ralphGroundRay.setOrigin(0, 0, 1000) self.ralphGroundRay.setDirection(0, 0, -1) self.ralphGroundCol = CollisionNode('ralphRay') self.ralphGroundCol.addSolid(self.ralphGroundRay) self.ralphGroundCol.setFromCollideMask(BitMask32.bit(0)) self.ralphGroundCol.setIntoCollideMask(BitMask32.allOff()) self.ralphGroundColNp = self.ralph.attachNewNode(self.ralphGroundCol) self.ralphGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.ralphGroundColNp, self.ralphGroundHandler) self.camGroundRay = CollisionRay() self.camGroundRay.setOrigin(0, 0, 1000) self.camGroundRay.setDirection(0, 0, -1) self.camGroundCol = CollisionNode('camRay') self.camGroundCol.addSolid(self.camGroundRay) self.camGroundCol.setFromCollideMask(BitMask32.bit(0)) self.camGroundCol.setIntoCollideMask(BitMask32.allOff()) self.camGroundColNp = base.camera.attachNewNode(self.camGroundCol) self.camGroundHandler = CollisionHandlerQueue() self.cTrav.addCollider(self.camGroundColNp, self.camGroundHandler) # Uncomment this line to see the collision rays #self.ralphGroundColNp.show() #self.camGroundColNp.show() # Uncomment this line to show a visual representation of the # collisions occuring #self.cTrav.showCollisions(render) # Create some lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor(Vec4(.3, .3, .3, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(Vec3(-5, -5, -5)) directionalLight.setColor(Vec4(1, 1, 1, 1)) directionalLight.setSpecularColor(Vec4(1, 1, 1, 1)) render.setLight(render.attachNewNode(ambientLight)) render.setLight(render.attachNewNode(directionalLight)) # show an object in Ralph's hand #Now we will expose the joint the hand joint. ExposeJoint allows us to #get the position of a joint while it is animating. This is different than #controlJonit which stops that joint from animating but lets us move it. #This is particularly usefull for putting an object (like a weapon) in an #actor's hand self.rightHand = self.ralph.exposeJoint(None, 'modelRoot', 'RightHand') #This is a table with models, positions, rotations, and scales of objects to #be attached to our exposed joint. These are stock models and so they needed #to be repositioned to look right. positions = [("models/net", (0, -.66, -.95), (90, 0, 90), .4), ("models/fluture", (.15, -.99, -.22), (90, 0, 90), .5), ("models/banana", (.08, -.1, .09), (0, -90, 0), 1.75), ("models/sword", (.11, .19, .06), (0, 0, 90), 1)] self.models = [] #A list that will store our models objects for row in positions: np = loader.loadModel(row[0]) #Load the model np.setPos(row[1][0], row[1][1], row[1][2]) #Position it np.setHpr(row[2][0], row[2][1], row[2][2]) #Rotate it np.setScale(row[3]) #Scale it #Reparent the model to the exposed joint. That way when the joint moves, #the model we just loaded will move with it. np.reparentTo(self.rightHand) self.models.append(np) #Add it to our models list self.setObject(0) def setObject(self, i): for np in self.models: np.hide() self.models[i].show() #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): # If the camera-left key is pressed, move camera left. # If the camera-right key is pressed, move camera right. base.camera.lookAt(self.ralph) if (self.keyMap["cam-left"] != 0): base.camera.setX(base.camera, -20 * globalClock.getDt()) if (self.keyMap["cam-right"] != 0): base.camera.setX(base.camera, +20 * globalClock.getDt()) # save ralph's initial position so that we can restore it, # in case he falls off the map or runs into something. startpos = self.ralph.getPos() # If a move-key is pressed, move ralph in the specified direction. #dmove=150 #dforw=10 if (self.keyMap["run"] != 0 ): #if r key is pressed than run until arrows keys are depressed dmove = 300 #run means that the change of position has a bigger value dforw = 25 #if self.isMoving: # self.ralph.loop("run") else: dmove = 150 dforw = 10 if (self.keyMap["left"] != 0): self.ralph.setH(self.ralph.getH() + dmove * globalClock.getDt()) if (self.keyMap["right"] != 0): self.ralph.setH(self.ralph.getH() - dmove * globalClock.getDt()) if (self.keyMap["forward"] != 0): self.ralph.setY(self.ralph, -dforw * globalClock.getDt()) # If ralph is moving, loop the run animation. # If he is standing still, stop the animation. if (self.keyMap["walk"] != 0): if self.isMoving: self.ralph.loop("walk") self.setKey("run", 0) self.setKey("walk", 0) if (self.keyMap["forward"] != 0) or (self.keyMap["left"] != 0) or (self.keyMap["right"] != 0): if self.isMoving is False: if self.keyMap["run"] != 0: self.ralph.loop("run") #self.setKey("run",0) else: self.ralph.loop("walk") self.isMoving = True else: if self.isMoving: self.ralph.stop() self.ralph.pose("walk", 5) self.isMoving = False #Jump at different higths depending on velocity if (self.keyMap["jump"] != 0): if (self.keyMap["run"] != 0): jmp = 0.4 else: jmp = 0.2 else: jmp = 0 # grab something ->activate grab animation if (self.keyMap["grab"] != 0): if self.isMoving is False: self.ralph.pose("grab", 1) #workaround untill animation is ready!! self.keyMap["grab"] = 0 # If the camera is too far from ralph, move it closer. # If the camera is too close to ralph, move it farther. camvec = self.ralph.getPos() - base.camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() if (camdist > 10.0): base.camera.setPos(base.camera.getPos() + camvec * (camdist - 10)) camdist = 10.0 if (camdist < 5.0): base.camera.setPos(base.camera.getPos() - camvec * (5 - camdist)) camdist = 5.0 # Now check for collisions. self.cTrav.traverse(render) # Adjust ralph's Z coordinate. If ralph's ray hit terrain, # update his Z. If it hit anything else, or didn't hit anything, put # him back where he was last frame. entries = [] for i in range(self.ralphGroundHandler.getNumEntries()): entry = self.ralphGroundHandler.getEntry(i) if entry.getIntoNode().getName() != "terrain": print entry entries.append(entry) entries.sort(lambda x, y: cmp( y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): self.ralph.setZ(entries[0].getSurfacePoint(render).getZ() + jmp) else: self.ralph.setPos(startpos) # Keep the camera at one foot above the terrain, # or two feet above ralph, whichever is greater. entries = [] for i in range(self.camGroundHandler.getNumEntries()): entry = self.camGroundHandler.getEntry(i) entries.append(entry) entries.sort(lambda x, y: cmp( y.getSurfacePoint(render).getZ(), x.getSurfacePoint(render).getZ())) if (len(entries) > 0) and (entries[0].getIntoNode().getName() == "terrain"): base.camera.setZ(entries[0].getSurfacePoint(render).getZ() + 1.0) if (base.camera.getZ() < self.ralph.getZ() + 2.0): base.camera.setZ(self.ralph.getZ() + 2.0 - jmp) # The camera should look in ralph's direction, # but it should also try to stay horizontal, so look at # a floater which hovers above ralph's head. self.floater.setPos(self.ralph.getPos()) self.floater.setZ(self.ralph.getZ() + 2.0 - jmp) base.camera.lookAt(self.floater) return task.cont
s.accept('escape', sys.exit) s.cam.setPos(0, -5, 5) s.cam.lookAt(0, 0, 0) a = Actor('assets/cars/Ricardeaut_Magnesium.bam') a.reparentTo(s.render) puppet = s.loader.loadModel('assets/cars/Ricardeaut_Magnesium.bam') puppet.find("armature").hide() puppet.reparentTo(a) repulsors = a.findAllMatches('**/fz_repulsor*') print(repulsors) for r, repulsor in enumerate(repulsors): repulsor.setPos(0, 0, 0) repulsor.setP(-90) joint = a.exposeJoint(None, "modelRoot", "repulsor_bone:" + str(r)) repulsor.reparentTo(joint) #a.enableBlend() animations = ["gems", "accelerate", "turn", "strafe", "hover"] for animation in animations: a.setControlEffect(animation, 1) a.play(animation) def pingPong(animation, d, min=0, mid=10, max=20): frame = a.getCurrentFrame(animation) if frame == None: frame = 0 rate = a.getPlayRate(animation) if d == 1: if frame < max: a.setPlayRate(1, animation)
class CharGen(DirectObject): def __init__(self, common): self.common = common self.common['chargen'] = self self.load() def load(self): self.newGame = True self.font = loader.loadFont('Bitter-Bold.otf') self.common['font'] = self.font self.common['pc_stat1'] = 50 self.common['pc_stat2'] = 50 self.common['pc_stat3'] = 50 #render.setShaderAuto() #base.disableMouse() #render.setAntialias(AntialiasAttrib.MMultisample) #base.setBackgroundColor(0, 0, 0) wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() self.campmap = loader.loadModel("models/camp3") self.campmap.reparentTo(render) #music self.common['music'] = MusicPlayer(self.common) self.common['music'].loop(0) #self.common['music']=base.loadMusic("music/LuridDeliusion.ogg") #self.common['music'].setLoop(True) #self.common['music'].play() self.common["random-objects-freq"] = 0.65 self.node = render.attachNewNode("node") self.cameraNode = self.node.attachNewNode("cameraNode") self.cameraNode.setZ(-1) base.camera.setY(-8) base.camera.setZ(5) base.camera.lookAt((0, 3, 0)) base.camera.wrtReparentTo(self.cameraNode) self.pointer = self.cameraNode.attachNewNode("pointerNode") #light self.pLight = PointLight('plight') self.pLight.setColor(VBase4(1, .95, .9, 1)) self.pLight.setAttenuation(Point3(.5, 0, 0.1)) self.pLightNode = self.node.attachNewNode(self.pLight) self.pLightNode.setZ(1.0) render.setLight(self.pLightNode) self.sLight = Spotlight('sLight') self.sLight.setColor(VBase4(.4, .25, .25, 1)) if self.common['extra_ambient']: self.sLight.setColor(VBase4(.7, .5, .5, 1)) spot_lens = PerspectiveLens() spot_lens.setFov(40) self.sLight.setLens(spot_lens) self.Ambient = self.cameraNode.attachNewNode(self.sLight) self.Ambient.setPos(base.camera.getPos(render)) self.Ambient.lookAt((0, 3, 0)) render.setLight(self.Ambient) self.fire_node = self.node.attachNewNode("fireNode") self.fire = vfx(self.fire_node, texture='vfx/big_fire3.png', scale=.29, Z=.5, depthTest=True, depthWrite=True) self.fire.show() self.fire.loop(0.02) self.character1 = Actor( "models/pc/male", { "attack": "models/pc/male_attack2", "idle": "models/pc/male_ready2", "block": "models/pc/male_block" }) self.character1.reparentTo(self.node) self.character1.setBlend(frameBlend=True) self.character1.setPos(1, 2, 0) self.character1.setScale(.025) self.character1.setH(-25.0) self.character1.setBin("opaque", 10) self.character1.loop("idle") self.swingSound = base.loader.loadSfx("sfx/swing2.ogg") coll_sphere = self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(1, 2, 1, 1)) coll_sphere.setTag("class", "1") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) self.character2 = Actor("models/pc/female", { "attack": "models/pc/female_attack1", "idle": "models/pc/female_idle" }) #self.character2.setPlayRate(.4, "attack") self.character2.reparentTo(self.node) self.character2.setBlend(frameBlend=True) self.character2.setPos(-1, 2, 0) self.character2.setScale(.026) self.character2.setH(25.0) #self.character2.setBin("opaque", 10) self.character2.loop("idle") self.char2_magic = loader.loadModel('vfx/vfx3') self.char2_magic.setPos(self.character2.getPos()) self.char2_magic.setH(self.character2.getH()) self.char2_magic.setP(-10.0) self.char2_magic.setZ(0.71) self.char2_magic.setScale(1, 2, 1) self.char2_magic.wrtReparentTo(self.character2) self.char2_magic.setY(-10) self.char2_magic.setDepthWrite(False) self.char2_magic.setDepthTest(False) self.char2_magic.setLightOff() self.char2_magic.hide() self.vfxU = -0.125 self.vfxV = 0 self.magicSound = base.loader.loadSfx("sfx/thunder3.ogg") coll_sphere = self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(-1, 2, 1, 1)) coll_sphere.setTag("class", "2") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) self.character3 = Actor( "models/pc/female2", { "attack": "models/pc/female2_arm", "reset": "models/pc/female2_fire", "idle": "models/pc/female2_idle" }) #self.character2.setPlayRate(.4, "attack") self.character3.reparentTo(self.node) self.character3.setBlend(frameBlend=True) self.character3.setPos(-1.8, 0.9, 0) self.character3.setScale(.026) self.character3.setH(40.0) #self.character2.setBin("opaque", 10) self.character3.loop("idle") coll_sphere = self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(-1.8, 0.9, 0, 1)) coll_sphere.setTag("class", "3") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) self.arrow_bone = self.character3.exposeJoint(None, 'modelRoot', 'arrow_bone') self.arrow = loader.loadModel('models/arrow') self.arrow.reparentTo(self.arrow_bone) self.arrow.setP(-45) self.movingArrow = None self.arrowTime = 0.0 self.drawSound = base.loader.loadSfx("sfx/draw_bow2.ogg") self.fireSound = base.loader.loadSfx("sfx/fire_arrow3.ogg") self.character4 = Actor("models/pc/male2", { "attack": "models/pc/male2_aura", "idle": "models/pc/male2_idle" }) #self.character2.setPlayRate(.4, "attack") self.character4.reparentTo(self.node) self.character4.setBlend(frameBlend=True) self.character4.setPos(1.8, 0.9, 0) self.character4.setScale(.024) self.character4.setH(-60.0) #self.character2.setBin("opaque", 10) self.character4.loop("idle") self.FFSound = base.loader.loadSfx("sfx/teleport.ogg") #self.FFSound = base.loader.loadSfx("sfx/walk_new3.ogg") coll_sphere = self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(1.8, 0.9, 0, 1)) coll_sphere.setTag("class", "4") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) #gui self.mp_logo = DirectFrame(frameSize=(-512, 0, 0, 128), frameColor=(1, 1, 1, 1), frameTexture='images/mp_logo.png', state=DGG.NORMAL, parent=pixel2d) self.mp_logo.setPos(256 + winX / 2, 0, -winY) self.mp_logo.setBin('fixed', 1) self.mp_logo.hide() self.mp_logo.setTransparency(TransparencyAttrib.MDual) self.mp_logo.bind(DGG.B1PRESS, self.open_www, ['http://www.matthewpablo.com/']) #self.mp_logo.bind(DGG.WITHIN, self.GUIOnEnter, ["MP"]) #self.mp_logo.bind(DGG.WITHOUT, self.GUIOnExit) self.title = DirectFrame(frameSize=(-512, 0, 0, 128), frameColor=(1, 1, 1, 1), frameTexture='images/select.png', parent=pixel2d) self.title.setPos(256 + winX / 2, 0, -128) self.title.setBin('fixed', 1) self.title.setTransparency(TransparencyAttrib.MDual) #self.title.hide() self.close = DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/close.png', state=DGG.NORMAL, parent=pixel2d) self.close.setPos(winX, 0, -32) self.close.setBin('fixed', 1) self.close.bind(DGG.B1PRESS, self.exit) self.new_game_button = DirectButton( frameSize=(-0.2, 0.2, 0, 0.08), frameColor=(1, 1, 1, 1), frameTexture='images/level_select.png', text_font=self.font, text='START NEW GAME', text_pos=(-0.16, 0.026, 0), text_scale=0.035, text_fg=(0, 0, 0, 1), text_align=TextNode.ALeft, textMayChange=1, state=DGG.FLAT, relief=DGG.FLAT, pos=(0, 0, 0.5), command=self.onStart, parent=aspect2d) self.new_game_button.setBin('fixed', 1) self.new_game_button.hide() self.continue_button = DirectButton( frameSize=(-0.2, 0.2, 0, 0.08), frameColor=(1, 1, 1, 1), frameTexture='images/level_select.png', text_font=self.font, text='CONTINUE GAME', text_pos=(-0.16, 0.026, 0), text_scale=0.035, text_fg=(0, 0, 0, 1), text_align=TextNode.ALeft, textMayChange=1, state=DGG.FLAT, relief=DGG.FLAT, pos=(0, 0, 0.4), command=self.loadAndStart, parent=aspect2d) self.continue_button.setBin('fixed', 1) self.continue_button.hide() self.cursor = DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/cursor1.png', parent=pixel2d) self.cursor.setPos(32, 0, -32) self.cursor.flattenLight() self.cursor.setBin('fixed', 10) self.cursor.setTransparency(TransparencyAttrib.MDual) self.frameDesc = DirectFrame(frameSize=(0, 1, 0, 0.3), frameColor=(1, 1, 1, 1), frameTexture='images/frame1.png', state=DGG.NORMAL, pos=(-0.5, 0, 0.6), parent=aspect2d) self.labelDesc = DirectLabel( text="", text_fg=(1, 1, 1, 1), frameColor=(0, 0, 0, 0), #text_font=self.font, text_scale=0.06, text_align=TextNode.ALeft, pos=(0.1, 0, 0.2), parent=self.frameDesc) self.frameDesc.setBin('fixed', 1) self.frameDesc.hide() self.frameDesc.bind(DGG.WITHIN, self.GUIOnEnter, ["3B"]) self.frameDesc.bind(DGG.WITHOUT, self.GUIOnExit) #tooltip #self.font.setPixelsPerUnit(16) #self.font.setMinfilter(Texture.FTNearest ) #self.font.setMagfilter(Texture.FTNearest ) #self.font.setAnisotropicDegree(4) #self.font.setNativeAntialias(False) #self.font.setPageSize(1024,1024) self.Tooltip = DirectLabel( frameColor=(0, 0, 0, 0), text_font=self.font, text= 'Lorem ipsum dolor sit amet,\n consectetur adipisicing elit,\n sed do eiusmod tempor incididunt \nut labore et dolore magna aliqua.', #pos = (0, 0,-35), text_scale=16, text_fg=(1, 1, 1, 1), text_align=TextNode.ALeft, textMayChange=1, parent=pixel2d) self.Tooltip.flattenLight() self.Tooltip.setBin('fixed', 300) self.Tooltip.hide() #collisions #self.traverser=CollisionTraverser("playerTrav") #self.traverser.setRespectPrevTransform(True) #self.queue = CollisionHandlerQueue() self.MousePickerNode = CollisionNode('mouseRay') self.pickerNP = base.camera.attachNewNode(self.MousePickerNode) self.MousePickerNode.setFromCollideMask(BitMask32.bit(1)) self.MousePickerNode.setIntoCollideMask(BitMask32.allOff()) self.pickerRay = CollisionSegment() #Make our ray self.MousePickerNode.addSolid( self.pickerRay) #Add it to the collision node self.common['traverser'].addCollider(self.pickerNP, self.common['queue']) self.accept("mouse1", self.onClick) taskMgr.doMethodLater(0.2, self.flicker, 'flicker') #taskMgr.add(self.camera_spin, "camera_spin") taskMgr.add(self.__getMousePos, "chargenMousePos") self.current_class = None self.currentLevel = 0 self.camLoop = Sequence( LerpHprInterval(self.cameraNode, 10.0, VBase3(-20, 0, 0), bakeInStart=0), LerpHprInterval(self.cameraNode, 10.0, VBase3(20, 0, 0), bakeInStart=0)) self.camLoop.loop() self.accept('window-event', self.windowEventHandler) def selectLevel(self, next, event=None): self.currentLevel += next if self.currentLevel < 0: self.currentLevel = 0 if self.currentLevel > self.common['max_level']: self.currentLevel = self.common['max_level'] self.start_main['text'] = "Start in Level " + str(self.currentLevel + 1) def moveArrow(self, task): if self.movingArrow: self.arrowTime += task.time if self.arrowTime > 3.0: self.movingArrow.removeNode() self.arrowTime = 0.0 return task.done dt = globalClock.getDt() self.movingArrow.setX(self.movingArrow, 400 * dt) return task.again else: return task.done def fireArrow(self): self.movingArrow = loader.loadModel('models/arrow') self.movingArrow.reparentTo(self.arrow_bone) self.movingArrow.setP(-45) self.movingArrow.wrtReparentTo(render) self.arrow.hide() self.fireSound.play() taskMgr.add(self.moveArrow, "moveArrowTask") Sequence(Wait(0.5), Func(self.arrow.show)).start() def loadAndStart(self): self.newGame = False self.common['levelLoader'].loadGame(PCLoad=False) self.onStart() def onStart(self, event=None): #unload stuff self.camLoop.pause() self.camLoop = None base.camera.reparentTo(render) self.campmap.removeNode() self.node.removeNode() self.fire.remove_loop() if taskMgr.hasTaskNamed('flicker'): taskMgr.remove('flicker') if taskMgr.hasTaskNamed('chargenMousePos'): taskMgr.remove('chargenMousePos') self.common['traverser'].removeCollider(self.pickerNP) self.pickerNP.removeNode() self.Ambient.removeNode() self.frameDesc.destroy() self.labelDesc.destroy() self.Tooltip.destroy() self.cursor.destroy() self.new_game_button.destroy() self.continue_button.destroy() self.close.destroy() self.title.destroy() self.mp_logo.destroy() render.setLightOff() self.ignoreAll() #self.common['music'].stop() #self.common['spawner']=Spawner(self.common) #self.common['levelLoader']=LevelLoader(self.common) if not self.newGame and 'max_level' in self.common: self.currentLevel = self.common['max_level'] else: self.currentLevel = 0 self.common['levelLoader'].load(self.currentLevel, PCLoad=False) #render.ls() if self.newGame or not 'current_class' in self.common: self.common['current_class'] = self.current_class else: self.current_class = self.common['current_class'] if self.current_class == "1": self.common['PC'] = Knight(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class == "2": self.common['PC'] = Witch(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class == "3": self.common['PC'] = Archer(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class == "4": self.common['PC'] = Wizard(self.common) #self.common['PC'].node.setPos(-12, 0, 0) pos = (data.levels[self.currentLevel]["enter"][0], data.levels[self.currentLevel]["enter"][1], data.levels[self.currentLevel]["enter"][2]) self.common['PC'].node.setPos(pos) self.common['music'].loop(1, fadeIn=True) if not self.newGame: self.common['levelLoader'].loadGame(PCLoad=True) def open_www(self, url, event=None): webbrowser.open_new(url) def windowEventHandler(self, window=None): #print "resize" if window is not None: # window is none if panda3d is not started wp = base.win.getProperties() X = wp.getXSize() / 2 Y = wp.getYSize() # self.frameDesc.setPos(-96+X, 0, -32) self.title.setPos(256 + X, 0, -128) self.close.setPos(X * 2, 0, -32) self.mp_logo.setPos(256 + X, 0, -Y) def GUIOnEnter(self, object, event=None): if object[0] == "4": if object[1] == "A": self.Tooltip['text'] = "Click to start!" elif object[1] == "B": self.Tooltip['text'] = "Next level" elif object[1] == "C": self.Tooltip['text'] = "Previous level" self.Tooltip['text_pos'] = (10, -40, 0) self.Tooltip['text_align'] = TextNode.ACenter self.Tooltip.show() return if not self.current_class: return #print int(self.current_class) def GUIOnExit(self, event=None): self.Tooltip.hide() #print "out" def start_lightning(self, time=0.03): taskMgr.doMethodLater(time, self.lightning, 'vfx') self.magicSound.play() def lightning(self, task): self.char2_magic.show() self.vfxU = self.vfxU + 0.5 if self.vfxU >= 1.0: self.vfxU = 0 self.vfxV = self.vfxV - 0.125 if self.vfxV <= -1: self.char2_magic.hide() self.vfxU = 0 self.vfxV = 0 return task.done self.char2_magic.setTexOffset(TextureStage.getDefault(), self.vfxU, self.vfxV) return task.again def loopAnim(self, actor, anim): actor.loop(anim) def set_slider(self, id): #self.current_class=id #print id, if id == "1": self.common['pc_stat1'] = int(self.slider1['value']) #print self.common['pc_stat1'] elif id == "2": self.common['pc_stat2'] = int(self.slider2['value']) #print self.common['pc_stat2'] elif id == "3": self.common['pc_stat3'] = int(self.slider3['value']) #print self.common['pc_stat3'] def onClick(self): self.common['traverser'].traverse(render) my_class = None for entry in self.common['queue'].getEntries(): if entry.getIntoNodePath().hasTag("class"): my_class = entry.getIntoNodePath().getTag("class") if Path("save.dat").exists(): self.continue_button.show() if my_class == "1": self.current_class = my_class self.title.hide() self.labelDesc.setText( "Knight:\nHe has greater resistance.\nHe can attack with the sword\nand defend with a shield." ) self.frameDesc.show() self.new_game_button.show() Sequence(self.character1.actorInterval("attack"), self.character1.actorInterval("block"), Func(self.loopAnim, self.character1, "idle")).start() self.swingSound.play() #self.character1.play("attack") self.character2.loop("idle") elif my_class == "2": self.current_class = my_class self.title.hide() self.labelDesc.setText( "Witch:\nShe can throw energy balls and\na long distance beam." ) self.frameDesc.show() self.new_game_button.show() Sequence(self.character2.actorInterval("attack", playRate=0.8), Func(self.loopAnim, self.character2, "idle")).start() Sequence(Wait(0.3), Func(self.start_lightning, 0.05)).start() #self.character2.play("attack") self.character1.loop("idle") #RayVfx(self.character2, texture='vfx/lightning.png').start() elif my_class == "3": self.current_class = my_class self.title.hide() self.labelDesc.setText( "Archer:\nShe can throw arrows\nand run faster.") self.frameDesc.show() self.new_game_button.show() self.drawSound.play() self.character3.play("attack") Sequence(Wait(1.5), Func(self.fireArrow), Func(self.character3.play, "reset"), Wait(1.0), Func(self.loopAnim, self.character3, "idle")).start() elif my_class == "4": self.current_class = my_class self.title.hide() self.labelDesc.setText( "Wizard:\nHe can throw magma balls\nand teleport himself.") self.frameDesc.show() self.new_game_button.show() self.character4.loop("attack") aura = vfx(self.character4, texture='vfx/tele2.png', scale=.5, Z=.85, depthTest=False, depthWrite=False) aura.show() aura.start() self.FFSound.play() Sequence(Wait(2.2), Func(self.loopAnim, self.character4, "idle")).start() def exit(self, event=None): self.common['root'].save_and_exit() #sys.exit() def __getMousePos(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) pos2d = Point3(mpos.getX(), 0, mpos.getY()) self.cursor.setPos(pixel2d.getRelativePoint(render2d, pos2d)) self.Tooltip.setPos(self.cursor.getPos()) return task.again def flicker(self, task): self.pLight.setAttenuation(Point3(1, 0, random.uniform(.1, 0.15))) self.pLightNode.setZ(random.uniform(.9, 1.1)) #self.pLight.setColor(VBase4(random.uniform(.9, 1.0), random.uniform(.9, 1.0), .9, 1)) return task.again def camera_spin(self, task): H = self.cameraNode.getH() #Z=self.cameraNode.getZ() #print H if H <= -20.0 or H >= 20.0: if self.reverse_spin: self.reverse_spin = False else: self.reverse_spin = True if self.reverse_spin: self.cameraNode.setH(self.cameraNode, 4 * globalClock.getDt()) #self.cameraNode.setZ(Z+0.1*globalClock.getDt()) else: self.cameraNode.setH(self.cameraNode, -4 * globalClock.getDt()) #self.cameraNode.setZ(Z-0.1*globalClock.getDt()) return task.again
class MakePlayer(DirectObject): """ MakePlayer Class: This class handels the creation of Players. Players will be stored in the Entity dict. """ def __init__(self): """ constructor: @param name: String_name, for the Player - In game. @param entityName: String_name for the PC - Player in ENTITY / dict{} for all uses in code. """ self.direction = Vec3(0,0,0) self.angular_direction = Vec3(0,0,0) self.speed = 1 self.angular_speed = 3 # Setup Player inventory self.playerDataStorage = [] # May change ## ADD MOUSE LOOK TASK TO TASKMGR #taskMgr.add(self.look, 'camera') # Crouch Flag self.crouching = False # Mouse look self.omega = 0.0 # Setup player input self.accept('space', self.jump) self.accept('c', self.crouch) # We need to fix the height self.accept( "escape",sys.exit ) self.accept('arrow_up', self.up ) self.accept('arrow_down', self.down ) self.accept('arrow_left', self.left ) self.accept('arrow_right', self.right) self.accept("arrow_up-up", self.idle, ["up"]) self.accept("arrow_down-up", self.idle, ["down"]) self.accept("arrow_left-up", self.idle, ["left"]) self.accept("arrow_right-up", self.idle, ["right"]) #inputState.watchWithModifiers('forward', 'w') #inputState.watchWithModifiers('left', 'a') #inputState.watchWithModifiers('reverse', 's') #inputState.watchWithModifiers('right', 'd') #inputState.watchWithModifiers('turnLeft', 'q') #inputState.watchWithModifiers('turnRight', 'e') #inputState.watchWithModifiers('turnRight', 'e') # Camera Setup for player # Get the screen size for the camera controller self.winXhalf = base.win.getXSize()/2 self.winYhalf = base.win.getYSize()/2 ## SETUP CHARACTER AND CHARACTER SHAPE # Setup Shape # units = meters # body height : 1.8 meters # eyes line : 1.8 - 0.11 meters = 1.69 meters # h is distance between the centers of the 2 spheres # w is radius of the spheres # 1.8 = 0.3 + 1.2 + 0.3 # center : 1.8/2 = 0.9 # camera height : 1.69-0.9 = 0.79 h = 1.2 w = 0.3 # Player needs different setup saam as bullet character controller. # Atm force gets added onto the node making it ballich shape = BulletCapsuleShape(w, h , ZUp) node = BulletRigidBodyNode('Box') node.setMass(1.0) node.addShape(shape) self.node = node node.setAngularDamping(10) np = GAMEPLAY_NODES['PLAYER'].attachNewNode(node) np.setPos(0, 0, 1) self.arm = np.attachNewNode('arm') self.arm.setPos(0,0,0.2) self.np = np PHYSICS['WORLD'].attachRigidBody(node) #self.character = BulletCharacterControllerNode(shape, 1, 'Player') #-------------------------------------------------------------------# # PLAYER GRAVITY SETTINGS AND FALL SPEED # #self.character.setGravity(0.87) #self.character.setFallSpeed(0.3) # #-------------------------------------------------------------------# #self.characterNP = GAMEPLAY_NODES['PLAYER'].attachNewNode(self.character) #self.characterNP.setPos(0, 0, 2) # May need some tweaking #self.characterNP.setCollideMask(BitMask32.allOn()) # Attach the character to the base _Physics #PHYSICS['WORLD'].attachCharacter(self.character) # Reparent the camera to the player #base.camera.reparentTo(self.np) #base.camera.setPos(0,0,0.79) #base.camLens.setNearFar(camNear,camFar) base.camLens.setFov(90) base.disableMouse() gui = Crosshair() self.arm = loader.loadModel('../assets/models/test.egg') screens = self.arm.findAllMatches('**') self.arm_screen = None rot = 0 pos = 0 for screen in screens : if screen.hasTag('screen'): self.arm_screen = screen rot = screen.getHpr() pos = screen.getPos() print("rotation"+str(rot)) self.actor = Actor('../assets/models/test.egg', {'anim1':'../assets/models/test-Anim0.egg'}) self.actor.reparentTo(self.np) self.actor.loop('anim1') self.actor.setPos(.0,-0.1,0.4) self.actor.setH(180) self.actor.node().setBounds(OmniBoundingVolume()) self.actor.node().setFinal(True) #self.actor.setTwoSided(True) #self.actor.reparentTo(self.world.buffer_system.geom_cam) #self.actor.hide(self.world.buffer_system.light_mask) # attach smth to hand picker = self.actor.exposeJoint(None,"modelRoot","hand_picker") arm_bone = self.actor.exposeJoint(None,"modelRoot","screen_picker") self.arm_screen.reparentTo(arm_bone) self.arm_screen.setH(self.arm_screen.getH()+90) self.temp_animate = self.arm_screen self.picker = picker taskMgr.add(self.update,'update player position') # Player Debug: #print "" #print "Player Character controller settings: " #print "" #print "Character Gravity: ", self.character.getGravity() #print "Character Max Slope: ",self.character.getMaxSlope() #print "" def up(self): self.direction += Vec3(0,1,0) self.angular_direction += Vec3(1,0,0) def down(self): self.direction += Vec3(0,-1,0) def left(self): self.direction += Vec3(-1,0,0) def right(self): self.direction += Vec3(1,0,0) def idle(self, key): if(key == "up"): self.direction -= Vec3(0,1,0) self.angular_direction -= Vec3(1,0,0) elif(key == "down"): self.direction -= Vec3(0,-1,0) elif(key == "left"): self.direction -= Vec3(-1,0,0) elif(key == "right"): self.direction -= Vec3(1,0,0) # Handle player jumping def jump(self): self.character.setMaxJumpHeight(2.3) self.character.setJumpSpeed(4.5) self.character.doJump() # Handle player crouch. <Buged to shit> def crouch(self): self.crouching = not self.crouching sz = self.crouching and 0.6 or 1.0 #self.character.getShape().setLocalScale(Vec3(1, 1, sz)) self.characterNP.setScale(Vec3(1, 1, sz) * 0.3048) #self.characterNP.setPos(0, 0, -1 * sz) # Handle player mouse def look(self, task): dt = globalClock.getDt() # Handle mouse md = base.win.getPointer(0) x = md.getX() y = md.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): self.omega = (x - self.winXhalf)*-mouseSpeed base.camera.setP( (clampScalar(-90,90, base.camera.getP() - (y - self.winYhalf)*0.09)) ) self.processInput(dt) return task.cont def update(self,task): dt = globalClock.getDt() self.np.setPos(self.np,self.direction * dt * self.speed) base.camera.setPos(self.np.getPos()+ Vec3(0,0,0.79)) md = base.win.getPointer(0) x = md.getX() y = md.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): base.camera.setP(base.camera.getP() - (y - self.winYhalf)*dt*self.angular_speed) self.np.setH(self.np.getH() - (x - self.winXhalf)*dt*self.angular_speed) base.camera.setH(self.np.getH()) base.camera.setR(self.np.getR()) self.node.setAngularFactor(0) self.node.setAngularVelocity(0) BUFFER_SYSTEM['main'].reflection_cube.setPos(base.camera.getPos()) BUFFER_SYSTEM['main'].reflection_cube.setHpr(base.camera.getHpr()) return task.cont # Handle player input def processInput(self, dt): print(self.direction) speed = Vec3(0, 0, 0) #@param PCSpeed: Player move speed under devconfig.py if inputState.isSet('forward'): speed.setY( PCSpeed) if inputState.isSet('reverse'): speed.setY(-PCSpeed) if inputState.isSet('left'): speed.setX(-PCSpeed) if inputState.isSet('right'): speed.setX( PCSpeed) self.character.setAngularMovement(self.omega) self.character.setLinearMovement(speed, True)
class Cannon: def __init__(self, cycle, mount, audio3D): self.cycle = cycle self.name = "Virtue X-A9 Equalizer" self.audio3D = audio3D self.actor = Actor("../Models/CannonActor.egg") self.model = loader.loadModel("../Models/Cannon.bam") self.actor.reparentTo(mount) self.model.reparentTo(self.actor) self.flashModel = loader.loadModel("../Models/LaserFlash.bam") self.projModel = loader.loadModel("../Models/LaserProj.bam") self.refNP = self.cycle.trgtrMount.attachNewNode("CannonRefNP") self.muzzle = self.actor.exposeJoint(None, "modelRoot", "Muzzle") self.audio3D = audio3D self.fireSfx = self.audio3D.loadSfx("../Sound/LaserShot.wav") self.audio3D.attachSoundToObject(self.fireSfx, self.muzzle) reloadTime = 1.5 self.damage = 75 self.energyCost = 5 self.blastR = 10 self.flashLerp = LerpScaleInterval(self.flashModel, reloadTime * .1, Point3(2, 2, 2), Point3(.2, .2, .2)) self.firePar = Parallel(Func(self.checkForHit), Func(self.setEffects), self.flashLerp) self.fireSeq = Sequence(self.firePar, Func(self.clearEffects), Wait(reloadTime * .9)) def fire(self): if (self.fireSeq.isPlaying() == False): self.fireSeq.start() self.fireSfx.play() self.cycle.energy -= self.energyCost return def setEffects(self): self.flashModel.reparentTo(self.muzzle) self.projModel.reparentTo(self.muzzle) self.projModel.lookAt(self.refNP.getPos(self.muzzle)) self.projModel.setSy( trueDist(Point3(0, 0, 0), self.refNP.getPos(self.muzzle)) * 2) return def clearEffects(self): self.flashModel.detachNode() self.projModel.detachNode() return def checkForHit(self): self.cycle.trgtrCTrav.traverse(render) if (self.cycle.trgtrCHan.getNumEntries() > 0): self.cycle.trgtrCHan.sortEntries() entry = self.cycle.trgtrCHan.getEntry(0) # If collisions were detected sort them nearest to far and pull out the first one. colPoint = entry.getSurfacePoint(render) self.refNP.setPos(render, colPoint) # Get the collision point and the range to the collision. boom = Boom(colPoint, self.blastR, self.damage, self.audio3D) # Create an explosion at the collision point. else: self.refNP.setPos(self.cycle.trgtrCNP, 0, 300, 0) boom = Boom(self.refNP.getPos(render), self.blastR, self.damage, self.audio3D) # If no collision was detected, create a boom at a distant point. def destroy(self): self.actor.delete() self.model.removeNode() self.flashModel.removeNode() self.projModel.removeNode() self.refNP.removeNode() self.cycle = None self.flashLerp = None self.firePar = None self.fireSeq = None self.audio3D.detachSound(self.fireSfx) return
class Monster(): def __init__(self, setup_data, common, level=1.0, start_pos=(0,0,0)): common['monsterList'].append(self) id=len(common['monsterList'])-1 self.monsterList=common['monsterList'] self.waypoints_data=common['waypoints_data'] self.waypoints=common['waypoints'] self.audio3d=common['audio3d'] self.common=common #root node self.node=render.attachNewNode("monster") self.sound_node=None self.soundset=None self.actor=Actor(setup_data["model"],setup_data["anim"] ) self.actor.setBlend(frameBlend = True) self.actor.reparentTo(self.node) self.actor.setScale(setup_data["scale"]*random.uniform(0.9, 1.1)) self.actor.setH(setup_data["heading"]) self.actor.setBin("opaque", 10) self.rootBone=self.actor.exposeJoint(None, 'modelRoot', setup_data["root_bone"]) #sounds self.soundID=self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.sound_names={"hit":setup_data["hit_sfx"], "arrow_hit":setup_data["arrowhit_sfx"], "attack":setup_data["attack_sfx"], "die":setup_data["die_sfx"]} self.vfx=setup_data["hit_vfx"] self.stats={"speed":setup_data["speed"], "hp":setup_data["hp"]*level, "armor":setup_data["armor"]*level, "dmg":setup_data["dmg"]*level } if self.stats['hp']>300: self.stats['hp']=300 self.maxHP=self.stats['hp'] self.HPring=Actor("models/ring_morph", {'anim' : 'models/ring_anim'}) self.HPring.setScale(0.07) self.HPring.setZ(0.4) self.HPring.setLightOff() self.HPring.reparentTo(self.node) self.HPvis=self.HPring.controlJoint(None, 'modelRoot', 'morph01') self.HPvis.setX(self.stats['hp']/300) self.HPring.hide(BitMask32.bit(1)) self.HPring.hide() #self.HPring.setColorScale(0.0, 1.0, 0.0, 1.0) #gamestate variables self.attack_pattern=setup_data["attack_pattern"] self.damage=setup_data["dmg"] #self.HP=setup_data["hp"] self.state="STOP" self.id=id self.nextWaypoint=None self.canSeePC=False self.PCisInRange=False self.PC=common['PC'] self.speed_mode=random.randrange(0+int(level),42+int(level), 7)/100.0 self.totalSpeed=self.stats['speed']+self.speed_mode self.sparkSum=0 self.lastMagmaDmg=0 self.DOT=0 self.arrows=set() self.traverser=CollisionTraverser("Trav"+str(self.id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #bit masks: # 1 visibility polygons & coll-rays # 2 walls & radar-ray # 3 spheres #collision ray for testing visibility polygons coll=self.node.attachNewNode(CollisionNode('collRay')) coll.node().addSolid(CollisionRay(0, 0, 2, 0,0,-180)) coll.setTag("id", str(id)) coll.node().setIntoCollideMask(BitMask32.allOff()) coll.node().setFromCollideMask(BitMask32.bit(1)) self.traverser.addCollider(coll, self.queue) #radar collision ray self.radar=self.node.attachNewNode(CollisionNode('radarRay')) self.radar.node().addSolid(CollisionRay(0, 0, 1, 0,90,0)) self.radar.node().setIntoCollideMask(BitMask32.allOff()) self.radar.node().setFromCollideMask(BitMask32.bit(2)) self.radar.setTag("radar", str(id)) #self.radar.show() self.traverser.addCollider(self.radar, self.queue) #collision sphere self.coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) self.coll_sphere.node().addSolid(CollisionSphere(0, 0, 0.8, 0.8)) self.coll_sphere.setTag("id", str(id)) self.coll_sphere.node().setIntoCollideMask(BitMask32.bit(3)) #coll_sphere.show() #other monster blocking self.coll_quad=loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) #coll_quad=render.attachNewNode(CollisionNode('monsterSphere')) #coll_quad.node().addSolid(CollisionPolygon(Point3(-.5, -.5, 2), Point3(-.5, .5, 0), Point3(.5, .5, 0), Point3(.5, .5, 2))) #coll_quad.setTag("id", str(id)) #coll_quad.node().setIntoCollideMask(BitMask32.bit(2)) #coll_quad.reparentTo(self.node) #coll_quad.show() Sequence(Wait(random.uniform(.6, .8)), Func(self.restart)).start() self.node.setPos(render,start_pos) taskMgr.add(self.runAI, "AIfor"+str(self.id)) taskMgr.doMethodLater(.6, self.runCollisions,'collFor'+str(self.id)) taskMgr.doMethodLater(1.0, self.damageOverTime,'DOTfor'+str(self.id)) def damageOverTime(self, task): if self.state=="DIE": return task.done if self.DOT>0: self.doDamage(self.DOT) self.DOT=int((self.DOT*0.9)-1.0) if self.stats['hp']<1: self.actor.play("die") #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) self.common['soundPool'].play(self.soundID, self.sound_names["die"]) self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016, 24) return task.again def restart(self): self.state="SEEK" def check_stacking(self): for monster in self.monsterList: if monster and monster.id!=self.id : if self.node.getDistance(monster.node)< .8: if monster.state!="STOP" and self.state=="SEEK": if self.totalSpeed <= monster.totalSpeed: self.state="STOP" self.actor.stop() Sequence(Wait(1.5), Func(self.restart)).start() return True def doDamage(self, damage, igoreArmor=False): if self.state=="DIE": return if not igoreArmor: damage-=self.stats['armor'] if damage<1: damage=1 #print damage self.stats['hp']-=damage scale=self.stats['hp']/self.maxHP self.HPvis.setX(self.stats['hp']/300.0) #self.HPring.setColor(0.8*(1.0-scale), 0.8*scale, 0.0, 1.0) self.HPring.show() self.HPring.setColorScale((1.0-scale), scale, 0.0, 1.0) if self.stats['hp']<1: self.HPring.hide() def attack(self, pattern): if self.state=="DIE": return if not self.PC.node: return if pattern: next=pattern.pop() else: self.state="SEEK" self.PCisInRange=False return if self.PC.node and self.node: range= self.node.getDistance(self.PC.node) else: return #print range if range<1.8: self.PC.hit(self.damage) Sequence(Wait(next), Func(self.attack, pattern)).start() def onMagmaHit(self): if self.state=="DIE": return damage=self.lastMagmaDmg self.doDamage(damage) self.common['soundPool'].play(self.soundID, "onFire") vfx(self.node, texture="vfx/small_flame.png",scale=.6, Z=.7, depthTest=False, depthWrite=False).start(0.016, stopAtFrame=24) if self.stats['hp']<1: self.actor.play("die") self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) def onPlasmaHit(self, damage): if self.state=="DIE": return self.doDamage(damage*1.5, True) #self.soundset["spark"].play() #self.common['soundPool'].play(self.soundID, "spark") if self.stats['hp']<1: self.actor.play("die") #self.soundset["die3"].play() self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) #else: # short_vfx(self.node, texture="vfx/short_spark.png",scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) def onSparkHit(self, damage): if self.state=="DIE": return #print damage self.doDamage(damage) #self.soundset["spark"].play() self.common['soundPool'].play(self.soundID, "spark") if self.stats['hp']<1: self.actor.play("die") #self.soundset["die3"].play() self.common['soundPool'].play(self.soundID, "die3") self.state="DIE" vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) else: short_vfx(self.node, texture="vfx/short_spark.png",scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) def onHit(self, damage, sound="hit"): if self.state=="DIE": return self.doDamage(damage) #print damage vfx(self.node, texture=self.vfx,scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) if self.stats['hp']<1: self.actor.play("die") #self.sounds["die"].play() if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) self.common['soundPool'].play(self.soundID, self.sound_names["die"]) self.state="DIE" else: #self.sounds["hit"].play() if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) def findFirstWaypoint(self): min=100000 nearest=None for waypoint in self.waypoints: dist=self.node.getDistance(waypoint) if dist<min: min=dist nearest=waypoint return nearest def runCollisions(self, task): if self.state=="DIE": return task.done if self.node.getDistance(self.PC.node) >50.0: self.nextWaypoint=None return task.again if self.check_stacking(): return task.again self.radar.lookAt(self.PC.node) valid_waypoints=[] isFirstTest=True self.canSeePC=False self.traverser.traverse(render) self.queue.sortEntries() for entry in self.queue.getEntries(): if entry.getFromNodePath().hasTag("id"): #it's the monsters collRay valid_waypoints.append(int(entry.getIntoNodePath().getTag("index"))) #visibility polygons elif entry.getFromNodePath().hasTag("radar"): #it's the radar-ray #print "radar hit", entry.getIntoNodePath() if isFirstTest: isFirstTest=False #print "first hit!" #print "radar hit", entry.getIntoNodePath() if entry.getIntoNodePath().hasTag("player"): self.canSeePC=True '''distance={} for target in self.PC.myWaypoints: for waypoint in valid_waypoints: distance[target]=self.waypoints_data[target][waypoint] print(target, distance[target]) if distance: self.nextWaypoint=self.waypoints[min(distance, key=distance.get)] #print self.canSeePC''' if not valid_waypoints: #self.nextWaypoint=self.findFirstWaypoint() print(self.id, ": I'm lost!") valid_waypoints=[self.findFirstWaypoint()] #return task.again if self.state=="STOP": self.nextWaypoint=self.waypoints[random.choice(valid_waypoints)] return task.again best_distance=9000000 target_node=None for target in self.PC.myWaypoints: for valid in valid_waypoints: distance=self.waypoints_data[target][valid] #print "target->valid=",target, valid, distance if distance<best_distance: best_distance=distance target_node=valid if target_node: self.nextWaypoint=self.waypoints[target_node] else: #print "no target", valid_waypoints self.nextWaypoint=self.findFirstWaypoint() #self.waypoints[random.choice(valid_waypoints)] #print self.nextWaypoint return task.again def runAI(self, task): #print self.state if self.state=="DIE": self.coll_sphere.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() self.actor.play("die") self.common["kills"]-=1 if self.common["kills"]==0: Interactive(self.common, data.items['key'], self.node.getPos(render)) elif random.randrange(10)==0: Interactive(self.common, data.items['potion'], self.node.getPos(render)) Sequence(Wait(2.0),LerpPosInterval(self.node, 2.0, VBase3(self.node.getX(),self.node.getY(),self.node.getZ()-5)),Func(self.destroy)).start() return task.done elif self.state=="STOP": target=self.nextWaypoint if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target)>0.3: self.node.setY(self.node, self.totalSpeed*globalClock.getDt()) if(self.actor.getCurrentAnim()!="walk"): self.actor.loop("walk") return task.again elif self.state=="ATTACK": self.node.headsUp(self.PC.node) if(self.actor.getCurrentAnim()!="attack"): self.actor.play("attack") #Sequence(Wait(self.attack_pattern[-1]+self.speed_mode), Func(self.attack, list(self.attack_pattern))).start() Sequence(Wait(self.attack_pattern[-1]), Func(self.attack, list(self.attack_pattern))).start() return task.again elif self.state=="SEEK": if self.PCisInRange: self.state="ATTACK" return task.again target=self.nextWaypoint if self.canSeePC and self.PC.HP>0: target=self.PC.node #print "target pc!" if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target)>0.3: self.node.setY(self.node, self.totalSpeed*globalClock.getDt()) if(self.actor.getCurrentAnim()!="walk"): self.actor.loop("walk") return task.again else: #print "I'm stuck?" #print target #print self.canSeePC self.nextWaypoint=self.PC.node return task.again def destroy(self): #for sound in self.soundset: # self.soundset[sound].stop() #print "destroy:", #self.sound_node.reparentTo(render) #self.common['soundPool'].append([self.sound_node,self.soundset]) self.common['soundPool'].set_free(self.soundID) #self.sounds=None #print " sounds", self.arrows=None if self.actor: self.actor.cleanup() self.actor.removeNode() #print " actor", if taskMgr.hasTaskNamed("AIfor"+str(self.id)): taskMgr.remove("AIfor"+str(self.id)) #print " AI", if taskMgr.hasTaskNamed('collFor'+str(self.id)): taskMgr.remove('collFor'+str(self.id)) #print " collision", if taskMgr.hasTaskNamed('DOTfor'+str(self.id)): taskMgr.remove('DOTfor'+str(self.id)) if self.node: self.node.removeNode() #print " node", self.monsterList[self.id]=None self.traverser=None self.queue=None
# C:::::C u::::u u::::u s::::::s t:::::t o::::o o::::om::::m m::::m m::::m M::::::M M:::::::M M::::::Mo::::o o::::o v:::::v v:::::v e:::::::::::::::::e m::::m m::::m m::::me:::::::::::::::::e n::::n n::::n t:::::t P::::P aa::::::::::::a t:::::t h:::::h h:::::h s::::::s # C:::::C u::::u u::::u s::::::s t:::::t o::::o o::::om::::m m::::m m::::m M::::::M M:::::M M::::::Mo::::o o::::o v:::::v:::::v e::::::eeeeeeeeeee m::::m m::::m m::::me::::::eeeeeeeeeee n::::n n::::n t:::::t P::::P a::::aaaa::::::a t:::::t h:::::h h:::::h s::::::s # C:::::C CCCCCCu:::::uuuu:::::u ssssss s:::::s t:::::t tttttto::::o o::::om::::m m::::m m::::m M::::::M MMMMM M::::::Mo::::o o::::o v:::::::::v e:::::::e m::::m m::::m m::::me:::::::e n::::n n::::n t:::::t tttttt P::::P a::::a a:::::a t:::::t tttttth:::::h h:::::hssssss s:::::s # C:::::CCCCCCCC::::Cu:::::::::::::::uus:::::ssss::::::s t::::::tttt:::::to:::::ooooo:::::om::::m m::::m m::::m M::::::M M::::::Mo:::::ooooo:::::o v:::::::v e::::::::e m::::m m::::m m::::me::::::::e n::::n n::::n t::::::tttt:::::t PP::::::PP a::::a a:::::a t::::::tttt:::::th:::::h h:::::hs:::::ssss::::::s # CC:::::::::::::::C u:::::::::::::::us::::::::::::::s tt::::::::::::::to:::::::::::::::om::::m m::::m m::::m M::::::M M::::::Mo:::::::::::::::o v:::::v e::::::::eeeeeeee m::::m m::::m m::::m e::::::::eeeeeeee n::::n n::::n tt::::::::::::::t P::::::::P a:::::aaaa::::::a tt::::::::::::::th:::::h h:::::hs::::::::::::::s # CCC::::::::::::C uu::::::::uu:::u s:::::::::::ss tt:::::::::::tt oo:::::::::::oo m::::m m::::m m::::m M::::::M M::::::M oo:::::::::::oo v:::v ee:::::::::::::e m::::m m::::m m::::m ee:::::::::::::e n::::n n::::n tt:::::::::::tt P::::::::P a::::::::::aa:::a tt:::::::::::tth:::::h h:::::h s:::::::::::ss # CCCCCCCCCCCCC uuuuuuuu uuuu sssssssssss ttttttttttt ooooooooooo mmmmmm mmmmmm mmmmmm MMMMMMMM MMMMMMMM ooooooooooo vvv eeeeeeeeeeeeee mmmmmm mmmmmm mmmmmm eeeeeeeeeeeeee nnnnnn nnnnnn ttttttttttt PPPPPPPPPP aaaaaaaaaa aaaa ttttttttttt hhhhhhh hhhhhhh sssssssssss # # # # # # # from direct.showbase.ShowBase import ShowBase from panda3d.core import * from direct.actor.Actor import Actor from direct.directutil import Mopath from direct.interval.MopathInterval import * showapp = ShowBase() actormodel = Actor("EggMod/PathMove.egg", {"PathMoving1": "EggMod/PathMove-Moving.egg"}) modelfollow = actormodel.exposeJoint(None, "modelRoot", "Bone") boxExample = loader.loadModel("box.egg") boxExample.reparentTo(modelfollow) actormodel.reparentTo(render) actormodel.play("PathMoving1") showapp.run()
class Player(FSM, DirectObject): NormalMode = "Normal" FightMode = "Fight" GAMEPADMODE = "Gamepad" MOUSEANDKEYBOARD = "MouseAndKeyboard" def __init__(self): FSM.__init__(self, "FSM-Player") random.seed() # # PLAYER CONTROLS AND CAMERA # self.player = Actor( "Character", { "Idle": "Character-Idle", "Run": "Character-Run", "Activate": "Character-Activate", "Death": "Character-Death", "Jump": "Character-Jump", "Hit": "Character-Hit", "Fight_Attack": "Character-FightAttack", "Fight_Idle": "Character-FightIdle", "Fight_Left": "Character-FightLeft", "Fight_Right": "Character-FightRight", }, ) self.player.setBlend(frameBlend=True) # the initial cam distance self.fightCamDistance = 3.0 # the next two vars will set the min and max distance the cam can have # to the node it is attached to self.maxCamDistance = 4.0 self.minCamDistance = 1.2 # the initial cam distance self.camDistance = (self.maxCamDistance - self.minCamDistance) / 2.0 + self.minCamDistance # the next two vars set the min and max distance on the Z-Axis to the # node the cam is attached to self.maxCamHeightDist = 3.0 self.minCamHeightDist = 1.5 # the average camera height self.camHeightAvg = (self.maxCamHeightDist - self.minCamHeightDist) / 2.0 + self.minCamHeightDist # an invisible object which will fly above the player and will be used to # track the camera on it self.camFloater = NodePath(PandaNode("playerCamFloater")) self.camFloater.setPos(0, 0, 1.5) self.camFloater.reparentTo(self.player) # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 # Interval for the jump animation self.jumpInterval = None self.jumpstartFloater = NodePath(PandaNode("jumpstartFloater")) self.jumpstartFloater.reparentTo(render) self.deathComplete = None # Joystick/Gamepad support self.hasJoystick = False if gamepadSupport: # initialize controls joysticks = [pygame.joystick.Joystick(x) for x in range(pygame.joystick.get_count())] if len(joysticks) > 0: self.mainJoystick = joysticks[0] self.mainJoystick.init() self.hasJoystick = True # # WEAPONS AND ACCESSORIES # self.RightHandAttach = self.player.exposeJoint(None, "modelRoot", "HandAttach_R") self.spear = loader.loadModel("Spear") self.spear.setP(90) self.spear.setR(180) self.spear.reparentTo(self.RightHandAttach) self.LeftHandAttach = self.player.exposeJoint(None, "modelRoot", "HandAttach_L") self.shield = loader.loadModel("Shield") self.shield.setZ(0.05) self.shield.setH(-90) self.shield.reparentTo(self.LeftHandAttach) # # PLAYER COLLISION DETECTION AND PHYSICS # self.playerSphere = CollisionSphere(0, 0, 0.8, 0.7) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision")) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # The foot collision checks self.footRay = CollisionRay(0, 0, 0, 0, 0, -1) self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision")) self.playerFootRay.node().addSolid(self.footRay) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) self.lifter.setMaxVelocity(5) base.cTrav.addCollider(self.playerFootRay, self.lifter) # a collision segment slightly in front of the player to check for jump ledges self.jumpCheckSegment = CollisionSegment(0, -0.2, 0.5, 0, -0.2, -2) self.playerJumpRay = self.player.attachNewNode(CollisionNode("playerJumpCollision")) self.playerJumpRay.node().addSolid(self.jumpCheckSegment) self.playerJumpRay.node().setIntoCollideMask(0) self.jumper = CollisionHandlerEvent() self.jumper.addOutPattern("%fn-out") base.cTrav.addCollider(self.playerJumpRay, self.jumper) # a collision segment to check attacks self.attackCheckSegment = CollisionSegment(0, 0, 1, 0, -1.3, 1) self.playerAttackRay = self.player.attachNewNode(CollisionNode("playerAttackCollision")) self.playerAttackRay.node().addSolid(self.attackCheckSegment) self.playerAttackRay.node().setIntoCollideMask(0) self.attackqueue = CollisionHandlerQueue() base.cTrav.addCollider(self.playerAttackRay, self.attackqueue) # # SOUNDEFFECTS # self.footstep = loader.loadSfx("Footstep.ogg") self.footstep.setLoop(True) self.footstep.setPlayRate(1.5) self.footstep.setVolume(0.5) self.spearAttackSfx = loader.loadSfx("SpearAttack.ogg") self.spearAttackSfx.setVolume(0.5) # # START/STOP # def start(self, startPoint): self.player.setPos(startPoint.getPos()) self.player.setHpr(startPoint.getHpr()) self.player.reparentTo(render) self.jumpstartFloater.setPos(self.player.getPos()) self.keyMap = {"horizontal": 0, "vertical": 0} self.health = 3 self.trackedEnemy = None # this mode will be used to determine in which move mode the player currently is self.mode = Player.NormalMode # the initial cam height self.camHeight = self.camHeightAvg # a time to keep the cam zoom at a specific speed independent of # current framerate self.camElapsed = 0.0 self.mouseSpeedX = 15.0 * base.mouseSensitivity self.mouseSpeedY = 0.2 * base.mouseSensitivity self.speed = 1.0 self.camCenterEvents = ["centerCam", "home", "q"] self.camZoomInEvents = ["zoomIn", "+", "wheel_up"] self.camZoomOutEvents = ["zoomOut", "-", "wheel_down"] self.actionEvents = ["doAction", "enter", "e"] self.accept("arrow_left", self.setKey, ["horizontal", 1]) self.accept("arrow_right", self.setKey, ["horizontal", -1]) self.accept("arrow_up", self.setKey, ["vertical", -1]) self.accept("arrow_down", self.setKey, ["vertical", 1]) self.accept("arrow_left-up", self.setKey, ["horizontal", 0]) self.accept("arrow_right-up", self.setKey, ["horizontal", 0]) self.accept("arrow_up-up", self.setKey, ["vertical", 0]) self.accept("arrow_down-up", self.setKey, ["vertical", 0]) self.accept("a", self.setKey, ["horizontal", 1]) self.accept("d", self.setKey, ["horizontal", -1]) self.accept("w", self.setKey, ["vertical", -1]) self.accept("s", self.setKey, ["vertical", 1]) self.accept("a-up", self.setKey, ["horizontal", 0]) self.accept("d-up", self.setKey, ["horizontal", 0]) self.accept("w-up", self.setKey, ["vertical", 0]) self.accept("s-up", self.setKey, ["vertical", 0]) for event in self.camCenterEvents: self.acceptOnce(event, self.center) for event in self.camZoomInEvents: self.acceptOnce(event, self.zoom, [True]) for event in self.camZoomOutEvents: self.acceptOnce(event, self.zoom, [False]) for event in self.actionEvents: self.acceptOnce(event, self.request, ["Action"]) self.accept("ActionDone", self.request, ["Idle"]) self.accept("playerJumpCollision-out", self.jump) taskMgr.add(self.move, "task_movement", priority=-10) taskMgr.add(self.updateCam, "task_camActualisation", priority=-4) if self.hasJoystick: taskMgr.add(self.gamepadLoop, "task_gamepad_loop", priority=-5) camera.setPos(self.player, 0, self.camDistance, self.camHeightAvg) self.hasJumped = False self.isActionmove = False self.request("Idle") def stop(self): taskMgr.remove("task_movement") taskMgr.remove("task_camActualisation") taskMgr.remove("task_gamepad_loop") self.ignoreAll() self.player.hide() def cleanup(self): self.stop() if self.deathComplete is not None: self.deathComplete.finish() if self.jumpInterval is not None: self.jumpInterval.finish() self.spear.removeNode() self.shield.removeNode() self.player.cleanup() self.player.removeNode() self.jumpstartFloater.removeNode() self.camFloater.removeNode() # # BASIC FUNCTIONS # def die(self): self.health -= 1 base.messenger.send("setHealth", [self.health]) self.request("Death") def heal(self): if self.health >= 3: return self.health += 1 base.messenger.send("setHealth", [self.health]) def hit(self): self.health -= 1 base.messenger.send("setHealth", [self.health]) if self.health == 0: self.request("Death") else: self.request("Hit") def resetPlayerPos(self): self.player.setPos(self.jumpstartFloater.getPos()) self.jumper.clear() self.request("Idle") def gameOver(self): base.messenger.send("GameOver", ["loose"]) def enterFightMode(self, trackedEnemy): self.trackedEnemy = trackedEnemy self.mode = Player.FightMode base.messenger.send("EnterFightMode") def exitFightMode(self): self.trackedEnemy = None self.mode = Player.NormalMode base.messenger.send("ExitFightMode") def gamepadLoop(self, task): joymap = {0: "doAction", 5: "centerCam", 6: "zoomIn", 4: "zoomOut", 9: "escape"} for event in pygame.event.get(): for button in range(self.mainJoystick.get_numbuttons()): if button in joymap and self.mainJoystick.get_button(button): base.messenger.send(joymap[button]) if event.type == pygame.JOYAXISMOTION: for axis in range(self.mainJoystick.get_numaxes()): axisChange = 0.0 axisChange = self.mainJoystick.get_axis(axis) if axis == 0: self.setKey("horizontal", -axisChange) if axis == 1: self.setKey("vertical", axisChange) return task.cont def setAnimationSpeed(self, requestedState): if requestedState == "Run": self.player.setPlayRate(3 * self.speed, "Run") elif requestedState == "RunReverse": self.player.setPlayRate(-3 * self.speed, "Run") elif requestedState == "FightLeft": self.player.setPlayRate(2 * self.speed, "Fight_Left") elif requestedState == "FightRight": self.player.setPlayRate(2 * self.speed, "Fight_Right") # # MOVE FUNCTIONS # def setKey(self, key, value): self.keyMap[key] = value def move(self, task): dt = globalClock.getDt() resetMouse = False def resetMouse(): if base.controlType == Player.MOUSEANDKEYBOARD: base.win.movePointer(0, self.winXhalf, self.winYhalf) if self.player.getAnimControl("Hit").isPlaying() or self.player.getAnimControl("Death").isPlaying(): resetMouse() return task.cont if self.deathComplete is not None: if self.deathComplete.isPlaying(): resetMouse() return task.cont if self.jumpInterval is not None: if self.jumpInterval.isPlaying(): resetMouse() return task.cont if self.isActionmove: resetMouse() return task.cont if self.mode == Player.NormalMode: self.__normalMove(dt) else: self.__fightMove(dt) return task.cont def __normalMove(self, dt): requestState = "Idle" move = False if self.keyMap["horizontal"] != 0: requestState = "Run" move = True if self.keyMap["vertical"] != 0: requestState = "Run" move = True if move and base.controlType == Player.GAMEPADMODE: movementVec = Vec3(self.keyMap["horizontal"], self.keyMap["vertical"], 0) self.speed = max(abs(self.keyMap["horizontal"]), abs(self.keyMap["vertical"])) angle = math.atan2(-movementVec.getX(), movementVec.getY()) rotation = angle * (180.0 / math.pi) self.player.setH(camera, rotation) self.player.setP(0) self.player.setR(0) self.player.setPos(self.player, (0, -2 * self.speed * dt, 0)) elif base.controlType == Player.MOUSEANDKEYBOARD: if not base.mouseWatcherNode.hasMouse(): return self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): z = camera.getZ() + (mouseY - self.winYhalf) * self.mouseSpeedY * dt camera.setZ(z) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX * dt if h < -360: h = 360 elif h > 360: h = -360 self.player.setH(h) if move: self.player.setPos( self.player, (2 * dt * self.keyMap["horizontal"], 2 * dt * self.keyMap["vertical"], 0) ) self.center() if self.state != requestState: self.request(requestState) self.setAnimationSpeed(requestState) def __fightMove(self, dt): if self.trackedEnemy == None: return requestState = "Idle" self.player.lookAt(self.trackedEnemy) self.player.setH(self.player, 180) if self.keyMap["horizontal"] > 0: self.player.setX(self.player, 2 * self.speed * dt) requestState = "FightLeft" elif self.keyMap["horizontal"] < 0: self.player.setX(self.player, -2 * self.speed * dt) requestState = "FightRight" elif self.keyMap["vertical"] < 0: self.player.setY(self.player, -2 * self.speed * dt) requestState = "Run" elif self.keyMap["vertical"] > 0: self.player.setY(self.player, 2 * self.speed * dt) requestState = "RunReverse" if self.state != requestState: self.request(requestState) self.setAnimationSpeed(requestState) def jump(self, extraArg): intoName = extraArg.getIntoNode().getName().lower() if not "floor" in intoName and not "plate" in intoName: return # setup the projectile interval startPos = self.player.getPos() self.jumpstartFloater.setPos(self.player, 0, 0.5, 0) tempFloater = NodePath(PandaNode("tempJumpFloater")) tempFloater.setPos(self.player, 0, -3.2, 0.1) endPos = tempFloater.getPos() tempFloater.removeNode() self.jumpInterval = ProjectileInterval( self.player, startPos=startPos, endPos=endPos, duration=1.5, gravityMult=0.25 ) self.request("Jump") self.jumpInterval.start() # # CAMERA FUNCTIONS # def updateCam(self, task): if self.mode == Player.NormalMode: self.__normalCam() else: self.__fightCam() return task.cont def zoom(self, zoomIn): # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() zoom = 0 if zoomIn: if camdist > self.minCamDistance + 0.5: zoom = 0.5 for event in self.camZoomInEvents: self.acceptOnce(event, self.zoom, [True]) else: if camdist < self.maxCamDistance - 0.5: zoom = -0.5 for event in self.camZoomOutEvents: self.acceptOnce(event, self.zoom, [False]) camera.setPos(camera, 0, zoom, 0) def center(self): # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() # get the cameras current offset to the player model on the z-axis offsetZ = camera.getZ() - self.player.getZ() camera.setPos(self.player, 0, camdist, offsetZ) for event in self.camCenterEvents: self.acceptOnce(event, self.center) def __normalCam(self): """This function will check the min and max distance of the camera to the defined model and will correct the position if the cam is to close or to far away""" # Camera Movement Updates camvec = self.player.getPos() - camera.getPos() camvec.setZ(0) camdist = camvec.length() camvec.normalize() # If far from player start following if camdist > self.maxCamDistance: camera.setPos(camera.getPos() + camvec * (camdist - self.maxCamDistance)) camdist = self.maxCamDistance # If player to close move cam backwards if camdist < self.minCamDistance: camera.setPos(camera.getPos() - camvec * (self.minCamDistance - camdist)) camdist = self.minCamDistance # get the cameras current offset to the player model on the z-axis offsetZ = camera.getZ() - self.player.getZ() # check if the camera is within the min and max z-axis offset if offsetZ < self.minCamHeightDist: camera.setZ(self.player.getZ() + self.minCamHeightDist) offsetZ = self.minCamHeightDist elif offsetZ > self.maxCamHeightDist: camera.setZ(self.player.getZ() + self.maxCamHeightDist) offsetZ = self.maxCamHeightDist if offsetZ != self.camHeightAvg and not base.controlType == Player.MOUSEANDKEYBOARD: # if we are not moving up or down, set the cam to an average position if offsetZ != self.camHeightAvg: if offsetZ > self.camHeightAvg: # the cam is higher then the average cam height above the player # so move it slowly down camera.setZ(camera.getZ() - 5 * globalClock.getDt()) newOffsetZ = camera.getZ() - self.player.getZ() # check if the cam has reached the desired offset if newOffsetZ < self.camHeightAvg: # set the cam z position to exactly the desired offset camera.setZ(self.player.getZ() + self.camHeightAvg) else: # the cam is lower then the average cam height above the player # so move it slowly up camera.setZ(camera.getZ() + 5 * globalClock.getDt()) newOffsetZ = camera.getZ() - self.player.getZ() # check if the cam has reached the desired offset if newOffsetZ > self.camHeightAvg: # set the cam z position to exactly the desired offset camera.setZ(self.player.getZ() + self.camHeightAvg) camera.lookAt(self.camFloater) def __fightCam(self): """This function will check the min and max distance of the camera to the defined model and will correct the position if the cam is to close or to far away""" camera.setX(self.player, 0) camera.setY(self.player, self.fightCamDistance) camera.setZ(0.5) camera.lookAt(self.camFloater) # # FSM FUNCTIONS # def enterIdle(self): if self.mode == Player.NormalMode: self.player.loop("Idle") self.footstep.stop() elif self.mode == Player.FightMode: self.player.loop("Fight_Idle") self.footstep.stop() def enterRun(self): self.player.loop("Run") self.footstep.play() def enterRunReverse(self): self.player.loop("Run") self.footstep.play() def enterAction(self): if self.player.getAnimControl("Hit").isPlaying() or self.player.getAnimControl("Death").isPlaying(): self.__exitAction() return self.isActionmove = True if self.mode == Player.NormalMode: self.__enterActivate() elif self.mode == Player.FightMode: self.__enterFightAttack() self.accept("ActionDone", self.__exitAction) def __exitAction(self): self.isActionmove = False for event in self.actionEvents: self.acceptOnce(event, self.request, ["Action"]) def __enterActivate(self): activateAnim = self.player.actorInterval("Activate", playRate=3) activateAnim.setDoneEvent("ActionDone") activateAnim.start() base.messenger.send("Player_Activate") self.footstep.stop() def enterDeath(self): self.footstep.stop() deathAnim = self.player.actorInterval("Death") deathComplete = None if self.health == 0: self.deathComplete = Sequence(deathAnim, Wait(2), Func(self.gameOver)) else: self.deathComplete = Sequence(deathAnim, Wait(2), Func(self.resetPlayerPos)) self.deathComplete.start() def enterJump(self): self.player.play("Jump") self.footstep.stop() def enterHit(self): self.player.setPlayRate(4, "Hit") self.player.play("Hit") self.footstep.stop() def __enterFightAttack(self): attackAnim = self.player.actorInterval("Fight_Attack", playRate=3) attackAnim.setDoneEvent("ActionDone") attackAnim.start() self.spearAttackSfx.play() for i in range(self.attackqueue.getNumEntries()): entry = self.attackqueue.getEntry(i) into = entry.getIntoNode() if "golemHitField" in into.getName(): if random.random() > 0.15: base.messenger.send("HitEnemy") self.footstep.stop() def enterFightLeft(self): self.player.loop("Fight_Left") self.footstep.play() def enterFightRight(self): self.player.loop("Fight_Right") self.footstep.play()
class PlayerBase(DirectObject): def __init__(self): # Player Model setup self.player = Actor("Player", {"Run":"Player-Run", "Sidestep":"Player-Sidestep", "Idle":"Player-Idle"}) self.player.setBlend(frameBlend = True) self.player.setPos(0, 0, 0) self.player.pose("Idle", 0) self.player.reparentTo(render) self.player.hide() self.footstep = base.audio3d.loadSfx('footstep.ogg') self.footstep.setLoop(True) base.audio3d.attachSoundToObject(self.footstep, self.player) # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) CamMask = BitMask32.bit(0) AvBufMask = BitMask32.bit(1) self.avbuf = None if base.win: self.avbufTex = Texture('avbuf') self.avbuf = base.win.makeTextureBuffer('avbuf', 256, 256, self.avbufTex, True) cam = Camera('avbuf') cam.setLens(base.camNode.getLens()) self.avbufCam = base.cam.attachNewNode(cam) dr = self.avbuf.makeDisplayRegion() dr.setCamera(self.avbufCam) self.avbuf.setActive(False) self.avbuf.setClearColor((1, 0, 0, 1)) cam.setCameraMask(AvBufMask) base.camNode.setCameraMask(CamMask) # avbuf renders everything it sees with the gradient texture. tex = loader.loadTexture('gradient.png') np = NodePath('np') np.setTexture(tex, 100) np.setColor((1, 1, 1, 1), 100) np.setColorScaleOff(100) np.setTransparency(TransparencyAttrib.MNone, 100) np.setLightOff(100) cam.setInitialState(np.getState()) #render.hide(AvBufMask) # Setup a texture stage to paint on the player self.paintTs = TextureStage('paintTs') self.paintTs.setMode(TextureStage.MDecal) self.paintTs.setSort(10) self.paintTs.setPriority(10) self.tex = Texture('paint_av_%s'%id(self)) # Setup a PNMImage that will hold the paintable texture of the player self.imageSizeX = 64 self.imageSizeY = 64 self.p = PNMImage(self.imageSizeX, self.imageSizeY, 4) self.p.fill(1) self.p.alphaFill(0) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) # Apply the paintable texture to the avatar self.player.setTexture(self.paintTs, self.tex) # team self.playerTeam = "" # A lable that will display the players team self.lblTeam = DirectLabel( scale = 1, pos = (0, 0, 3), frameColor = (0, 0, 0, 0), text = "TEAM", text_align = TextNode.ACenter, text_fg = (0,0,0,1)) self.lblTeam.reparentTo(self.player) self.lblTeam.setBillboardPointEye() # basic player values self.maxHits = 3 self.currentHits = 0 self.isOut = False self.TorsorControl = self.player.controlJoint(None,"modelRoot","Torsor") # setup the collision detection # wall and object collision self.playerSphere = CollisionSphere(0, 0, 1, 1) self.playerCollision = self.player.attachNewNode(CollisionNode("playerCollision%d"%id(self))) self.playerCollision.node().addSolid(self.playerSphere) base.pusher.addCollider(self.playerCollision, self.player) base.cTrav.addCollider(self.playerCollision, base.pusher) # foot (walk) collision self.playerFootRay = self.player.attachNewNode(CollisionNode("playerFootCollision%d"%id(self))) self.playerFootRay.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -1)) self.playerFootRay.node().setIntoCollideMask(0) self.lifter = CollisionHandlerFloor() self.lifter.addCollider(self.playerFootRay, self.player) base.cTrav.addCollider(self.playerFootRay, self.lifter) # Player weapon setup self.gunAttach = self.player.exposeJoint(None, "modelRoot", "WeaponSlot_R") self.color = LPoint3f(1, 1, 1) self.gun = Gun(id(self)) self.gun.reparentTo(self.gunAttach) self.gun.hide() self.gun.setColor(self.color) self.hud = None # Player controls setup self.keyMap = {"left":0, "right":0, "forward":0, "backward":0} # screen sizes self.winXhalf = base.win.getXSize() / 2 self.winYhalf = base.win.getYSize() / 2 self.mouseSpeedX = 0.1 self.mouseSpeedY = 0.1 # AI controllable variables self.AIP = 0.0 self.AIH = 0.0 self.movespeed = 5.0 self.userControlled = False self.accept("Bulet-hit-playerCollision%d" % id(self), self.hit) self.accept("window-event", self.recalcAspectRatio) def runBase(self): self.player.show() self.gun.show() taskMgr.add(self.move, "moveTask%d"%id(self), priority=-4) def stopBase(self): taskMgr.remove("moveTask%d"%id(self)) self.ignoreAll() self.gun.remove() self.footstep.stop() base.audio3d.detachSound(self.footstep) self.player.delete() def setKey(self, key, value): self.keyMap[key] = value def setPos(self, pos): self.player.setPos(pos) def setColor(self, color=LPoint3f(0,0,0)): self.color = color self.gun.setColor(color) c = (color[0], color[1], color[2], 1.0) self.lblTeam["text_fg"] = c def setTeam(self, team): self.playerTeam = team self.lblTeam["text"] = team def shoot(self, shotVec=None): self.gun.shoot(shotVec) if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def reload(self): self.gun.reload() if self.hud != None: self.hud.updateAmmo(self.gun.maxAmmunition, self.gun.ammunition) def recalcAspectRatio(self, window): self.winXhalf = window.getXSize() / 2 self.winYhalf = window.getYSize() / 2 def hit(self, entry, color): self.currentHits += 1 # Create a brush to paint on the texture splat = PNMImage("../data/Splat.png") splat = splat * LColorf(color[0], color[1], color[2], 1.0) self.colorBrush = PNMBrush.makeImage(splat, 6, 6, 1) self.paintAvatar(entry) if self.currentHits >= self.maxHits: base.messenger.send("GameOver-player%d" % id(self)) self.isOut = True def __paint(self, s, t): """ Paints a point on the avatar at texture coordinates (s, t). """ x = (s * self.p.getXSize()) y = ((1.0 - t) * self.p.getYSize()) # Draw in color directly on the avatar p1 = PNMPainter(self.p) p1.setPen(self.colorBrush) p1.drawPoint(x, y) self.tex.load(self.p) self.tex.setWrapU(self.tex.WMClamp) self.tex.setWrapV(self.tex.WMClamp) self.paintDirty = True def paintAvatar(self, entry): """ Paints onto an avatar. Returns true on success, false on failure (because there are no avatar pixels under the mouse, for instance). """ # First, we have to render the avatar in its false-color # image, to determine which part of its texture is under the # mouse. if not self.avbuf: return False #mpos = base.mouseWatcherNode.getMouse() mpos = entry.getSurfacePoint(self.player) ppos = entry.getSurfacePoint(render) self.player.showThrough(BitMask32.bit(1)) self.avbuf.setActive(True) base.graphicsEngine.renderFrame() self.player.show(BitMask32.bit(1)) self.avbuf.setActive(False) # Now we have the rendered image in self.avbufTex. if not self.avbufTex.hasRamImage(): print "Weird, no image in avbufTex." return False p = PNMImage() self.avbufTex.store(p) ix = int((1 + mpos.getX()) * p.getXSize() * 0.5) iy = int((1 - mpos.getY()) * p.getYSize() * 0.5) x = 1 if ix >= 0 and ix < p.getXSize() and iy >= 0 and iy < p.getYSize(): s = p.getBlue(ix, iy) t = p.getGreen(ix, iy) x = p.getRed(ix, iy) if x > 0.5: # Off the avatar. return False # At point (s, t) on the avatar's map. self.__paint(s, t) return True def move(self, task): if self is None: return task.done if self.userControlled: if not base.mouseWatcherNode.hasMouse(): return task.cont self.pointer = base.win.getPointer(0) mouseX = self.pointer.getX() mouseY = self.pointer.getY() if base.win.movePointer(0, self.winXhalf, self.winYhalf): p = self.TorsorControl.getP() + (mouseY - self.winYhalf) * self.mouseSpeedY if p <-80: p = -80 elif p > 90: p = 90 self.TorsorControl.setP(p) h = self.player.getH() - (mouseX - self.winXhalf) * self.mouseSpeedX if h <-360: h = 360 elif h > 360: h = -360 self.player.setH(h) else: self.TorsorControl.setP(self.AIP) self.player.setH(self.AIH) forward = self.keyMap["forward"] != 0 backward = self.keyMap["backward"] != 0 if self.keyMap["left"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, self.movespeed * globalClock.getDt()) elif self.keyMap["right"] != 0: if self.player.getCurrentAnim() != "Sidestep" and not (forward or backward): self.player.loop("Sidestep") self.player.setPlayRate(5, "Sidestep") self.player.setX(self.player, -self.movespeed * globalClock.getDt()) else: self.player.stop("Sidestep") if forward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(5, "Run") self.player.setY(self.player, -self.movespeed * globalClock.getDt()) elif backward: if self.player.getCurrentAnim() != "Run": self.player.loop("Run") self.player.setPlayRate(-5, "Run") self.player.setY(self.player, self.movespeed * globalClock.getDt()) else: self.player.stop("Run") if not (self.keyMap["left"] or self.keyMap["right"] or self.keyMap["forward"] or self.keyMap["backward"] or self.player.getCurrentAnim() == "Idle"): self.player.loop("Idle") self.footstep.stop() else: self.footstep.play() return task.cont
class Me(DirectObject): def __init__(self, terrainClass): self.model = Actor("models/ninja", {"walk":"models/ninja"}) self.actorHead = self.model.exposeJoint(None, 'modelRoot','Joint8') #self.model.setScale(4) self.playernum = None self.timeSinceLastUpdate = 0 self.model.reparentTo(render) self.model.setScale(0.5) self.isMoving = False self.AnimControl=self.model.getAnimControl('walk') self.AnimControl.setPlayRate(0.05) self.model.setBlend(frameBlend=1) self.model.setPos(244,188,0) #STORE TERRAIN SCALE FOR LATER USE# self.terrainScale = terrainClass.terrain.getRoot().getSz() def setPlayerNum(self,int): self.playernum = int def move(self, keyClass, terrainClass): self.meTerrainHeight = terrainClass.terrain.getElevation(self.model.getX(),self.model.getY()) * self.terrainScale self.camTerrainHeight = terrainClass.terrain.getElevation(camera.getX(),camera.getY()) * self.terrainScale self.elapsed = globalClock.getDt() base.camera.lookAt(self.actorHead) if (keyClass.keyMap["left"]!=0): self.model.setH(self.model.getH() + self.elapsed*300) print str(self.model.getY()), str(self.model.getX()) if (keyClass.keyMap["right"]!=0): self.model.setH(self.model.getH() - self.elapsed*300) if (keyClass.keyMap["forward"]!=0): self.model.setY(self.model, (self.elapsed*40)) if (keyClass.keyMap["back"]!=0): self.model.setY(self.model, -(self.elapsed*40)) if (keyClass.keyMap["forward"]!=0) or (keyClass.keyMap["left"]!=0) or (keyClass.keyMap["right"]!=0): if self.isMoving is False: self.model.loop("walk", fromFrame = 1, toFrame = 11) self.isMoving = True else: if self.isMoving: self.model.stop() self.model.pose("walk",5) self.isMoving = False self.model.setZ(self.meTerrainHeight) #CAMERA CONTROL# self.camvec = self.model.getPos() - base.camera.getPos() if (self.camTerrainHeight > self.meTerrainHeight): camera.setZ(self.camTerrainHeight + 5) else: camera.setZ(self.meTerrainHeight + 5) self.camvec.setZ(0) self.camdist = self.camvec.length() self.camvec.normalize() if (self.camdist > 20): base.camera.setPos(base.camera.getPos() + self.camvec*(self.camdist-20)) self.camdist = 20.0 if (self.camdist < 10): base.camera.setPos(base.camera.getPos() - self.camvec*(10-self.camdist)) self.camdist = 10.0 return Task.cont
class Enemy(Creature): def __init__(self, mainReference, name, position, regionID): super(Enemy, self).__init__(mainReference) # unique enemy name self.name = name # If enemy is alive self.alive = True # enemy's pursue speed P-units/s self.speed = 2.9 # enemy's rotation speed angles/s self.rotSpeed = 10 # enemy's current convex region; for pursue purposes self.currentRegionID = regionID # Hit Points of each part of zombie self.hitPoints = {'leg_lr':2, 'leg_ll':2, 'arm_lr':2, 'arm_ll':2} self.lifePoints = 100 # enemy NodePath self.enemyNP = self.mainRef.render.attachNewNode(self.name) self.enemyNP.setPos(position) # the name of the task the zombie is currently performing self.enemyActiveState = "" self.isEnemyAttacking = False # the cross point of the portal that the zombie is trying to cross self.currentCrossPointGoal = None # the time that the enemy will spend confused self.lostTargetTotalTime = 1.0 self.lostTargetTimer = self.lostTargetTotalTime # load our zombie self.enemyModel = Actor("../../models/model_zombie/zombie",{ 'walk':'../../models/model_zombie/zombie-walk', 'attack':'../../models/model_zombie/zombie-attack', }) # ****SCALE**** self.enemyModel.setScale(0.55) # ****SCALE**** #enemy's character controller self.enemyBody = CharacterBody(self.mainRef, self.enemyNP.getPos(), 0.38, 0.5 ) self.enemyBody.charBodyNP.reparentTo(self.enemyNP) # load the zombie's bounding boxes self.enemyBB = loader.loadModel("../../models/model_zombie/zombieBB") global bodyParts bodyParts = ['head', 'leg_ur', 'leg_ul', 'leg_lr', 'leg_ll', 'torso', 'arm_ur', 'arm_ul', 'arm_lr', 'arm_ll'] # List of the bullet nodes for this enemy, to be removed later self.bulletNodes = {} self.partNodes = {} # Get Joints self.joints = {} #for bodyPart in ['leg_lr', 'leg_ll', 'arm_lr', 'arm_ll']: # # Get joint control structure # self.joints[bodyPart] = self.enemyModel.controlJoint(None, 'modelRoot', bodyPart) # getting 1 by 1 and attaching them to their corresponding bones for bodyPart in bodyParts: self.bodyPartShape = BulletConvexHullShape() self.bodyPartShape.addGeom(self.enemyBB.getChild(0).find(bodyPart).node().getGeom(0)) self.bulletbodyPartNode = BulletRigidBodyNode(bodyPart+"_"+name) self.bulletbodyPartNode.addShape(self.bodyPartShape) self.bodyPartNode = self.mainRef.render.attachNewNode(self.bulletbodyPartNode) # ****SCALE**** self.bodyPartNode.setScale(0.55) # ****SCALE**** self.mainRef.world.attachRigidBody(self.bulletbodyPartNode) self.bodyPartNode.setCollideMask( BitMask32.bit( 2 ) ) self.bodyPartNode.wrtReparentTo(self.enemyModel.exposeJoint(None,"modelRoot",bodyPart)) self.bulletNodes[bodyPart] = self.bulletbodyPartNode self.partNodes[bodyPart] = self.bodyPartNode # uncomment to use triangleMesh instead of convexHull # mesh = BulletTriangleMesh() # mesh.addGeom(self.enemyBB.getChild(0).find(bodyPart).node().getGeom(0)) # self.bodyPartShape = BulletTriangleMeshShape(mesh, dynamic=True) # # self.bulletbodyPartNode = BulletRigidBodyNode(bodyPart) # self.bulletbodyPartNode.addShape(self.bodyPartShape) # # self.bodyPartNode = self.mainRef.render.attachNewNode(self.bulletbodyPartNode) # self.mainRef.world.attachRigidBody(self.bulletbodyPartNode) # # self.bodyPartNode.wrtReparentTo(self.enemyModel.exposeJoint(None,"modelRoot",bodyPart)) # initial path must be calculated self.updatePath() # adding a task to check if the enemy is leaving their region self.checkIfChangedRegionName = self.name + "cicr" self.oldPosition = self.enemyNP.getPos() taskMgr.add(self.checkIfChangedRegion, self.checkIfChangedRegionName) # walk loop # self.enemyModel.loop("walk") self.enemyModel.loop("walk") # attaching to render self.enemyModel.reparentTo(self.enemyNP) self.enemyModel.setPos(0,0,-0.51) # loading enemy roar sound zombieRoar = [None,None,None,None] for i in range( len(zombieRoar) ): zombieRoar[i] = self.mainRef.audio3d.loadSfx('../../sounds/zombie_roar_' + str(i+1) + '.mp3') # initialize first zombie roar self.zombieRoarFX = zombieRoar[0] self.mainRef.audio3d.attachSoundToObject(self.zombieRoarFX, self.enemyNP) self.zombieRoarFX.play() # random zombie roar def roarSort(task): if(self.zombieRoarFX.status() != self.zombieRoarFX.PLAYING): random.seed() value = random.choice(range(3)) self.zombieRoarFX = zombieRoar[value] self.mainRef.audio3d.attachSoundToObject(self.zombieRoarFX, self.enemyNP) self.zombieRoarFX.play() return task.again self.mainRef.taskMgr.doMethodLater(2, roarSort,self.name+'roar sort') def hide(self): self.enemyModel.hide() def show(self): self.mainRef.world.attachRigidBody(self.enemyBulletNode) self.enemyModel.show() self.enemyModel.loop("walk") def setNewCourse(self): # Simply follow the player if (len(self.portalsPathList) == 0): taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "pt" taskMgr.add(self.pursueTargetStep, self.enemyActiveState) # Go to the cross point that makes you closer to your target elif (self.portalsPathList[0].connectedRegionsIDs[0] == self.mainRef.player.currentRegionID or self.portalsPathList[0].connectedRegionsIDs[1] == self.mainRef.player.currentRegionID): self.setOptimalCrossPoint() taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "htp" taskMgr.add(self.headToPortalStep, self.enemyActiveState) # Go to the middle cross point else: self.currentCrossPointGoal = self.portalsPathList[0].middleCrossPoint taskMgr.remove( self.enemyActiveState ) self.enemyActiveState = self.name + "htp" taskMgr.add(self.headToPortalStep, self.enemyActiveState) # ======================================================================== # ======================== STATE MACHINE METHODS ========================== def pursueTargetStep(self, task): if (self.mainRef.player.currentRegionID == self.currentRegionID): if ( self.mainRef.player.playerNP.getPos(self.enemyNP).length() < 4.0): if (not self.isEnemyAttacking): self.speed += 1.0 self.isEnemyAttacking = True self.enemyModel.loop("attack") elif (self.isEnemyAttacking): self.speed -= 1.0 self.isEnemyAttacking = False self.enemyModel.loop("walk") targetDirection = Vec2( self.mainRef.player.playerNP.getPos(self.enemyNP).getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) targetDirection.normalize() playerMoveSpeedVec = targetDirection * self.speed * globalClock.getDt() self.enemyNP.setPos( self.enemyBody.move(Vec3(playerMoveSpeedVec.getX(), playerMoveSpeedVec.getY(), 0) ) ) if (abs(rotationAngle) > 120 * globalClock.getDt()): self.lostTargetTimer = self.lostTargetTotalTime self.enemyActiveState = self.name + "lt" taskMgr.add(self.lostTargetStep, self.enemyActiveState) return task.done return task.cont def lostTargetStep(self, task): self.enemyNP.setPos( self.enemyBody.move(Vec3(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())), 0) * self.speed * globalClock.getDt() ) ) self.lostTargetTimer -= globalClock.getDt() if (self.lostTargetTimer < 0): self.enemyActiveState = self.name + "rt" taskMgr.add(self.recoverTargetStep, self.enemyActiveState) return task.done return task.cont def recoverTargetStep(self, task): targetDirection = Vec2( self.mainRef.player.playerNP.getPos(self.enemyNP).getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) if (abs(targetDirectionAngle) < 5): self.enemyActiveState = self.name + "pt" taskMgr.add(self.pursueTargetStep, self.enemyActiveState) return task.done return task.cont def headToPortalStep(self, task): directionVec = Vec3(self.currentCrossPointGoal.getX() - self.enemyNP.getX(), self.currentCrossPointGoal.getY() - self.enemyNP.getY(), 0) directionVec.normalize() targetDirection = Vec2( self.currentCrossPointGoal - self.enemyNP.getPos().getXy() ) targetDirectionAngle = Vec2(-sin(radians(self.enemyModel.getH())), cos(radians(self.enemyModel.getH())) ).signedAngleDeg(targetDirection) rotationAngle = targetDirectionAngle * self.rotSpeed * globalClock.getDt() self.enemyModel.setH(self.enemyModel.getH() + rotationAngle) self.enemyNP.setPos( self.enemyBody.move( directionVec * self.speed * globalClock.getDt() ) ) return task.cont # ====================== END OF STATE MACHINE METHODS ======================== # ============================================================================ def destroy(self): self.alive = False taskMgr.remove(self.name+'roar sort') # removing sound for node in self.bulletNodes.keys(): self.mainRef.world.removeRigidBody(self.bulletNodes[node]) self.partNodes[node].removeNode() taskMgr.remove( self.enemyActiveState ) # removing state machine task self.enemyModel.cleanup() self.enemyBB.removeNode() self.enemyBody.destroy() def detachLimb(self,limb): # Detaches a limb from the enemy and makes it drop on the floor print "[Detach] Detach %s" % limb # self.partNodes[limb].wrtReparentTo(self.mainRef.render) # # shape = BulletSphereShape(10.0) # node = BulletRigidBodyNode('Sphere') # node.setMass(1.0) # node.addShape(shape) # playerNP = self.mainRef.render.attachNewNode(node) # playerNP.setPos(self.enemyModel.exposeJoint(None,"modelRoot",limb).getPos()) # playerNP.setPos(playerNP.getRelativePoint(self.partNodes[limb],self.partNodes[limb].getPos())) # playerNP.setPos(60,0,-60) # print playerNP.getRelativePoint(self.partNodes[limb],self.partNodes[limb].getPos()) # print self.partNodes[limb].getPos() # self.mainRef.world.attachRigidBody(node) # # self.bulletNodes[limb].applyCentralForce(Vec3(0, 0, -5)) # self.mainRef.world.removeRigidBody(self.bulletNodes[limb]) def updatePath(self): convexRegionsList = self.mainRef.map.convexRegions self.portalsPathList = [] # this is what we want for enemy's correct pursue path discoveredRegionsList = [] # part of the BFS algorithm visitedRegionsList = [False for item in range( len(convexRegionsList))] regionFatherList = [None for item in range( len(convexRegionsList))] # this list keeps track of a region's father AND the portalEntrance connecting them # from now, we'll execute a BFS to find each region that enemy will cross to reach player's position discoveredRegionsList.append( convexRegionsList[self.currentRegionID] ) visitedRegionsList[self.currentRegionID] = True regionFatherList[self.currentRegionID] = [-1, None] while(discoveredRegionsList): analisedRegion = discoveredRegionsList.pop(0) for portalEntrance in analisedRegion.portalEntrancesList: neighbourRegionID = portalEntrance.connectedRegionID if (not visitedRegionsList[neighbourRegionID]): regionFatherList[neighbourRegionID] = [analisedRegion.regionID, portalEntrance.portal] if (neighbourRegionID == self.mainRef.player.currentRegionID): discoveredRegionsList = [] # break while statement trick break visitedRegionsList[neighbourRegionID] = True discoveredRegionsList.append( convexRegionsList[neighbourRegionID] ) # now that we have all regions necessary , we'll just put all portals on the correct order lastRegionFatherID = self.mainRef.player.currentRegionID while (lastRegionFatherID != -1): lastRegionFather = regionFatherList[lastRegionFatherID] lastRegionFatherID = lastRegionFather[0] self.portalsPathList.append(lastRegionFather[1]) # putting portals path on the right order for enemy pursuing algorithm self.portalsPathList.pop() self.portalsPathList.reverse() # Debug # print "lista de portais:" # for portal in self.portalsPathList: # print portal.connectedRegionsIDs self.setNewCourse() def checkIfChangedRegion(self, task, lastRegion=0): for portalEntrance in self.mainRef.map.convexRegions[self.currentRegionID].portalEntrancesList: if ( self.intersect( self.oldPosition, self.enemyNP.getPos(), portalEntrance.portal.frontiers[0], portalEntrance.portal.frontiers[1] ) and portalEntrance.portal.connectedRegionsIDs[0] != lastRegion and portalEntrance.portal.connectedRegionsIDs[1] != lastRegion ): oldRegion = self.mainRef.player.currentRegionID self.currentRegionID = portalEntrance.connectedRegionID # Debug # print self.name + " region changed: ", oldRegion, ">", self.currentRegionID # erase last item of portalsPathList (if it isn't empty) if (len(self.portalsPathList) != 0): self.portalsPathList.pop(0) # new course must be calculated if the enemy changed it's region self.setNewCourse() self.oldPosition = self.enemyNP.getPos() return task.cont def ccw(self, A,B,C): return (C.getY()-A.getY())*(B.getX()-A.getX()) > (B.getY()-A.getY())*(C.getX()-A.getX()) def intersect(self, A,B,C,D): return self.ccw(A,C,D) != self.ccw(B,C,D) and self.ccw(A,B,C) != self.ccw(A,B,D) def setOptimalCrossPoint(self): deltaPositionVec = self.mainRef.player.playerNP.getPos() - self.enemyNP.getPos() positionPoint = self.enemyNP.getPos() deltaFrontiersVec = self.portalsPathList[0].frontiersVec frontierPoint = self.portalsPathList[0].frontiers[0] if (deltaPositionVec.getX() == 0): tang2 = deltaFrontiersVec.getY() / deltaFrontiersVec.getX() b2 = frontierPoint.getY() - tang2 * frontierPoint.getX() xRes = positionPoint.getX() yRes = tang2 * xRes + b2 if (deltaFrontiersVec.getX() == 0): tang1 = deltaPositionVec.getY() / deltaPositionVec.getX() b1 = positionPoint.getY() - tang1 * positionPoint.getX() xRes = frontierPoint.getX() yRes = tang1 * xRes + b1 else: tang1 = deltaPositionVec.getY() / deltaPositionVec.getX() tang2 = deltaFrontiersVec.getY() / deltaFrontiersVec.getX() b1 = positionPoint.getY() - tang1 * positionPoint.getX() b2 = frontierPoint.getY() - tang2 * frontierPoint.getX() xRes = (b1 - b2) / (tang1 - tang2) yRes = tang1 * xRes + b1 if (deltaFrontiersVec.getX() == 0): if ( ( yRes > self.portalsPathList[0].crossPoints[0].getY() and yRes < self.portalsPathList[0].crossPoints[1].getY() ) or ( yRes < self.portalsPathList[0].crossPoints[0].getY() and yRes > self.portalsPathList[0].crossPoints[1].getY() ) ) : self.currentCrossPointGoal = Vec2(xRes, yRes) elif (yRes > self.portalsPathList[0].crossPoints[0].getY() and yRes > self.portalsPathList[0].crossPoints[1].getY() ): if ( self.portalsPathList[0].crossPoints[0].getY() > self.portalsPathList[0].crossPoints[1].getY()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( self.portalsPathList[0].crossPoints[0].getY() < self.portalsPathList[0].crossPoints[1].getY()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( ( xRes > self.portalsPathList[0].crossPoints[0].getX() and xRes < self.portalsPathList[0].crossPoints[1].getX() ) or ( xRes < self.portalsPathList[0].crossPoints[0].getX() and xRes > self.portalsPathList[0].crossPoints[1].getX() ) ) : self.currentCrossPointGoal = Vec2(xRes, yRes) elif (xRes > self.portalsPathList[0].crossPoints[0].getX() and xRes > self.portalsPathList[0].crossPoints[1].getX()): if ( self.portalsPathList[0].crossPoints[0].getX() > self.portalsPathList[0].crossPoints[1].getX()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1] else: if ( self.portalsPathList[0].crossPoints[0].getX() < self.portalsPathList[0].crossPoints[1].getX()): self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[0] else: self.currentCrossPointGoal = self.portalsPathList[0].crossPoints[1]
class Monster(): def __init__(self, setup_data, common, start_pos=(0, 0, 0)): level = common[ 'max_level'] + 1 # max_level is the current level starting from 0 common['monsterList'].append(self) id = len(common['monsterList']) - 1 self.monsterList = common['monsterList'] self.waypoints_data = common['waypoints_data'] self.waypoints = common['waypoints'] self.audio3d = common['audio3d'] self.common = common #root node self.node = render.attachNewNode("monster") self.sound_node = None self.soundset = None self.actor = Actor(setup_data["model"], setup_data["anim"]) self.actor.setBlend(frameBlend=True) self.actor.reparentTo(self.node) self.actor.setScale(setup_data["scale"] * random.uniform(0.9, 1.1)) self.actor.setH(setup_data["heading"]) self.actor.setBin("opaque", 10) self.rootBone = self.actor.exposeJoint(None, 'modelRoot', setup_data["root_bone"]) #sounds self.soundID = self.common['soundPool'].get_id() self.common['soundPool'].set_target(self.soundID, self.node) self.sound_names = { "hit": setup_data["hit_sfx"], "arrow_hit": setup_data["arrowhit_sfx"], "attack": setup_data["attack_sfx"], "die": setup_data["die_sfx"] } self.vfx = setup_data["hit_vfx"] self.stats = { "speed": setup_data["speed"], "hp": setup_data["hp"] * (level**0.15), "armor": setup_data["armor"] * (level**0.2), "dmg": setup_data["dmg"] * (level**0.8) } if self.stats['hp'] > 500: self.stats['hp'] = 500 self.maxHP = self.stats['hp'] self.healthBar = DirectFrame(frameSize=(-0.05, 0.05, 0, 0.05), frameColor=(1, 0, 0, 1), frameTexture='icon/glass4.png', parent=self.node) self.healthBar.setTransparency(TransparencyAttrib.MDual) self.healthBar.setScale(10, 1, 1) self.healthBar.setZ(2) self.healthBar.setBillboardPointEye( ) #Make it flat in front of the camera self.ambientLight = AmbientLight('ambientLight') self.ambientLight.setColor(VBase4(.3, .3, .3, 1)) self.ambientLightNode = render.attachNewNode(self.ambientLight) self.healthBar.setLight(self.ambientLightNode) self.healthBar.hide() wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() #self.HPring.setColorScale(0.0, 1.0, 0.0, 1.0) #gamestate variables self.attack_pattern = setup_data["attack_pattern"] self.damage = setup_data["dmg"] #self.HP=setup_data["hp"] self.state = "STOP" self.id = id self.nextWaypoint = None self.canSeePC = False self.PCisInRange = False self.PC = common['PC'] self.speed_mode = random.randrange(0 + int(level), 42 + int(level), 7) / 100.0 self.totalSpeed = self.stats['speed'] + self.speed_mode self.sparkSum = 0 self.lastMagmaDmg = 0 self.DOT = 0 self.arrows = set() self.isSolid = True self.traverser = CollisionTraverser("Trav" + str(self.id)) #self.traverser.showCollisions(render) self.queue = CollisionHandlerQueue() #bit masks: # 1 visibility polygons & coll-rays # 2 walls & radar-ray # 3 spheres #collision ray for testing visibility polygons coll = self.node.attachNewNode(CollisionNode('collRay')) coll.node().addSolid(CollisionRay(0, 0, 2, 0, 0, -180)) coll.setTag("id", str(id)) coll.node().setIntoCollideMask(BitMask32.allOff()) coll.node().setFromCollideMask(BitMask32.bit(1)) self.traverser.addCollider(coll, self.queue) #radar collision ray self.radar = self.node.attachNewNode(CollisionNode('radarRay')) self.radar.node().addSolid(CollisionRay(0, 0, 1, 0, 90, 0)) self.radar.node().setIntoCollideMask(BitMask32.allOff()) self.radar.node().setFromCollideMask(BitMask32.bit(2)) self.radar.setTag("radar", str(id)) #self.radar.show() self.traverser.addCollider(self.radar, self.queue) #collision sphere self.coll_sphere = self.node.attachNewNode( CollisionNode('monsterSphere')) self.coll_sphere.node().addSolid(CollisionSphere(0, 0, 0.8, 0.6)) self.coll_sphere.setTag("id", str(id)) self.coll_sphere.node().setIntoCollideMask(BitMask32.bit(3)) #self.coll_sphere.show() #other monster blocking self.coll_quad = loader.loadModel("models/plane") self.coll_quad.reparentTo(self.node) #self.coll_quad=render.attachNewNode(CollisionNode('monsterSphere')) #self.coll_quad.node().addSolid(CollisionPolygon(Point3(-.5, -.5, 2), Point3(-.5, .5, 0), Point3(.5, .5, 0), Point3(.5, .5, 2))) #self.coll_quad.setTag("id", str(id)) #self.coll_quad.node().setIntoCollideMask(BitMask32.bit(2)) #self.coll_quad.reparentTo(self.node) #self.coll_quad.show() Sequence(Wait(random.uniform(.6, .8)), Func(self.restart)).start() self.node.setPos(render, start_pos) taskMgr.add(self.runAI, "AIfor" + str(self.id)) taskMgr.doMethodLater(.6, self.runCollisions, 'collFor' + str(self.id)) taskMgr.doMethodLater(1.0, self.damageOverTime, 'DOTfor' + str(self.id)) def die(self, soundname): n = random.random() if n < self.common["random-objects-freq"]: id = len(self.common["random-objects"]) object = RandomObject(id, self.common, self.node, render) self.common["random-objects"].append(object) self.actor.play("die") #self.common['soundPool'].play(self.soundID, self.sound_names["hit"]) self.common['soundPool'].play(self.soundID, soundname) self.state = "DIE" def damageOverTime(self, task): if self.state == "DIE": return task.done if self.DOT > 0: self.doDamage(self.DOT) self.DOT = int((self.DOT * 0.9) - 1.0) if self.stats['hp'] < 1: self.die(self.sound_names["die"]) vfx(self.node, texture=self.vfx, scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016, 24) return task.again def restart(self): self.state = "SEEK" def check_stacking(self): for monster in self.monsterList: if monster and monster.id != self.id: if self.node.getDistance(monster.node) < .8: if monster.state != "STOP" and self.state == "SEEK": if self.totalSpeed <= monster.totalSpeed: self.state = "STOP" self.actor.stop() Sequence(Wait(1.5), Func(self.restart)).start() return True def hideHealthbarTask(self, task): self.healthBar.hide() def doDamage(self, damage, ignoreArmor=False): if self.state == "DIE": return if not ignoreArmor: damage -= self.stats['armor'] if damage < 1: damage = 1 #print damage self.stats['hp'] -= damage self.healthBar.show() self.healthBar.setScale(10 * self.stats['hp'] / self.maxHP, 1, 1) taskMgr.doMethodLater(7.0, self.hideHealthbarTask, 'hideHealthbar') if self.stats['hp'] < 1: self.healthBar.hide() def attack(self, pattern): if self.state == "DIE": return if not self.PC.node: return if pattern: next = pattern.pop() else: self.state = "SEEK" self.PCisInRange = False return if self.PC.node and self.node: range = self.node.getDistance(self.PC.node) else: return #print range if range < 1.8: self.PC.hit(self.damage) Sequence(Wait(next), Func(self.attack, pattern)).start() def onHit(self, damage, sound="hit", weapon=None): if self.state == "DIE": return if weapon == "magma": damage = self.lastMagmaDmg self.common['soundPool'].play(self.soundID, "onFire") vfx(self.node, texture="vfx/small_flame.png", scale=.6, Z=.7, depthTest=False, depthWrite=False).start(0.016, stopAtFrame=24) elif weapon == "spark": self.common['soundPool'].play(self.soundID, "spark") short_vfx(self.node, texture="vfx/short_spark.png", scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.03) else: vfx(self.node, texture=self.vfx, scale=.5, Z=1.0, depthTest=True, depthWrite=True).start(0.016) self.doDamage(damage) if self.stats['hp'] < 1: if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) self.die(self.sound_names["die"]) else: if sound: self.common['soundPool'].play(self.soundID, self.sound_names[sound]) def findFirstWaypoint(self): min = 100000 nearest = None for waypoint in self.waypoints: dist = self.node.getDistance(waypoint) if dist < min: min = dist nearest = waypoint return nearest def runCollisions(self, task): if self.state == "DIE": return task.done if self.node.getDistance(self.PC.node) > 50.0: self.nextWaypoint = None return task.again if self.check_stacking(): return task.again self.radar.lookAt(self.PC.node) valid_waypoints = [] isFirstTest = True self.canSeePC = False self.traverser.traverse(render) self.queue.sortEntries() for entry in self.queue.getEntries(): if entry.getFromNodePath().hasTag( "id"): #it's the monsters collRay valid_waypoints.append( int(entry.getIntoNodePath().getTag( "index"))) #visibility polygons elif entry.getFromNodePath().hasTag("radar"): #it's the radar-ray #print "radar hit", entry.getIntoNodePath() if isFirstTest: isFirstTest = False #print "first hit!" #print "radar hit", entry.getIntoNodePath() if entry.getIntoNodePath().hasTag("player"): self.canSeePC = True '''distance={} for target in self.PC.myWaypoints: for waypoint in valid_waypoints: distance[target]=self.waypoints_data[target][waypoint] print(target, distance[target]) if distance: self.nextWaypoint=self.waypoints[min(distance, key=distance.get)] #print self.canSeePC''' if not valid_waypoints: #self.nextWaypoint=self.findFirstWaypoint() print(self.id, ": I'm lost!") valid_waypoints = [self.findFirstWaypoint()] #return task.again if self.state == "STOP": self.nextWaypoint = self.waypoints[random.choice(valid_waypoints)] return task.again best_distance = 9000000 target_node = None for target in self.PC.myWaypoints: for valid in valid_waypoints: distance = self.waypoints_data[target][valid] #print "target->valid=",target, valid, distance if distance < best_distance: best_distance = distance target_node = valid if target_node: self.nextWaypoint = self.waypoints[target_node] else: #print "no target", valid_waypoints self.nextWaypoint = self.findFirstWaypoint() #self.waypoints[random.choice(valid_waypoints)] #print self.nextWaypoint return task.again def runAI(self, task): #print self.state if self.state == "DIE": self.coll_sphere.node().setIntoCollideMask(BitMask32.allOff()) self.coll_quad.removeNode() #self.actor.play("die") self.common["kills"] -= 1 if self.common["kills"] == 0: Interactive(self.common, data.items['key'], self.node.getPos(render)) Sequence( Wait(2.0), LerpPosInterval( self.node, 2.0, VBase3(self.node.getX(), self.node.getY(), self.node.getZ() - 5)), Func(self.destroy)).start() return task.done elif self.state == "STOP": target = self.nextWaypoint if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target) > 0.3: self.node.setY(self.node, self.totalSpeed * globalClock.getDt()) if (self.actor.getCurrentAnim() != "walk"): self.actor.loop("walk") return task.again elif self.state == "ATTACK": self.node.headsUp(self.PC.node) if (self.actor.getCurrentAnim() != "attack"): self.actor.play("attack") #Sequence(Wait(self.attack_pattern[-1]+self.speed_mode), Func(self.attack, list(self.attack_pattern))).start() Sequence(Wait(self.attack_pattern[-1]), Func(self.attack, list(self.attack_pattern))).start() return task.again elif self.state == "SEEK": if self.PCisInRange: self.state = "ATTACK" return task.again target = self.nextWaypoint if self.canSeePC and self.PC.HP > 0: target = self.PC.node #print "target pc!" if not target: return task.again self.node.headsUp(target) if self.node.getDistance(target) > 0.3: self.node.setY(self.node, self.totalSpeed * globalClock.getDt()) if (self.actor.getCurrentAnim() != "walk"): self.actor.loop("walk") return task.again else: #print "I'm stuck?" #print target #print self.canSeePC self.nextWaypoint = self.PC.node return task.again def destroy(self): #for sound in self.soundset: # self.soundset[sound].stop() #print "destroy:", #self.sound_node.reparentTo(render) #self.common['soundPool'].append([self.sound_node,self.soundset]) self.common['soundPool'].set_free(self.soundID) #self.sounds=None #print " sounds", self.arrows = None if self.actor: self.actor.cleanup() self.actor.removeNode() #print " actor", if taskMgr.hasTaskNamed("hideHealthbar"): taskMgr.remove("hideHealthbar") if taskMgr.hasTaskNamed("AIfor" + str(self.id)): taskMgr.remove("AIfor" + str(self.id)) #print " AI", if taskMgr.hasTaskNamed('collFor' + str(self.id)): taskMgr.remove('collFor' + str(self.id)) #print " collision", if taskMgr.hasTaskNamed('DOTfor' + str(self.id)): taskMgr.remove('DOTfor' + str(self.id)) if self.node: self.node.removeNode() #print " node", self.monsterList[self.id] = None self.traverser = None self.queue = None self.healthBar.removeNode() self.ambientLightNode.removeNode()
class SimpleWeapon: """Provides a simple weapon system - not very sophisticaed, but good enough to test shooting things.""" def __init__(self,manager,xml): self.gunView = render.attachNewNode('gun-view') self.ray = None self.reload(manager,xml) def destroy(self): self.gunView.removeNode() if self.ray!=None: self.ray.destroy() def reload(self,manager,xml): # Get the path to load weapons from... basePath = manager.get('paths').getConfig().find('weapons').get('path') # Variables to manage the firing state (Used G36 as reference for defaults.)... bullet = xml.find('bullet') if bullet!=None: self.bulletRate = float(bullet.get('rate',1.0/12.5)) self.bulletSpeed = float(bullet.get('speed',920.0)) self.bulletWeight = float(bullet.get('mass',0.004)) else: self.bulletRate = 1.0/12.5 self.bulletSpeed = 920.0 self.bulletWeight = 0.004 # Determine the weapon meshes path... self.meshPath = posixpath.join(basePath, xml.find('egg').get('file')) # Get the camera interface, so we can zoom in when the player aims... self.camera = manager.get(xml.find('camera').get('plugin')) # Create our gun node - both the gun and the ray used for shooting track this - allows for gun jitter, kick back etc... parent = xml.find('parent') self.gunView.reparentTo(manager.get(parent.get('plugin')).getNode(parent.get('node'))) # Create a ray cast to detect what the player is looking at... and what will be shot... self.space = manager.get('ode').getSpace() if self.ray!=None: self.ray.destroy() self.ray = OdeRayGeom(100.0) self.ray.setCategoryBits(BitMask32(0xfffffffe)) self.ray.setCollideBits(BitMask32(0xfffffffe)) # Get all the stuff we need to do the muzzle flash particle effect... flash = xml.find('muzzle_flash') self.flashManager = manager.get(flash.get('plugin')) self.flashEffect = flash.get('effect') self.flashBone = flash.get('bone') # Will be swapped out for the actual node latter. self.flashPos = csp.getPos(flash.get('pos')) # Get all the stuff we need to do the bullet hit sparks effect... sparks = xml.find('sparks') self.sparksManager = manager.get(sparks.get('plugin')) self.sparksEffect = sparks.get('effect') # Create a quaternion that rotates +ve z to +ve y - used to point it in the weapon direction rather than up... self.zToY = Quat() self.zToY.setFromAxisAngle(-90.0,Vec3(1.0,0.0,0.0)) # State for the animation... self.state = False # False==casual, True==aim. self.nextState = False # Firing state... self.firing = False # True if the trigger is being held. self.triggerTime = 0.0 # How long the trigger has been held for, so we know when to eject ammo. # For bullet holes bh = xml.find('bullet_holes') if bh != None: self.bulletHoles = manager.get(bh.get('plugin')) else: self.bulletHoles = None def postInit(self): for i in self.postReload(): yield i def postReload(self): # Load the actor... self.mesh = Actor(self.meshPath) yield # Shader generator makes it shiny, plus we need it in the right places in the render graph... self.mesh.setShaderAuto() self.mesh.reparentTo(self.gunView) self.mesh.hide() yield # Set its animation going... except we pause it until needed... self.nextAni() self.interval.pause() # Gun flash requires an exposed bone... self.flashBone = self.mesh.exposeJoint(None,"modelRoot",self.flashBone) yield def gunControl(self,task): # Update the gun direction ray to follow the players view... self.ray.setPosition(self.gunView.getPos(render)) self.ray.setQuaternion(self.zToY.multiply(self.gunView.getQuat(render))) # If the gun is firing update the trigger time, if a bullet is ejected do the maths... if self.firing: dt = globalClock.getDt() self.triggerTime += dt while self.triggerTime>self.bulletRate: self.triggerTime -= self.bulletRate hit,pos,norm = ray_cast.nearestHit(self.space,self.ray) # Create a muzzle flash effect... self.flashManager.doEffect(self.flashEffect, self.flashBone, True, self.flashPos) if hit: # Create an impact sparks effect... # Calculate the reflection direction... rd = self.ray.getDirection() sparkDir = (norm * (2.0*norm.dot(rd))) - rd # Convert the reflection direction into a quaternion that will rotate +ve z to the required direction... try: ang = -math.acos(sparkDir[2]) except: print 'Angle problem', sparkDir ang = 0.0 axis = Vec3(0.0,0.0,1.0).cross(sparkDir) axis.normalize() sparkQuat = Quat() sparkQuat.setFromAxisAngleRad(ang,axis) # Set it going... self.sparksManager.doEffect(self.sparksEffect, render, False, pos, sparkQuat) # Make a bullet hole if hit.hasBody() and isinstance(hit.getBody().getData(), NodePath): self.bulletHoles.makeNew(pos, norm, hit.getBody().getData()) else: self.bulletHoles.makeNew(pos, norm, None) # Impart some energy on the object... if hit and hit.hasBody(): body = hit.getBody() # Calculate the force required to supply the energy the bullet contains to the body... force = self.bulletWeight*self.bulletSpeed/0.05 # Get the direction of travel of the bullet, multiply by force... d = self.ray.getDirection() d *= force # If the object is asleep awaken it... if not body.isEnabled(): body.enable() # Add the force to the object... body.addForceAtPos(d,pos) return task.cont def start(self): # Make the gun visible... self.mesh.show() # Set the gun animation going... self.interval.finish() # Weapon task - this primarily makes it shoot... self.task = taskMgr.add(self.gunControl,'GunControl') def stop(self): self.interval.pause() self.mesh.hide() taskMgr.remove(self.task) def nextAni(self): self.state = self.nextState if self.state: ani = random.choice(('aim_wiggle_a','aim_wiggle_b','aim_wiggle_c')) else: ani = random.choice(('casual_wiggle_a','casual_wiggle_b','casual_wiggle_c')) self.mesh.pose(ani,0) self.interval = Sequence(self.mesh.actorInterval(ani),Func(self.nextAni)) self.interval.start() def setAiming(self,s): if self.nextState!=s: self.interval.pause() self.nextState = s self.camera.setZoomed(s) def wib(): self.interval.finish() if s: ani = 'casual_aim' else: ani = 'aim_casual' transition = Sequence(self.mesh.actorInterval(ani),Func(wib)) transition.start() def setFiring(self,s): self.firing = s if self.firing: self.triggerTime = 0.0
class CharGen(DirectObject): def __init__(self, common): self.common=common self.common['chargen']=self self.load() def load(self): self.font = loader.loadFont('Bitter-Bold.otf') self.currentLevel=0 self.common['pc_stat1']=50 self.common['pc_stat2']=50 self.common['pc_stat3']=50 #render.setShaderAuto() #base.disableMouse() #render.setAntialias(AntialiasAttrib.MMultisample) #base.setBackgroundColor(0, 0, 0) wp = base.win.getProperties() winX = wp.getXSize() winY = wp.getYSize() self.campmap=loader.loadModel("models/camp3") self.campmap.reparentTo(render) #music self.common['music']=MusicPlayer(self.common) self.common['music'].loop(0) #self.common['music']=base.loadMusic("music/LuridDeliusion.ogg") #self.common['music'].setLoop(True) #self.common['music'].play() self.node=render.attachNewNode("node") self.cameraNode = self.node.attachNewNode("cameraNode") self.cameraNode.setZ(-1) base.camera.setY(-8) base.camera.setZ(5) base.camera.lookAt((0,3,0)) base.camera.wrtReparentTo(self.cameraNode) self.pointer=self.cameraNode.attachNewNode("pointerNode") #light self.pLight = PointLight('plight') self.pLight.setColor(VBase4(1, .95, .9, 1)) self.pLight.setAttenuation(Point3(.5, 0, 0.1)) self.pLightNode = self.node.attachNewNode(self.pLight) self.pLightNode.setZ(1.0) render.setLight(self.pLightNode) self.sLight=Spotlight('sLight') self.sLight.setColor(VBase4(.4, .25, .25, 1)) if self.common['extra_ambient']: self.sLight.setColor(VBase4(.7, .5, .5, 1)) spot_lens = PerspectiveLens() spot_lens.setFov(40) self.sLight.setLens(spot_lens) self.Ambient = self.cameraNode.attachNewNode( self.sLight) self.Ambient.setPos(base.camera.getPos(render)) self.Ambient.lookAt((0,3,0)) render.setLight(self.Ambient) self.fire_node=self.node.attachNewNode("fireNode") self.fire=vfx(self.fire_node, texture='vfx/big_fire3.png',scale=.29, Z=.5, depthTest=True, depthWrite=True) self.fire.show() self.fire.loop(0.02) self.character1=Actor("models/pc/male", {"attack":"models/pc/male_attack2","idle":"models/pc/male_ready2", "block":"models/pc/male_block"}) self.character1.reparentTo(self.node) self.character1.setBlend(frameBlend = True) self.character1.setPos(1,2, 0) self.character1.setScale(.025) self.character1.setH(-25.0) self.character1.setBin("opaque", 10) self.character1.loop("idle") self.swingSound = base.loader.loadSfx("sfx/swing2.ogg") coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(1, 2, 1, 1)) coll_sphere.setTag("class", "1") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) if self.common['nude']: self.character2=Actor("models/pc/female_nude", {"attack":"models/pc/female_attack1","idle":"models/pc/female_idle"}) else: self.character2=Actor("models/pc/female", {"attack":"models/pc/female_attack1","idle":"models/pc/female_idle"}) #self.character2.setPlayRate(.4, "attack") self.character2.reparentTo(self.node) self.character2.setBlend(frameBlend = True) self.character2.setPos(-1,2, 0) self.character2.setScale(.026) self.character2.setH(25.0) #self.character2.setBin("opaque", 10) self.character2.loop("idle") self.char2_magic= loader.loadModel('vfx/vfx3') self.char2_magic.setPos(self.character2.getPos()) self.char2_magic.setH(self.character2.getH()) self.char2_magic.setP(-10.0) self.char2_magic.setZ(0.71) self.char2_magic.setScale(1,2,1) self.char2_magic.wrtReparentTo(self.character2) self.char2_magic.setY(-10) self.char2_magic.setDepthWrite(False) self.char2_magic.setDepthTest(False) self.char2_magic.setLightOff() self.char2_magic.hide() self.vfxU=-0.125 self.vfxV=0 self.magicSound = base.loader.loadSfx("sfx/thunder3.ogg") coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(-1, 2, 1, 1)) coll_sphere.setTag("class", "2") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) if self.common['nude']: self.character3=Actor("models/pc/female2_nude", {"attack":"models/pc/female2_arm","reset":"models/pc/female2_fire","idle":"models/pc/female2_idle"}) else: self.character3=Actor("models/pc/female2", {"attack":"models/pc/female2_arm","reset":"models/pc/female2_fire","idle":"models/pc/female2_idle"}) #self.character2.setPlayRate(.4, "attack") self.character3.reparentTo(self.node) self.character3.setBlend(frameBlend = True) self.character3.setPos(-1.8,0.9, 0) self.character3.setScale(.026) self.character3.setH(40.0) #self.character2.setBin("opaque", 10) self.character3.loop("idle") coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(-1.8,0.9, 0, 1)) coll_sphere.setTag("class", "3") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) self.arrow_bone=self.character3.exposeJoint(None, 'modelRoot', 'arrow_bone') self.arrow=loader.loadModel('models/arrow') self.arrow.reparentTo(self.arrow_bone) self.arrow.setP(-45) self.movingArrow=None self.arrowTime=0.0 self.drawSound = base.loader.loadSfx("sfx/draw_bow2.ogg") self.fireSound = base.loader.loadSfx("sfx/fire_arrow3.ogg") self.character4=Actor("models/pc/male2", {"attack":"models/pc/male2_aura","idle":"models/pc/male2_idle"}) #self.character2.setPlayRate(.4, "attack") self.character4.reparentTo(self.node) self.character4.setBlend(frameBlend = True) self.character4.setPos(1.8,0.9, 0) self.character4.setScale(.024) self.character4.setH(-60.0) #self.character2.setBin("opaque", 10) self.character4.loop("idle") self.FFSound = base.loader.loadSfx("sfx/teleport.ogg") #self.FFSound = base.loader.loadSfx("sfx/walk_new3.ogg") coll_sphere=self.node.attachNewNode(CollisionNode('monsterSphere')) coll_sphere.node().addSolid(CollisionSphere(1.8,0.9, 0, 1)) coll_sphere.setTag("class", "4") coll_sphere.node().setIntoCollideMask(BitMask32.bit(1)) #gui self.mp_logo=DirectFrame(frameSize=(-512, 0, 0, 128), frameColor=(1,1,1, 1), frameTexture='mp_logo.png', state=DGG.NORMAL, parent=pixel2d) self.mp_logo.setPos(256+winX/2, 0, -winY) self.mp_logo.setBin('fixed', 1) self.mp_logo.hide() self.mp_logo.setTransparency(TransparencyAttrib.MDual) self.mp_logo.bind(DGG.B1PRESS, self.open_www, ['http://www.matthewpablo.com/']) #self.mp_logo.bind(DGG.WITHIN, self.GUIOnEnter, ["MP"]) #self.mp_logo.bind(DGG.WITHOUT, self.GUIOnExit) self.title = DirectFrame(frameSize=(-512, 0, 0, 128), frameColor=(1,1,1, 1), frameTexture='select.png', parent=pixel2d) self.title.setPos(256+winX/2, 0, -128) self.title.setBin('fixed', 1) self.title.setTransparency(TransparencyAttrib.MDual) #self.title.hide() self.close=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/close.png', state=DGG.NORMAL, parent=pixel2d) self.close.setPos(winX, 0, -32) self.close.setBin('fixed', 1) self.close.bind(DGG.B1PRESS, self.exit) self.start=DirectFrame(frameSize=(-256, 0, 0, 32), frameTexture='icon/level_select.png', frameColor=(1, 1, 1, 1), parent=pixel2d) self.start.setPos(128+winX/2, 0, -164) self.start.setTransparency(TransparencyAttrib.MDual) #self.start.bind(DGG.B1PRESS, self.onStart) self.start.setBin('fixed', 1) #self.start.hide() self.start_main=DirectFrame(frameSize=(-192, 0, 0, 32), frameColor=(1,1,1, 0), text_font=self.font, text='Start in Level 1', text_pos = (-160, 12,0), text_scale = 16, text_fg=(0,0,0,1), text_align=TextNode.ALeft, textMayChange=1, state=DGG.NORMAL, parent=pixel2d) self.start_main.setPos(96+winX/2, 0, -164) self.start_main.setTransparency(TransparencyAttrib.MDual) self.start_main.bind(DGG.B1PRESS, self.onStart) self.start_main.bind(DGG.WITHIN, self.GUIOnEnter, ["4A"]) self.start_main.bind(DGG.WITHOUT, self.GUIOnExit) self.start_main.setBin('fixed', 1) self.start_main.wrtReparentTo(self.start) self.start_back=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1,0,0, 0), state=DGG.NORMAL, parent=pixel2d) self.start_back.setPos(128+winX/2, 0, -164) self.start_back.setTransparency(TransparencyAttrib.MDual) self.start_back.bind(DGG.B1PRESS, self.selectLevel, [1]) self.start_back.bind(DGG.WITHIN, self.GUIOnEnter, ["4B"]) self.start_back.bind(DGG.WITHOUT, self.GUIOnExit) self.start_back.setBin('fixed', 1) self.start_back.wrtReparentTo(self.start) self.start_next=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(0,1,0, 0), state=DGG.NORMAL, parent=pixel2d) self.start_next.setPos(-96+winX/2, 0, -164) self.start_next.setTransparency(TransparencyAttrib.MDual) self.start_next.bind(DGG.B1PRESS, self.selectLevel, [-1]) self.start_next.bind(DGG.WITHIN, self.GUIOnEnter, ["4C"]) self.start_next.bind(DGG.WITHOUT, self.GUIOnExit) self.start_next.setBin('fixed', 1) self.start_next.wrtReparentTo(self.start) self.start.hide() self.slider3 = DirectSlider(range=(0,100), value=50, pageSize=10, thumb_relief=DGG.FLAT, thumb_frameTexture='glass1.png', #thumb_frameColor=(1,1,1, 1), frameTexture='glass2.png', scale=96, #frameSize=(-100, 0, 0, 100), command=self.set_slider, extraArgs=["3"], parent=pixel2d) self.slider3.setPos(winX/2, 0, -16) self.slider3.setBin('fixed', 2) self.slider2 = DirectSlider(range=(0,100), value=50, pageSize=10, thumb_relief=DGG.FLAT, thumb_frameTexture='glass1.png', #thumb_frameColor=(1,1,1, 1), frameTexture='glass2.png', scale=96, #frameSize=(-100, 0, 0, 100), command=self.set_slider, extraArgs=["2"], parent=pixel2d) self.slider2.setPos(winX/2, 0, -64) self.slider2.setBin('fixed', 2) self.slider1 = DirectSlider(range=(0,100), value=50, pageSize=10, thumb_relief=DGG.FLAT, thumb_frameTexture='glass1.png', #thumb_frameColor=(1,1,1, 1), frameTexture='glass2.png', scale=96, #frameSize=(-100, 0, 0, 100), command=self.set_slider, extraArgs=["1"], parent=pixel2d) self.slider1.setPos(winX/2, 0, -112) self.slider1.setBin('fixed', 2) self.slider1.hide() self.slider2.hide() self.slider3.hide() self.cursor=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/cursor1.png', parent=pixel2d) self.cursor.setPos(32,0, -32) self.cursor.flattenLight() self.cursor.setBin('fixed', 10) self.cursor.setTransparency(TransparencyAttrib.MDual) self.button1A=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button1A.setPos(128+winX/2, 0, -128) self.button1A.setBin('fixed', 1) self.button1B=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button1B.setPos(-96+winX/2, 0, -128) self.button1B.setBin('fixed', 1) self.button2A=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button2A.setPos(128+winX/2, 0, -79) self.button2A.setBin('fixed', 1) self.button2B=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button2B.setPos(-96+winX/2, 0, -79) self.button2B.setBin('fixed', 1) self.button3A=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button3A.setPos(128+winX/2, 0, -32) self.button3A.setBin('fixed', 1) self.button3B=DirectFrame(frameSize=(-32, 0, 0, 32), frameColor=(1, 1, 1, 1), frameTexture='icon/armor.png', state=DGG.NORMAL, parent=pixel2d) self.button3B.setPos(-96+winX/2, 0, -32) self.button3B.setBin('fixed', 1) self.button1A.hide() self.button1B.hide() self.button2A.hide() self.button2B.hide() self.button3A.hide() self.button3B.hide() self.button1A.bind(DGG.WITHIN, self.GUIOnEnter, ["1A"]) self.button1A.bind(DGG.WITHOUT, self.GUIOnExit) self.button2A.bind(DGG.WITHIN, self.GUIOnEnter, ["2A"]) self.button2A.bind(DGG.WITHOUT, self.GUIOnExit) self.button3A.bind(DGG.WITHIN, self.GUIOnEnter, ["3A"]) self.button3A.bind(DGG.WITHOUT, self.GUIOnExit) self.button1B.bind(DGG.WITHIN, self.GUIOnEnter, ["1B"]) self.button1B.bind(DGG.WITHOUT, self.GUIOnExit) self.button2B.bind(DGG.WITHIN, self.GUIOnEnter, ["2B"]) self.button2B.bind(DGG.WITHOUT, self.GUIOnExit) self.button3B.bind(DGG.WITHIN, self.GUIOnEnter, ["3B"]) self.button3B.bind(DGG.WITHOUT, self.GUIOnExit) #tooltip #self.font.setPixelsPerUnit(16) #self.font.setMinfilter(Texture.FTNearest ) #self.font.setMagfilter(Texture.FTNearest ) #self.font.setAnisotropicDegree(4) #self.font.setNativeAntialias(False) #self.font.setPageSize(1024,1024) self.Tooltip=DirectLabel(frameColor=(0, 0, 0, 0), text_font=self.font, text='Lorem ipsum dolor sit amet,\n consectetur adipisicing elit,\n sed do eiusmod tempor incididunt \nut labore et dolore magna aliqua.', #pos = (0, 0,-35), text_scale = 16, text_fg=(1,1,1,1), text_align=TextNode.ALeft , textMayChange=1, parent=pixel2d ) self.Tooltip.flattenLight() self.Tooltip.setBin('fixed', 300) self.Tooltip.hide() self.tooltip_text=[None, {"1A":"ARMOR:\nYou have more Hit Points\n", "1B":"REGENERATION:\nYou heal over time\n", "2A":"BLOCK:\nYour block is more effective\n", "2B":"SPEED:\nYour move faster\n", "3A":"DAMAGE:\nYou deal more damage\n", "3B":"CRITICAL HIT:\nChance for a critical hit\n"}, {"1A":"BLAST:\nBigger Magic Bolt explosion\n", "1B":"DAMAGE:\nMagic Bolt deals more damage\n", "2A":"LIGHTNING:\nMore damage to far targets\n", "2B":"THUNDER:\nMore damage to near targets\n", "3A":"RAPID CHARGE:\nExponential damage increase\n", "3B":"STATIC CHARGE:\nLinear damage increase\n"}, {"1A":"BARBS:\nOne hit counts as two\n", "1B":"PIERCE:\nArrows pass through targets\n", "2A":"BLEED:\nDamage over time\n", "2B":"CRIPPLE:\nSlow down enemies\n", "3A":"FINESSE:\nMore critical hits\n", "3B":"PROWESS:\nMore damage\n"}, {"1A":"BURNING DEATH:\nMagma deals more damage\n", "1B":"MAGMA FLOW:\nMore magma at once\n", "2A":"HEART OF FIRE:\nMagma lasts longer\n", "2B":"VOLCANIC ACTIVITY:\nMagma is bigger\n", "3A":"PHASESHIFT:\nYou can teleport more often\n", "3B":"WARP FIELD:\nFaster recovery after teleport\n"} ] #collisions #self.traverser=CollisionTraverser("playerTrav") #self.traverser.setRespectPrevTransform(True) #self.queue = CollisionHandlerQueue() self.MousePickerNode = CollisionNode('mouseRay') self.pickerNP = base.camera.attachNewNode(self.MousePickerNode) self.MousePickerNode.setFromCollideMask(BitMask32.bit(1)) self.MousePickerNode.setIntoCollideMask(BitMask32.allOff()) self.pickerRay = CollisionSegment() #Make our ray self.MousePickerNode.addSolid(self.pickerRay) #Add it to the collision node self.common['traverser'].addCollider(self.pickerNP, self.common['queue']) self.accept("mouse1", self.onClick) taskMgr.doMethodLater(0.2, self.flicker,'flicker') #taskMgr.add(self.camera_spin, "camera_spin") taskMgr.add(self.__getMousePos, "chargenMousePos") self.current_class=None self.camLoop=Sequence(LerpHprInterval(self.cameraNode, 10.0, VBase3(-20,0, 0), bakeInStart=0),LerpHprInterval(self.cameraNode, 10.0, VBase3(20,0, 0),bakeInStart=0)) self.camLoop.loop() self.accept( 'window-event', self.windowEventHandler) def selectLevel(self, next, event=None): self.currentLevel+=next if self.currentLevel<0: self.currentLevel=0 if self.currentLevel>self.common['max_level']: self.currentLevel=self.common['max_level'] self.start_main['text']="Start in Level "+str(self.currentLevel+1) def moveArrow(self, task): if self.movingArrow: self.arrowTime+=task.time if self.arrowTime>3.0: self.movingArrow.removeNode() self.arrowTime=0.0 return task.done dt = globalClock.getDt() self.movingArrow.setX(self.movingArrow, 400*dt) return task.again else: return task.done def fireArrow(self): self.movingArrow=loader.loadModel('models/arrow') self.movingArrow.reparentTo(self.arrow_bone) self.movingArrow.setP(-45) self.movingArrow.wrtReparentTo(render) self.arrow.hide() self.fireSound.play() taskMgr.add(self.moveArrow, "moveArrowTask") Sequence(Wait(0.5),Func(self.arrow.show)).start() def onStart(self, event=None): #unload stuff self.camLoop.pause() self.camLoop=None base.camera.reparentTo(render) self.campmap.removeNode() self.node.removeNode() self.fire.remove_loop() if taskMgr.hasTaskNamed('flicker'): taskMgr.remove('flicker') if taskMgr.hasTaskNamed('chargenMousePos'): taskMgr.remove('chargenMousePos') self.common['traverser'].removeCollider(self.pickerNP) self.pickerNP.removeNode() self.Ambient.removeNode() self.button1A.destroy() self.button1B.destroy() self.button2A.destroy() self.button2B.destroy() self.button3A.destroy() self.button3B.destroy() self.Tooltip.destroy() self.cursor.destroy() self.slider1.destroy() self.slider2.destroy() self.slider3.destroy() self.start.destroy() self.start_back.destroy() self.start_next.destroy() self.close.destroy() self.title.destroy() self.mp_logo.destroy() render.setLightOff() self.ignoreAll() #self.common['music'].stop() #self.common['spawner']=Spawner(self.common) #self.common['levelLoader']=LevelLoader(self.common) self.common['levelLoader'].load(self.currentLevel, PCLoad=False) #render.ls() if self.current_class=="1": self.common['PC']=PC1(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class=="2": self.common['PC']=PC2(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class=="3": self.common['PC']=PC3(self.common) #self.common['PC'].node.setPos(-12, 0, 0) elif self.current_class=="4": self.common['PC']=PC4(self.common) #self.common['PC'].node.setPos(-12, 0, 0) pos=(data.levels[self.currentLevel]["enter"][0], data.levels[self.currentLevel]["enter"][1], data.levels[self.currentLevel]["enter"][2]) self.common['PC'].node.setPos(pos) self.common['music'].loop(1, fadeIn=True) def open_www(self, url, event=None): webbrowser.open_new(url) def windowEventHandler( self, window=None ): #print "resize" if window is not None: # window is none if panda3d is not started wp = base.win.getProperties() X= wp.getXSize()/2 Y= wp.getYSize() self.slider3.setPos(X, 0, -16) self.slider2.setPos(X, 0, -64) self.slider1.setPos(X, 0, -112) self.button1A.setPos(128+X, 0, -128) self.button1B.setPos(-96+X, 0, -128) self.button2A.setPos(128+X, 0, -79) self.button2B.setPos(-96+X, 0, -79) self.button3A.setPos(128+X, 0, -32) self.button3B.setPos(-96+X, 0, -32) self.start.setPos(128+X, 0, -164) self.title.setPos(256+X, 0, -128) self.close.setPos(X*2, 0, -32) self.mp_logo.setPos(256+X, 0, -Y) def getSliderValue(self, option): value=0 if option[0]=="1": value=int(self.slider1['value']) elif option[0]=="2": value=int(self.slider2['value']) elif option[0]=="3": value=int(self.slider3['value']) if self.current_class=="2": if option=="1A": return "{0}% blast size".format(value+50) elif option=="1B": return "{0}% damage".format(75+(101-value)/2) elif option=="2A": return "{0}% damage to far targets".format(value*2) elif option=="2B": return "{0}% damage to near targets\n".format(2*(100-value)) elif option=="3A": return "{0}-{1} Lightning damage\n{2}-{3} Magic Bolt damage".format( int(round(value/100.0+8*(101-value)/100.0)), int(round(15*value/100.0+8*(101-value)/100)), 2*int(round(2*value/100.0+6*(101-value)/100.0)), 2*int(round(26*value/100.0+20*(101-value)/100)) ) elif option=="3B": return "{0}-{1} Lightning damage\n{2}-{3} Magic Bolt damage".format( int(round(value/100.0+8*(101-value)/100.0)), int(round(15*value/100.0+8*(101-value)/100)), 2*int(round(2*value/100.0+6*(101-value)/100.0)), 2*int(round(26*value/100.0+20*(101-value)/100)) ) elif self.current_class=="1": if option=="1A": return "{0} total HP".format(value+50) elif option=="1B": return "+{0}HP/second".format(round((101-value)/100.0, 1)) elif option=="2A": return "{0}% damage blocked".format(50+(value+1)/2) elif option=="2B": return "{0}% movement speed".format(75+(101-value)/2) elif option=="3A": return "{0}-{1} damage".format( int(round(1.0+(value+1.0)/100.0)), int(round(15.0*(1.0+(value+1.0)/50.0)))) elif option=="3B": return "{0}% chance for +{1} damage".format(5+(101-value)/2,5+(101-value)/5) elif self.current_class=="3": if option=="1A": return "{0}% chance to activate".format(int(value/2)) elif option=="1B": return "{0}%chance to pierce".format(int((100-value)/2)) elif option=="2A": return "{0}% of critical hits".format(int(value)) elif option=="2B": return "{0}% of critical hits".format(int(100-value)) elif option=="3A": return "{0}% chance for critical hit".format(25+ int(value/2)) elif option=="3B": return "{0}% damage".format(50+int(100-value)) elif self.current_class=="4": if option=="1A": return "{0}% damage".format(50+int(value)) elif option=="1B": v=1+int((100-value)/20) if v<2: return "Control 1 orb of magma" return "Control {0} orbs of magma".format(v) elif option=="2A": return "{0}% time".format(50+int(value)) elif option=="2B": return "{0}% size".format(50+int(100-value)) elif option=="3A": return "Teleport every {0} seconds".format(16.0*((100-value)/1000.0)+0.8) elif option=="3B": return "{0}% recovery time".format(50+int(value)) return "???" def GUIOnEnter(self, object, event=None): if object[0]=="4": if object[1]=="A": self.Tooltip['text']="Click to start!" elif object[1]=="B": self.Tooltip['text']="Next level" elif object[1]=="C": self.Tooltip['text']="Previous level" self.Tooltip['text_pos'] = (10, -40,0) self.Tooltip['text_align'] =TextNode.ACenter self.Tooltip.show() return if not self.current_class: return #print int(self.current_class) self.Tooltip['text']=self.tooltip_text[int(self.current_class)][object]+self.getSliderValue(object) if object[1]=="A": self.Tooltip['text_pos'] = (30, -10,0) self.Tooltip['text_align'] =TextNode.ALeft else: self.Tooltip['text_pos'] = (-20, -10,0) self.Tooltip['text_align'] =TextNode.ARight self.Tooltip.show() #print "in" def GUIOnExit(self, event=None): self.Tooltip.hide() #print "out" def start_lightning(self, time=0.03): taskMgr.doMethodLater(time, self.lightning,'vfx') self.magicSound.play() def lightning(self, task): self.char2_magic.show() self.vfxU=self.vfxU+0.5 if self.vfxU>=1.0: self.vfxU=0 self.vfxV=self.vfxV-0.125 if self.vfxV <=-1: self.char2_magic.hide() self.vfxU=0 self.vfxV=0 return task.done self.char2_magic.setTexOffset(TextureStage.getDefault(), self.vfxU, self.vfxV) return task.again def loopAnim(self, actor, anim): actor.loop(anim) def set_slider(self, id): #self.current_class=id #print id, if id=="1": self.common['pc_stat1']=int(self.slider1['value']) #print self.common['pc_stat1'] elif id=="2": self.common['pc_stat2']=int(self.slider2['value']) #print self.common['pc_stat2'] elif id=="3": self.common['pc_stat3']=int(self.slider3['value']) #print self.common['pc_stat3'] def onClick(self): self.common['traverser'].traverse(render) my_class=None for entry in self.common['queue'].getEntries(): if entry.getIntoNodePath().hasTag("class"): my_class=entry.getIntoNodePath().getTag("class") if my_class=="1": self.slider1['value']=50 self.slider2['value']=50 self.slider3['value']=50 self.current_class=my_class self.title.hide() self.start.show() self.button1A.show() self.button1B.show() self.button2A.show() self.button2B.show() self.button3A.show() self.button3B.show() self.button1A['frameTexture']='icon/armor.png' self.button1B['frameTexture']='icon/heart.png' self.button2A['frameTexture']='icon/shield2.png' self.button2B['frameTexture']='icon/move.png' self.button3A['frameTexture']='icon/power.png' self.button3B['frameTexture']='icon/critical.png' #self.skills.show() self.slider1.show() self.slider2.show() self.slider3.show() Sequence(self.character1.actorInterval("attack"),self.character1.actorInterval("block"), Func(self.loopAnim, self.character1, "idle")).start() self.swingSound.play() #self.character1.play("attack") self.character2.loop("idle") elif my_class=="2": self.slider1['value']=50 self.slider2['value']=50 self.slider3['value']=50 self.current_class=my_class self.title.hide() self.start.show() self.button1A.show() self.button1B.show() self.button2A.show() self.button2B.show() self.button3A.show() self.button3B.show() self.button1A['frameTexture']='icon/blast.png' self.button1B['frameTexture']='icon/damage.png' self.button2A['frameTexture']='icon/lightning.png' self.button2B['frameTexture']='icon/thunder.png' self.button3A['frameTexture']='icon/amp.png' self.button3B['frameTexture']='icon/volt.png' self.slider1.show() self.slider2.show() self.slider3.show() Sequence(self.character2.actorInterval("attack", playRate=0.8),Func(self.loopAnim, self.character2, "idle")).start() Sequence(Wait(0.3), Func(self.start_lightning, 0.05)).start() #self.character2.play("attack") self.character1.loop("idle") #RayVfx(self.character2, texture='vfx/lightning.png').start() elif my_class=="3": self.slider1['value']=50 self.slider2['value']=50 self.slider3['value']=50 self.current_class=my_class self.title.hide() self.start.show() self.button1A.show() self.button1B.show() self.button2A.show() self.button2B.show() self.button3A.show() self.button3B.show() self.button1A['frameTexture']='icon/barbs.png' self.button1B['frameTexture']='icon/pierce.png' self.button2A['frameTexture']='icon/bleed.png' self.button2B['frameTexture']='icon/cripple.png' self.button3A['frameTexture']='icon/finese.png' self.button3B['frameTexture']='icon/bow_damage.png' self.slider1.show() self.slider2.show() self.slider3.show() self.drawSound.play() self.character3.play("attack") Sequence(Wait(1.5),Func(self.fireArrow), Func(self.character3.play, "reset"),Wait(1.0),Func(self.loopAnim, self.character3, "idle")).start() elif my_class=="4": self.slider1['value']=50 self.slider2['value']=50 self.slider3['value']=50 self.current_class=my_class self.title.hide() self.start.show() self.button1A.show() self.button1B.show() self.button2A.show() self.button2B.show() self.button3A.show() self.button3B.show() self.button1A['frameTexture']='icon/hand_o_fate.png' self.button1B['frameTexture']='icon/magma_flow.png' self.button2A['frameTexture']='icon/heart_o_fire.png' self.button2B['frameTexture']='icon/vulcanic.png' self.button3A['frameTexture']='icon/warp.png' self.button3B['frameTexture']='icon/thorns.png' #self.skills.show() self.slider1.show() self.slider2.show() self.slider3.show() self.character4.loop("attack") aura=vfx(self.character4, texture='vfx/tele2.png',scale=.5, Z=.85, depthTest=False, depthWrite=False) aura.show() aura.start() self.FFSound.play() Sequence(Wait(2.2), Func(self.loopAnim, self.character4, "idle")).start() def exit(self, event=None): self.common['root'].save_and_exit() #sys.exit() def __getMousePos(self, task): if base.mouseWatcherNode.hasMouse(): mpos = base.mouseWatcherNode.getMouse() self.pickerRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) pos2d=Point3(mpos.getX() ,0, mpos.getY()) self.cursor.setPos(pixel2d.getRelativePoint(render2d, pos2d)) self.Tooltip.setPos(self.cursor.getPos()) return task.again def flicker(self, task): self.pLight.setAttenuation(Point3(1, 0, random.uniform(.1, 0.15))) self.pLightNode.setZ(random.uniform(.9, 1.1)) #self.pLight.setColor(VBase4(random.uniform(.9, 1.0), random.uniform(.9, 1.0), .9, 1)) return task.again def camera_spin(self, task): H=self.cameraNode.getH() #Z=self.cameraNode.getZ() #print H if H<=-20.0 or H>=20.0: if self.reverse_spin: self.reverse_spin=False else: self.reverse_spin=True if self.reverse_spin: self.cameraNode.setH(self.cameraNode, 4*globalClock.getDt()) #self.cameraNode.setZ(Z+0.1*globalClock.getDt()) else: self.cameraNode.setH(self.cameraNode, -4*globalClock.getDt()) #self.cameraNode.setZ(Z-0.1*globalClock.getDt()) return task.again #c=Camp() #run()
class Transporter(): def __init__(self, name, aiworld, tradeMap, position=Vec3(-10, 0, 0)): self.name = name self.aiworld = aiworld self.tradeMap = tradeMap self.model = Actor("models/ralph", {"run":"models/ralph-run"}) self.model.reparentTo(render) self.model.setScale(0.5) self.model.setPos(position) self.model.loop("run") self.radius = getRadius(self.model) self.rightHand = self.model.exposeJoint(None, 'modelRoot', 'RightHand') self.cargo = 0 self.money = 10 self.tradeRoute = None self.goal = None self.initAI() def initAI(self): self.ai = AICharacter(self.name, self.model, 100, 10, 10) self.aiworld.addAiChar(self.ai) self.behaviors = self.ai.getAiBehaviors() self.behaviors.obstacleAvoidance(1.0) self.aiworld.addObstacle(self.model) taskMgr.doMethodLater(0.5, self.updateAI, "transporter ai") def buy(self, factory): '''Buy one product from input factory if possible.''' if factory.canSell(): factory.product -= 1 factory.updateDisplay() self.grab(Cargo(factory.productType)) return True return False def sell(self, factory): '''Sell one product to input factory if possible.''' if factory.canBuy(): factory.resource += 1 factory.updateDisplay() self.drop() return True return False def grab(self, cargo): cargo.carryOn(self.rightHand) self.cargo = cargo def drop(self): self.cargo.drop() self.cargo = None def findTradeRoute(self): '''Find the best (shortest) trade route from our current position. Currently uses only distance. ''' lowestDistance = 9999999999 bestRoute = None distance = lowestDistance for x in self.tradeMap.routes: if x.open: distance = x.distance + getXYDistance(self.model, x.start.productNP) if distance < lowestDistance: bestRoute = x lowestDistance = distance return bestRoute def findBuyer(self): '''We have a product, so we don't need a complete trade route. Just find the best (closest) buyer for our product.''' if not self.cargo: return lowestDistance = 9999999999 bestBuyer = None for x in self.tradeMap.factories: if x.canBuy(): if x.resourceType == self.cargo: distance = getXYDistance(self.model, x.resourceNP) if distance < lowestDistance: bestBuyer = x lowestDistance = distance return bestBuyer def setGoal(self, goal): self.goal = goal if not goal == None: print self.name, "'s goal: ", self.goal.name else: print self.name, "'s goal: None" def stop(self): self.behaviors.removeAi("seek") def updateAI(self, task): #self.stop() # If ai has no current goal, try to find one. if (self.goal == None): if (self.tradeRoute == None): self.tradeRoute = self.findTradeRoute() if (self.tradeRoute == None): return Task.again if (self.cargo): self.setGoal(self.tradeRoute.end) else: self.setGoal(self.tradeRoute.start) # If we still don't have a goal just try again later. if (self.goal == None): return Task.again if (self.cargo): # We have the product. Go to resource point for trade route ending. dockingDistance = self.radius + self.goal.getResourceRadius() if (getXYDistance(self.model, self.goal.resourceNP) > dockingDistance): self.behaviors.seek(self.goal.resourceNP, 0.5) else: self.tradeRoute = None if self.sell(self.goal): self.setGoal(None) else: self.setGoal(self.findBuyer()) else: # We have no product. Go to product point of trade route start. dockingDistance = self.radius + self.goal.getProductRadius() if (getXYDistance(self.model, self.goal.productNP) > dockingDistance): self.behaviors.seek(self.goal.productNP, 0.5) else: if not self.buy(self.goal): self.tradeRoute = None self.setGoal(None) return Task.again
class ToonMaker(ShowBase): def __init__(self): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) ''' cam1 = Camera('cam1') cam1.getLens().setNear(0.01) cam1.getLens().setFov(50) cam1.showFrustum() camera1 = self.render.attachNewNode(cam1) camera1.setName('camera1') camera1.setPos(0, -6, 3) cam2 = Camera('cam2') cam2.getLens().setNear(0.01) cam2.getLens().setFov(50) #cam2.showFrustum() camera2 = self.render.attachNewNode(cam2) camera2.setName('camera2') camera2.setPos(0, -6, 3) ''' self.disableMouse() #self.cam = camera2 #self.lens = self.cam.node().getLens() self.camera.setPos(0, -6, 3.2) self.camLens.setNearFar(0.01, 1000.0) self.camLens.setFov(50) #self.cam.node().setLodScale(math.tan(math.radians(100.0 * 0.5))) self.setBackgroundColor(1, 1, 1) # Check video card capabilities. if not self.win.getGsg().getSupportsBasicShaders(): print( "Toon Shader: Video driver reports that Cg shaders are not supported." ) return # This shader's job is to render the model with discrete lighting # levels. The lighting calculations built into the shader assume # a single nonattenuating point light. tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(self.loader.loadShader("shader/lightingGen.sha")) self.cam.node().setInitialState(tempnode.getState()) # This is the object that represents the single "light", as far # the shader is concerned. It's not a real Panda3D LightNode, but # the shader doesn't care about that. light = self.render.attachNewNode("light") light.setPos(30, -50, 0) # this call puts the light's nodepath into the render state. # this enables the shader to access this light by name. self.render.setShaderInput("light", light) # The "normals buffer" will contain a picture of the model colorized # so that the color of the model is a representation of the model's # normal at that point. normalsBuffer = self.win.makeTextureBuffer("normalsBuffer", 0, 0) normalsBuffer.setClearColor(LVecBase4(0.5, 0.5, 0.5, 1)) self.normalsBuffer = normalsBuffer normalsCamera = self.makeCamera(normalsBuffer, lens=self.cam.node().getLens()) normalsCamera.node().setScene(self.render) tempnode = NodePath(PandaNode("temp node")) tempnode.setShader(self.loader.loadShader("shader/normalGen.sha")) normalsCamera.node().setInitialState(tempnode.getState()) # what we actually do to put edges on screen is apply them as a texture to # a transparent screen-fitted card drawnScene = normalsBuffer.getTextureCard() drawnScene.setTransparency(1) drawnScene.setColor(1, 1, 1, 0) drawnScene.reparentTo(self.render2d) self.drawnScene = drawnScene # this shader accepts, as input, the picture from the normals buffer. # it compares each adjacent pixel, looking for discontinuities. # wherever a discontinuity exists, it emits black ink. self.separation = 0.00065 self.cutoff = 0.3 inkGen = self.loader.loadShader("shader/inkGen.sha") drawnScene.setShader(inkGen) drawnScene.setShaderInput( "separation", LVecBase4(self.separation, 0, self.separation, 0)) drawnScene.setShaderInput("cutoff", LVecBase4(self.cutoff)) # Load a model and start its animation. self.character = Actor() #self.character.loadModel('models/miku/tda_miku') #self.character.loadAnims({'anim': 'models/miku/tda_miku-Anim0'}) #self.character.listJoints() #node = self.character.find('**/*modelRoot') #geom_node = node.getChildren()[0].node() #geoms = geom_node.getGeoms() #for child in node.getChildren(): # print child self.character.loadModel('models/dekiruo/dekiruo') self.character.reparentTo(self.render) self.character.ls() self.character.loadAnims( {'normal': 'models/dekiruo/dekiruo-Anim_normal'}) self.character.play('normal') #self.character.loadAnims({'anger': 'models/dekiruo/dekiruo-Anim_anger'}) #self.character.play('anger') #self.character.loadAnims({'sadness2crying': 'models/dekiruo/dekiruo-Anim_sadness2crying'}) #self.character.play('sadness2crying') #self.character.loadAnims({'sleep': 'models/dekiruo/dekiruo-Anim_sleep'}) #self.character.play('sleep') #self.character.loadAnims({'smile': 'models/dekiruo/dekiruo-Anim_smile'}) #self.character.play('smile') #self.character.loadAnims({'surprised': 'models/dekiruo/dekiruo-Anim_surprised'}) #self.character.play('surprised') #self.character.loadModel('models/dekinaio/dekinaio') #self.character.reparentTo(self.render) #self.character.ls() #self.character.loadAnims({'normal': 'models/dekinaio/dekinaio-Anim_normal'}) #self.character.play('normal') #self.character.loadAnims({'anger': 'models/dekinaio/dekinaio-Anim_anger'}) #self.character.play('anger') #self.character.loadAnims({'sadness2crying': 'models/dekinaio/dekinaio-Anim_sadness2crying'}) #self.character.play('sadness2crying') #self.character.loadAnims({'sleep': 'models/dekinaio/dekinaio-Anim_sleep'}) #self.character.play('sleep') #self.character.loadAnims({'smile': 'models/dekinaio/dekinaio-Anim_smile'}) #self.character.play('smile') #self.character.loadAnims({'surprised': 'models/dekinaio/dekinaio-Anim_surprised'}) #self.character.play('surprised') #anim = self.character.getCurrentAnim() #frames = self.character.getNumFrames(anim) #print anim, frames #self.character.pose(anim, int(frames * 0.9)) # Create smiley's node to indicate 3d points self.smileyActor1 = self.render.attachNewNode('SmileyActorNode1') self.smileyActor2 = self.render.attachNewNode('SmileyActorNode2') smiley = self.loader.loadModel('smiley') smiley.setScale(0.01, 0.01, 0.01) smiley.instanceTo(self.smileyActor1) smiley.instanceTo(self.smileyActor2) n1 = self.character.exposeJoint(None, "modelRoot", "Eyes") n2 = self.character.exposeJoint(None, "modelRoot", "Head") self.label1 = OnscreenText(text='P1', fg=(1, 0, 0, 1), pos=(0, 0), scale=.05, mayChange=1) self.label2 = OnscreenText(text='P2', fg=(1, 0, 0, 1), pos=(0, 0), scale=.05, mayChange=1) self.info1 = OnscreenText(text='dist3d:', fg=(1, 0, 0, 1), pos=(-1, 0), scale=.05, mayChange=1) self.info2 = OnscreenText(text='dist2d:', fg=(1, 0, 0, 1), pos=(-1, -0.1), scale=.05, mayChange=1) self.info3 = OnscreenText(text='camera:', fg=(1, 0, 0, 1), pos=(-1, -0.2), scale=.05, mayChange=1) self.taskMgr.add(self.lookAt, 'lookAt', extraArgs=[n1, n2]) self.taskMgr.add(self.updateNamePos, 'name pos update', extraArgs=[n1, n2]) # These allow you to change cartooning parameters in realtime self.accept("escape", sys.exit, [0]) self.accept("arrow_up", self.camera_f) #self.increaseSeparation) self.accept("arrow_down", self.camera_b) #self.decreaseSeparation) self.accept("arrow_left", self.camera_l) #self.increaseCutoff) self.accept("arrow_right", self.camera_r) #self.decreaseCutoff) self.accept("s", self.saveImage) self.accept("p", self.play) self.accept("o", self.stop) self.accept("n", self.forward) self.accept("b", self.rewind) self.accept("l", self.lookAt) self.accept("h", self.hide) self.accept("1", self.cam_closeup) self.accept("2", self.cam_bustshot) self.accept("3", self.cam_longshot) def decide_camera_distance(self, face_length): pass #顔の大きさが決まったら対象からカメラの距離を返す。TODO def cam_closeup(self): self.camera.setPos(self.render, (0, -1.0, 3.2)) def cam_bustshot(self): self.camera.setPos(self.render, (0, -2.0, 3.2)) def cam_longshot(self): self.camera.setPos(self.render, (0, -10.0, 3.2)) def camera_f(self): pos = self.camera.getPos(self.render) self.camera.setPos(pos[0], pos[1] + 0.1, pos[2]) def camera_b(self): pos = self.camera.getPos(self.render) self.camera.setPos(pos[0], pos[1] - 0.1, pos[2]) def camera_r(self): pos = self.camera.getPos(self.render) self.camera.setPos(pos[0] + 0.1, pos[1], pos[2]) def camera_l(self): pos = self.camera.getPos(self.render) self.camera.setPos(pos[0] - 0.1, pos[1], pos[2]) def increaseSeparation(self): self.separation = self.separation * 1.11111111 print("separation: %f" % (self.separation)) self.drawnScene.setShaderInput( "separation", LVecBase4(self.separation, 0, self.separation, 0)) def decreaseSeparation(self): self.separation = self.separation * 0.90000000 print("separation: %f" % (self.separation)) self.drawnScene.setShaderInput( "separation", LVecBase4(self.separation, 0, self.separation, 0)) def increaseCutoff(self): self.cutoff = self.cutoff * 1.11111111 print("cutoff: %f" % (self.cutoff)) self.drawnScene.setShaderInput("cutoff", LVecBase4(self.cutoff)) def decreaseCutoff(self): self.cutoff = self.cutoff * 0.90000000 print("cutoff: %f" % (self.cutoff)) self.drawnScene.setShaderInput("cutoff", LVecBase4(self.cutoff)) def saveImage(self): self.graphicsEngine.renderFrame() image = PNMImage() dr = self.camNode.getDisplayRegion(0) dr.getScreenshot(image) image.write(Filename('testImg.png')) def play(self): frame = self.character.getCurrentFrame('anim') self.character.play('anim', fromFrame=frame) def stop(self): frame = self.character.getCurrentFrame('anim') self.character.pose('anim', frame) def forward(self): frame = self.character.getCurrentFrame('anim') + 10 frame = min(frame, self.character.getNumFrames('anim')) self.character.pose('anim', frame) def rewind(self): frame = self.character.getCurrentFrame('anim') - 10 frame = max(0, frame) self.character.pose('anim', frame) def lookAt(self, node1, node2): pos1 = node1.getPos(self.render) pos2 = node2.getPos(self.render) self.camera.lookAt((pos1 + pos2) / 2.0, (0, 0, 1)) return Task.cont def hide(self): if self.character.isHidden(): self.character.show() else: self.character.hide() def map3dToAspect2d(self, node, point): """Maps the indicated 3-d point (a Point3), which is relative to the indicated NodePath, to the corresponding point in the aspect2d scene graph. Returns the corresponding Point3 in aspect2d. Returns None if the point is not onscreen. """ # Convert the point to the 3-d space of the camera p3 = self.camera.getRelativePoint(node, point) # Convert it through the lens to render2d coordinates p2 = Point2() if not self.camLens.project(p3, p2): return None r2d = Point3(p2[0], 0, p2[1]) # And then convert it to aspect2d coordinates a2d = self.aspect2d.getRelativePoint(self.render2d, r2d) return a2d def updateNamePos(self, node1, node2): # show 3d points self.smileyActor1.setPos(node1.getPos(self.render)) self.smileyActor2.setPos(node2.getPos(self.render)) # show 2d points pos1 = self.map3dToAspect2d(self.render, node1.getPos(self.render)) if pos1 == None: self.label1.hide() else: self.label1['pos'] = (pos1[0], pos1[2]) self.label1.show() pos2 = self.map3dToAspect2d(self.render, node2.getPos(self.render)) if pos2 == None: self.label2.hide() else: self.label2['pos'] = (pos2[0], pos2[2]) self.label2.show() dist3dc = (node2.getPos(self.render) - node1.getPos(self.render)).length() dist3d = node2.getPos(node1).length() self.info1['text'] = 'dist3d: ' + str(dist3d) if pos1 != None and pos2 != None: dist2d = (pos2 - pos1).length() dist_cam = 4.0 * (dist3d / dist2d) else: dist2d = None dist_cam = None self.info2['text'] = 'dist2d: ' + str(dist2d) cam_pos = self.camera.getPos() self.info3['text'] = 'camera: ' + str(cam_pos) + ' dist_cam: ' + str( dist_cam) # -10.0 <-> -1.0 return Task.cont
class MayaDemo(ShowBase): R_LEG_JOINTS = ["joint6", "joint7", "joint8"] L_LEG_JOINTS = ["joint10", "joint11", "joint12"] def __init__(self): ShowBase.__init__(self) self.bandit = Actor("banditRiggedNoHat.egg") self.bandit.makeSubpart("r_leg", self.R_LEG_JOINTS) self.bandit.makeSubpart("l_leg", self.L_LEG_JOINTS) headJoint = self.bandit.exposeJoint(None, "modelRoot", "joint5") hat = loader.loadModel("{}_hat.egg".format(random.randint(0, 7))) hat.setPos(0, 0, -0.08) hat.setHpr(-90, 0, 0) hat.setScale(0.35) hat.reparentTo(headJoint) self.bandit.reparentTo(render) r_hip_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[0]) r_hip_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[0]) r_knee_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[1]) r_knee_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[1]) r_ankle_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[2]) r_ankle_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[2]) distances = np.array([ r_hip_ro.getDistance(r_knee_ro), r_knee_ro.getDistance(r_ankle_ro) ]) self.r_leg = Leg.Leg(r_hip_ro, r_hip_wo, r_knee_ro, r_knee_wo, r_ankle_ro, r_ankle_wo, distances) l_hip = self.bandit.controlJoint(None, "modelRoot", self.L_LEG_JOINTS[0]) l_knee = self.bandit.controlJoint(None, "modelRoot", self.L_LEG_JOINTS[1]) l_ankle = self.bandit.exposeJoint(None, "modelRoot", self.L_LEG_JOINTS[2]) distances = np.array( [l_hip.getDistance(l_knee), l_knee.getDistance(l_ankle)]) #self.l_leg = Leg.Leg(l_hip, l_knee, l_ankle, distances) self.accept("arrow_up", self.r_leg.moveAnkle, [(0, 0, 0.1)]) self.accept("arrow_down", self.r_leg.moveAnkle, [(0, 0, -0.1)]) self.accept("arrow_left", self.r_leg.rotateAnkle, [(0, 0, 10)]) self.accept("arrow_right", self.r_leg.rotateAnkle, [(0, 0, -10)]) # Draws debug skeleton self.bandit.setBin('background', 1) self.walkJointHierarchy(self.bandit, self.bandit.getPartBundle('modelRoot')) self.stream = StreamRead("/dev/input/smartshoes") self.last_t = time.time() taskMgr.add(self.getDeviceData, 'Stream reader') def getDeviceData(self, task): records = self.stream.readFromStream() if records and len(records[0]) == 10: records = map(float, records[0]) angular_velocity, acceleration, magnetic_field = [ records[x:x + 3] for x in range(0, 9, 3) ] # Switch axis orientations angular_velocity[2], angular_velocity[0] = angular_velocity[ 0], angular_velocity[2] acceleration[2], acceleration[0] = acceleration[0], acceleration[2] magnetic_field[2], magnetic_field[0] = magnetic_field[ 0], magnetic_field[2] self.r_leg.ankle_rotation.rotationMagic(records[9], angular_velocity, acceleration, magnetic_field) self.r_leg.updateAnkleRotation() return task.again def walkJointHierarchy(self, actor, part, parentNode=None, indent=""): if isinstance(part, CharacterJoint): np = actor.exposeJoint(None, 'modelRoot', part.getName()) if parentNode and parentNode.getName() != "root": lines = LineSegs() lines.setThickness(3.0) lines.setColor(random.random(), random.random(), random.random()) lines.moveTo(0, 0, 0) lines.drawTo(np.getPos(parentNode)) lnp = parentNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40) lnp.setDepthWrite(False) lnp.setDepthTest(False) parentNode = np for child in part.getChildren(): self.walkJointHierarchy(actor, child, parentNode, indent + " ")
class IKChain(): def __init__(self, parent): # Create a character. self.char = Character('IKChain') self.bundle = self.char.getBundle(0) self.skeleton = PartGroup(self.bundle, '<skeleton>') self.root = CharacterJoint(self.char, self.bundle, self.skeleton, 'root', Mat4.identMat()) self.bones = [] self.target = None self.targetReached = False self.parent = parent def addBone(self, offset, rotAxis=None, minAng=0, maxAng=0, parentBone=None): name = "joint" + str(len(self.bones)) if parentBone is None: transform = Mat4.identMat() joint = CharacterJoint(self.char, self.bundle, self.root, name, transform) else: transform = Mat4.translateMat(parentBone.offset) joint = CharacterJoint(self.char, self.bundle, parentBone.joint, name, transform) if rotAxis: rotAxis = rotAxis.normalized() bone = Bone(offset, rotAxis, minAng, maxAng, joint, parent=parentBone) self.bones.append(bone) return bone def finalize(self): self.charNodePath = NodePath(self.char) self.actor = Actor(self.charNodePath) #, {'simplechar' : anim}) self.actor.reparentTo(self.parent) self.rootExposedNode = self.actor.exposeJoint(None, "modelRoot", self.root.getName()) # Root of the chain parentIKNode = self.rootExposedNode # For each bone, create: # - a control node which will be used to update the bone position after IK solving # - an exposed node which we can attach things to, to render them # - a normal NodePath node called ikNode, which we'll use during IK solving for bone in self.bones: name = bone.joint.getName() controlNode = self.actor.controlJoint(None, "modelRoot", name) bone.controlNode = controlNode exposedNode = self.actor.exposeJoint(None, "modelRoot", name) bone.exposedNode = exposedNode # Separate nodes for IK: ikNode = parentIKNode.attachNewNode(name) # Same local pos as the exposed joints: ikNode.setPos(controlNode.getPos()) bone.ikNode = ikNode parentIKNode = ikNode self.endEffector = self.bones[-1].ikNode.attachNewNode("EndEffector") self.endEffector.setPos(self.bones[-1].offset) def updateIK(self): # Solve the IK chain for the IK nodes: if self.target: self.inverseKinematicsCCD() # Copy the data from the IK chain to the actual bones. # This will end up affecting the actual mesh. for bone in self.bones: bone.controlNode.setQuat(bone.ikNode.getQuat()) def inverseKinematicsCCD(self, threshold=1e-2, minIterations=1, maxIterations=10): self.targetReached = False for i in range(maxIterations): if i >= minIterations: err = (self.target.getPos(render) - self.endEffector.getPos(render)).lengthSquared() if err < threshold: self.targetReached = True break for j in range(len(self.bones)): bone = self.bones[-j - 1] boneNode = bone.ikNode if bone.parent: parentNode = bone.parent.ikNode else: parentNode = self.rootExposedNode target = self.target.getPos(boneNode) pos = LPoint3.zero() ee = self.endEffector.getPos(boneNode) d1 = target - pos d2 = ee - pos cross = d1.cross(d2).normalized() if cross.lengthSquared() < 1e-9: continue ang = d2.normalized().signedAngleRad(d1.normalized(), cross) q = Quat() q.setFromAxisAngleRad(ang, cross) # Add this rotation to the current rotation: qOld = boneNode.getQuat() qNew = q * qOld qNew.normalize() #boneNode.setQuat( qNew ) # Correct rotation for hinge: if bone.axis: #qInv = boneNode.getQuat() #qInv.invertInPlace() #myAxisInParentSpace = qInv.xform( bone.axis ) myAxisInParentSpace = bone.axis swing, twist = swingTwistDecomposition( qNew, -myAxisInParentSpace) qNew = twist rotAxis = qNew.getAxis() rotAxis.normalize() ang = qNew.getAngleRad() if rotAxis.lengthSquared() > 1e-3 and not math.isnan( ang) and abs(ang) > 0: # valid rotation axis? # reduce the angle ang = ang % (math.pi * 2) # force into the minimum absolute value residue class, so that -180 < angle <= 180 if ang > math.pi: ang -= 2 * math.pi if abs(ang) > 1e-6 and abs(ang) < math.pi * 2: if bone.axis and (rotAxis - bone.axis).lengthSquared() > 0.5: # Clamp the rotation value: ang = max(-bone.maxAng, min(-bone.minAng, ang)) else: # Clamp the rotation value: ang = max(bone.minAng, min(bone.maxAng, ang)) #ang = -ang #rotAxis = -rotAxis #annealing = (j+1)/len(self.bones) #print("annealing", annealing) #q = qOld + (qNew-qOld)*annealing qNew.setFromAxisAngleRad(ang, rotAxis) boneNode.setQuat(qNew) def setTarget(self, node): self.target = node def debugDisplay(self): for bone in self.bones: col = (random.random(), random.random(), random.random()) #col = (0,0,0) lines = LineSegs() lines.setThickness(6) lines.setColor(col[0], col[1], col[2]) lines.moveTo(0, 0, 0) #lines.drawTo(np.getPos(parentNode)) lnp = bone.exposedNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40) #lnp.setDepthWrite(False) #lnp.setDepthTest(False) lines = LineSegs() lines.setThickness(12) lines.setColor(col[0], col[1], col[2]) lines.moveTo(0, 0, 0) lines.drawTo(bone.offset) #lines.drawTo(np.getPos(parentNode)) lnp = bone.exposedNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40) #lnp.setDepthWrite(False) #lnp.setDepthTest(False) if bone.parent: parentNode = bone.parent.exposedNode else: parentNode = self.rootExposedNode lines = LineSegs() lines.setColor(0.6, 0.2, 0.2) #lines.setColor( 0.02, 0.02, 0.02 ) myPos = bone.exposedNode.getPos(parentNode) if bone.axis: qMin = Quat() qMin.setFromAxisAngleRad(bone.minAng, bone.axis) qMax = Quat() qMax.setFromAxisAngleRad(bone.maxAng, bone.axis) l = bone.offset.normalized() * 0.3 lines.moveTo(myPos) lines.drawTo(myPos + qMin.xform(l)) lines.moveTo(myPos) lines.drawTo(myPos + qMax.xform(l)) else: qMin = Quat() qMin.setFromAxisAngleRad(bone.minAng, LVector3f.unitY()) qMax = Quat() qMax.setFromAxisAngleRad(bone.maxAng, LVector3f.unitY()) l = bone.offset.normalized() * 0.3 lines.moveTo(myPos) lines.drawTo(myPos + qMin.xform(l)) lines.moveTo(myPos) lines.drawTo(myPos + qMax.xform(l)) qMin = Quat() qMin.setFromAxisAngleRad(bone.minAng, LVector3f.unitZ()) qMax = Quat() qMax.setFromAxisAngleRad(bone.maxAng, LVector3f.unitZ()) lines.moveTo(myPos) lines.drawTo(myPos + qMin.xform(l)) lines.moveTo(myPos) lines.drawTo(myPos + qMax.xform(l)) lnp = parentNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40) #lnp.setDepthWrite(False) #lnp.setDepthTest(False) if bone.axis: lines = LineSegs() lines.setColor(0.6, 0.6, 0.6) lines.setThickness(3) lines.moveTo(myPos) lines.drawTo(myPos + bone.axis.normalized() * 0.3) lnp = parentNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40)
class HL2Pistol(BaseHitscan, HL2PistolShared): #ModelPath = "phase_14/hl2/w_pistol/w_pistol.bam" ModelOrigin = (-0.03, 1.19, -0.14) ModelAngles = (2.29, 347.01, 45) ModelScale = 2 Name = GagGlobals.HL2Pistol ID = ATTACK_HL2PISTOL Hold = ATTACK_HOLD_RIGHT sgDir = 'phase_14/hl2/v_pistol/' sgActorDef = [ sgDir + 'v_pistol.bam', { 'draw': sgDir + 'v_pistol-draw.egg', 'idle': sgDir + 'v_pistol-idle01.egg', 'fire': sgDir + 'v_pistol-fire.egg', 'reload': sgDir + 'v_pistol-reload.egg' } ] sgFirePath = 'phase_14/hl2/v_pistol/pistol_fire2.wav' sgEmptyPath = 'phase_14/hl2/v_pistol/pistol_empty.wav' sgReloadPath = 'phase_14/hl2/v_pistol/pistol_reload1.wav' SpecialVM = True def __init__(self): BaseHitscan.__init__(self) self.sgViewModel = None self.fireSound = None self.emptySound = None self.reloadSound = None self.fpMuzzleAttach = None @classmethod def doPrecache(cls): super(HL2Pistol, cls).doPrecache() precacheActor(cls.sgActorDef) precacheSound(cls.sgFirePath) precacheSound(cls.sgEmptyPath) precacheSound(cls.sgReloadPath) def load(self): self.fireSound = base.audio3d.loadSfx(self.sgFirePath) self.emptySound = base.audio3d.loadSfx(self.sgEmptyPath) self.reloadSound = base.audio3d.loadSfx(self.sgReloadPath) base.audio3d.attachSoundToObject(self.fireSound, self.avatar) base.audio3d.attachSoundToObject(self.emptySound, self.avatar) base.audio3d.attachSoundToObject(self.reloadSound, self.avatar) if self.isLocal(): self.sgViewModel = Actor(self.sgActorDef[0], self.sgActorDef[1]) self.sgViewModel.setPlayRate(self.Speed, "idle") self.sgViewModel.node().setBounds(OmniBoundingVolume()) self.sgViewModel.node().setFinal(1) self.sgViewModel.setBlend( frameBlend=base.config.GetBool('interpolate-frames', False)) self.sgViewModel.setH(180) self.fpMuzzleAttach = self.sgViewModel.exposeJoint( None, "modelRoot", "ValveBiped.muzzle") def cleanup(self): if self.sgViewModel: self.sgViewModel.cleanup() self.sgViewModel.removeNode() self.sgViewModel = None self.fpMuzzleAttach = None if self.fireSound: base.audio3d.detachSound(self.fireSound) self.fireSound = None if self.emptySound: base.audio3d.detachSound(self.emptySound) self.emptySound = None if self.reloadSound: base.audio3d.detachSound(self.reloadSound) self.reloadSound = None BaseHitscan.cleanup(self) def equip(self): if not BaseHitscan.equip(self): return False if self.isFirstPerson(): fpsCam = self.getFPSCam() fpsCam.swapViewModel(self.sgViewModel, 54.0) self.getViewModel().show() self.doDrawAndHold('squirt', 0, 43, 1.0, 43, 43) return True def unEquip(self): if not BaseHitscan.unEquip(self): return False if self.isFirstPerson(): self.getFPSCam().restoreViewModel() self.getViewModel().hide() return True def onSetAction(self, action): if action == self.StateReload: self.reloadSound.play() elif action == self.StateFire: self.fireSound.play() def onSetAction_firstPerson(self, action): track = Sequence() vm = self.getViewModel() fpsCam = self.getFPSCam() if action == self.StateIdle: track.append(Func(vm.loop, "idle")) elif action == self.StateDraw: track.append(ActorInterval(vm, "draw", playRate=self.Speed)) elif action == self.StateReload: track.append(Func(self.reloadSound.play)) track.append(ActorInterval(vm, "reload", playRate=self.Speed)) elif action == self.StateFire: CIGlobals.makeMuzzleFlash(self.fpMuzzleAttach, (0, 0, 0), (-90, 0, 0), 7) fpsCam.resetViewPunch() fpsCam.addViewPunch( Vec3(random.uniform(-0.6, 0.6), random.uniform(-0.25, -0.5), 0.0)) track.append(Func(self.fireSound.play)) track.append(ActorInterval(vm, "fire", playRate=self.Speed)) fpsCam.setVMAnimTrack(track)
class Player(Movable): """Player has many parts, and all of them we must sync""" def __init__(self, model, world): model = render.attachNewNode("player") super(Player, self).__init__(model, world) # Player has some parts #Legs, body, weapons self.legs = Actor('content/entity/mech', { 'stay': 'content/entity/mech-Anim1', 'start': 'content/entity/ech-Anim1', 'walk': 'content/entity/mech-walk', }) self.legs.reparentTo(model) self.legs.loop('walk') point = self.legs.exposeJoint(None, "modelRoot", "pelvis") self.body = loader.loadModel('content/entity/torso') self.body.reparentTo(point) self.body.setHpr(render, 0, 0, 0) # weapons has limited points # 1 self.tower = None # 2 self.right = None # 3 self.left = None # 4 self.right2 = None # 5 self.left2 = None # For firing using dict, witch weapon is on self.firing = [1, ] # variables hardcoded self.bodyRotate = 50 self.speedRotate = 50 self.isPlayer = False self.targetRotation = (0, 0) self.target = None def setControl(self, key, value): '''TODO ''' changed = False if value and key not in self.actions: self.actions.append(key) changed = True elif not value and key in self.actions: self.actions.remove(key) changed = True if changed and self.isPlayer: self.world.stateChange(json.dumps({"action": [key, value]})) def updateTarget(self): # send P and H self.world.stateChange(json.dumps({"targetRot": self.targetRotation})) def targeting(self, task): pass def move(self, task): if self.body: needH = self.targetRotation[1] h = self.body.getH(render) if abs(needH - h) < 1: self.body.setH(render, needH) else: rot = (needH - h) / abs(needH - h) self.body.setH( self.body, rot * self.gc.getDt() * self.bodyRotate) return super(Player, self).move(task)
class Walker (PhysicalObject): collide_bits = SOLID_COLLIDE_BIT def __init__(self, incarnator, colordict=None, player=False): super(Walker, self).__init__() self.spawn_point = incarnator self.on_ground = False self.mass = 150.0 # 220.0 for heavy self.xz_velocity = Vec3(0, 0, 0) self.y_velocity = Vec3(0, 0, 0) self.factors = { 'forward': 7.5, 'backward': -7.5, 'left': 2.0, 'right': -2.0, 'crouch': 0.0, } self.movement = { 'forward': 0.0, 'backward': 0.0, 'left': 0.0, 'right': 0.0, 'crouch': 0.0, } self.head_height = Vec3(0, 1.5, 0) self.collides_with = MAP_COLLIDE_BIT | SOLID_COLLIDE_BIT self.grenade_loaded = False self.energy = 1.0 self.left_gun_charge = 1.0 self.right_gun_charge = 1.0 self.primary_color = [1,1,1,1] self.colordict = colordict if colordict else None self.crouching = False self.player = player self.can_jump = False self.crouch_impulse = 0 def get_model_part(self, obj_name): return self.actor.find("**/%s" % obj_name) def create_node(self): self.actor = Actor('walker.egg') if self.colordict: self.setup_color(self.colordict) self.actor.set_pos(*self.spawn_point.pos) self.actor.look_at(*self.spawn_point.heading) self.spawn_point.was_used() self.left_barrel_joint = self.actor.exposeJoint(None, 'modelRoot', 'left_barrel_bone') self.right_barrel_joint = self.actor.exposeJoint(None, 'modelRoot', 'right_barrel_bone') return self.actor def create_solid(self): walker_capsule = BulletGhostNode(self.name + "_walker_cap") self.walker_capsule_shape = BulletCylinderShape(.7, .2, YUp) walker_bullet_np = self.actor.attach_new_node(walker_capsule) walker_bullet_np.node().add_shape(self.walker_capsule_shape) walker_bullet_np.node().set_kinematic(True) walker_bullet_np.set_pos(0,1.5,0) walker_bullet_np.wrt_reparent_to(self.actor) self.world.physics.attach_ghost(walker_capsule) walker_bullet_np.node().setIntoCollideMask(GHOST_COLLIDE_BIT) return None def setup_shape(self, gnodepath, bone, pname): shape = BulletConvexHullShape() gnode = gnodepath.node() geom = gnode.get_geom(0) shape.add_geom(geom) node = BulletRigidBodyNode(self.name + pname) np = self.actor.attach_new_node(node) np.node().add_shape(shape) np.node().set_kinematic(True) np.wrt_reparent_to(bone) self.world.physics.attach_rigid_body(node) return np def setup_color(self, colordict): if colordict.has_key('barrel_color'): color = colordict['barrel_color'] self.get_model_part('left_barrel').setColor(*color) self.get_model_part('right_barrel').setColor(*color) if colordict.has_key('visor_color'): self.get_model_part('visor').setColor(*colordict['visor_color']) if colordict.has_key('body_primary_color'): color = colordict['body_primary_color'] self.primary_color = color for part in ['hull_primary', 'rt_leg_primary', 'lt_leg_primary', 'lb_leg_primary', 'rb_leg_primary', 'left_barrel_ring', 'right_barrel_ring', 'hull_bottom']: self.get_model_part(part).setColor(*color) if colordict.has_key('body_secondary_color'): color = colordict['body_secondary_color'] for part in ['hull_secondary', 'visor_stripe', 'rb_leg_secondary', 'rt_leg_secondary', 'lb_leg_secondary', 'lt_leg_secondary']: self.get_model_part(part).setColor(*color) return def attached(self): self.integrator = Integrator(self.world.gravity) #self.world.register_collider(self) self.world.register_updater(self) pelvis_bone = self.actor.controlJoint(None, 'modelRoot', 'pelvis_bone') left_foot_bone = self.actor.exposeJoint(None, 'modelRoot', 'left_foot_bone') left_foot_bone_origin_ref = self.actor.attach_new_node("left_foot_reference") left_foot_bone_origin_ref.set_pos(left_foot_bone.get_pos()) #pelvis_bone.attach_new_node(left_foot_bone_origin_ref) right_foot_bone = self.actor.exposeJoint(None, 'modelRoot', 'right_foot_bone') right_foot_bone_origin_ref = self.actor.attach_new_node("right_foot_reference") right_foot_bone_origin_ref.set_pos(right_foot_bone.get_pos()) #pelvis_bone.attach_new_node(right_foot_bone_origin_ref) left_bones = LegBones( self.world.scene, self.world.physics, self.actor.exposeJoint(None, 'modelRoot', 'left_hip_bone'), left_foot_bone, left_foot_bone_origin_ref, *[self.actor.controlJoint(None, 'modelRoot', name) for name in ['left_top_bone', 'left_bottom_bone']] ) right_bones = LegBones( self.world.scene, self.world.physics, self.actor.exposeJoint(None, 'modelRoot', 'right_hip_bone'), right_foot_bone, right_foot_bone_origin_ref, *[self.actor.controlJoint(None, 'modelRoot', name) for name in ['right_top_bone', 'right_bottom_bone']] ) self.skeleton = Skeleton(left_bones, right_bones, pelvis_bone) self.skeleton.setup_footsteps(self.world.audio3d) self.head_bone = self.actor.controlJoint(None, 'modelRoot', 'head_bone') self.head_bone_joint = self.actor.exposeJoint(None, 'modelRoot', 'head_bone') self.loaded_missile = LoadedMissile(self.head_bone_joint, self.primary_color) self.loaded_grenade = LoadedGrenade(self.head_bone_joint, self.primary_color) if self.player: self.sights = Sights(self.left_barrel_joint, self.right_barrel_joint, self.world) def collision(self, other, manifold, first): world_pt = manifold.get_position_world_on_a() if first else manifold.get_position_world_on_b() print self, 'HIT BY', other, 'AT', world_pt def handle_command(self, cmd, pressed): if cmd is 'crouch' and pressed: self.crouching = True if self.on_ground: self.can_jump = True if cmd is 'crouch' and not pressed and self.on_ground and self.can_jump: self.crouching = False self.y_velocity = Vec3(0, 6.8, 0) self.can_jump = False if cmd is 'fire' and pressed: self.handle_fire() return if cmd is 'missile' and pressed: if self.loaded_grenade.can_fire(): self.loaded_grenade.toggle_visibility() self.loaded_missile.toggle_visibility() return if cmd is 'grenade' and pressed: if self.loaded_missile.can_fire(): self.loaded_missile.toggle_visibility() self.loaded_grenade.toggle_visibility() return if cmd is 'grenade_fire' and pressed: if self.loaded_missile.can_fire(): self.loaded_missile.toggle_visibility() if not self.loaded_grenade.can_fire(): self.loaded_grenade.toggle_visibility() walker_v = Vec3(self.xz_velocity) walker_v.y = self.y_velocity.y self.loaded_grenade.fire(self.world, walker_v) return self.movement[cmd] = self.factors[cmd] if pressed else 0.0 def handle_fire(self): if self.loaded_missile.can_fire(): self.loaded_missile.fire(self.world) elif self.loaded_grenade.can_fire(): walker_v = self.xz_velocity walker_v.y = self.y_velocity.y self.loaded_grenade.fire(self.world, walker_v) else: p_energy = 0 hpr = 0 if self.left_gun_charge > self.right_gun_charge: origin = self.left_barrel_joint.get_pos(self.world.scene) hpr = self.left_barrel_joint.get_hpr(self.world.scene) p_energy = self.left_gun_charge if p_energy < MIN_PLASMA_CHARGE: return self.left_gun_charge = 0 else: origin = self.right_barrel_joint.get_pos(self.world.scene) hpr = self.right_barrel_joint.get_hpr(self.world.scene) p_energy = self.right_gun_charge if p_energy < MIN_PLASMA_CHARGE: return self.right_gun_charge = 0 hpr.y += 180 plasma = self.world.attach(Plasma(origin, hpr, p_energy)) def st_result(self, cur_pos, new_pos): return self.world.physics.sweepTestClosest(self.walker_capsule_shape, cur_pos, new_pos, self.collides_with, 0) def update(self, dt): dt = min(dt, 0.2) # let's just temporarily assume that if we're getting less than 5 fps, dt must be wrong. yaw = self.movement['left'] + self.movement['right'] self.rotate_by(yaw * dt * 60, 0, 0) walk = self.movement['forward'] + self.movement['backward'] start = self.position() cur_pos_ts = TransformState.make_pos(self.position() + self.head_height) if self.on_ground: friction = DEFAULT_FRICTION else: friction = AIR_FRICTION #to debug walk cycle (stay in place) #riction = 0 speed = walk pos = self.position() self.move_by(0, 0, speed) direction = self.position() - pos newpos, self.xz_velocity = Friction(direction, friction).integrate(pos, self.xz_velocity, dt) self.move(newpos) # Cast a ray from just above our feet to just below them, see if anything hits. pt_from = self.position() + Vec3(0, 1, 0) pt_to = pt_from + Vec3(0, -1.1, 0) result = self.world.physics.ray_test_closest(pt_from, pt_to, MAP_COLLIDE_BIT | SOLID_COLLIDE_BIT) # this should return 'on ground' information self.skeleton.update_legs(walk, dt, self.world.scene, self.world.physics) if self.y_velocity.get_y() <= 0 and result.has_hit(): self.on_ground = True self.crouch_impulse = self.y_velocity.y self.y_velocity = Vec3(0, 0, 0) self.move(result.get_hit_pos()) self.skeleton.left_leg_on_ground = True self.skeleton.right_leg_on_ground = True else: self.on_ground = False current_y = Point3(0, self.position().get_y(), 0) y, self.y_velocity = self.integrator.integrate(current_y, self.y_velocity, dt) self.move(self.position() + (y - current_y)) if self.crouching and self.skeleton.crouch_factor < 1: self.skeleton.crouch_factor += (dt*60)/10 self.skeleton.update_legs(0, dt, self.world.scene, self.world.physics) elif not self.crouching and self.skeleton.crouch_factor > 0: self.skeleton.crouch_factor -= (dt*60)/10 self.skeleton.update_legs(0, dt, self.world.scene, self.world.physics) #if self.crouch_impulse < 0: goal = self.position() adj_dist = abs((start - goal).length()) new_pos_ts = TransformState.make_pos(self.position() + self.head_height) sweep_result = self.st_result(cur_pos_ts, new_pos_ts) count = 0 while sweep_result.has_hit() and count < 10: moveby = sweep_result.get_hit_normal() self.xz_velocity = -self.xz_velocity.cross(moveby).cross(moveby) moveby.normalize() moveby *= adj_dist * (1 - sweep_result.get_hit_fraction()) self.move(self.position() + moveby) new_pos_ts = TransformState.make_pos(self.position() + self.head_height) sweep_result = self.st_result(cur_pos_ts, new_pos_ts) count += 1 if self.energy > WALKER_MIN_CHARGE_ENERGY: if self.left_gun_charge < 1: self.energy -= WALKER_ENERGY_TO_GUN_CHARGE[0] self.left_gun_charge += WALKER_ENERGY_TO_GUN_CHARGE[1] else: self.left_gun_charge = math.floor(self.left_gun_charge) if self.right_gun_charge < 1: self.energy -= WALKER_ENERGY_TO_GUN_CHARGE[0] self.right_gun_charge += WALKER_ENERGY_TO_GUN_CHARGE[1] else: self.right_gun_charge = math.floor(self.right_gun_charge) if self.energy < 1: self.energy += WALKER_RECHARGE_FACTOR * (dt) if self.player: self.sights.update(self.left_barrel_joint, self.right_barrel_joint)
class Me(DirectObject): """Testing self controlled player, can be build upon""" def __init__(self): self.model = Actor("assets/models/ninja", {"walk": "assets/models/ninja"}) self.actorHead = self.model.exposeJoint(None, 'modelRoot', 'Joint8') # self.model.setScale(4) self.username = input("Input username: \n") self.player_id = None self.Dt_update = self.Dt = 0 self.model.reparentTo(base.render) self.model.setScale(0.5) self.moving = False self.AnimControl = self.model.getAnimControl('walk') self.AnimControl.setPlayRate(0.05) self.model.setBlend(frameBlend=1) self.model.setPos(244, 188, 0) # STORE TERRAIN SCALE FOR LATER USE# self.terrainScale = terrain.terrain.getRoot().getSz() base.camera.reparentTo(self.model) self.camDummy = self.model.attachNewNode("camDummy") self.camDummy.setZ(5) def move(self, arg): # self.meTerrainHeight = terrainClass.terrain.getElevation(self.model.getX(),self.model.getY()) * self.terrainScale # self.camTerrainHeight = terrainClass.terrain.getElevation(camera.getX(),camera.getY()) * self.terrainScale self.Dt = globalClock.getDt() # base.camera.lookAt(self.actorHead) if keys.keyMap["left"] != 0: self.model.setH(self.model.getH() + self.Dt * 300) logging.debug(f"{self.model.getY()}, {self.model.getX()}") if keys.keyMap["right"] != 0: self.model.setH(self.model.getH() - self.Dt * 300) if keys.keyMap["forward"] != 0: self.model.setY(self.model, (self.Dt * 40)) if keys.keyMap["back"] != 0: self.model.setY(self.model, -(self.Dt * 40)) if (keys.keyMap["forward"] != 0) or \ (keys.keyMap["left"] != 0) or \ (keys.keyMap["right"] != 0): if self.moving is False: self.model.loop("walk", fromFrame=1, toFrame=11) self.moving = True else: if self.moving: self.model.stop() self.model.pose("walk", 5) self.moving = False self.meTerrainHeight = terrain.terrain.getElevation( self.model.getX(), self.model.getY()) * self.terrainScale self.model.setZ(self.meTerrainHeight) # base.camera.reparentTo(self.model) base.camera.lookAt(self.camDummy) base.camLens.setNear(.1) if keys.keyMap["cam"] == 1: # base.camera.setZ(5) # base.camera.setY(1) base.disableMouse() base.camera.setPosHpr(0, 2, 5, 0, 0, 0) elif keys.keyMap["cam"] == 2: # base.camera.setPosHpr(0,-30,10,0,0,0) base.enableMouse() else: base.disableMouse() base.camera.setPosHpr(0, -30, 10, 0, 0, 0) # base.camera.setZ(10) # base.camera.setY(-30) return Task.cont
class Walker (PhysicalObject): collide_bits = SOLID_COLLIDE_BIT def __init__(self, incarnator, colordict=None, player=False): super(Walker, self).__init__() self.spawn_point = incarnator self.on_ground = False self.mass = 150.0 # 220.0 for heavy self.xz_velocity = Vec3(0, 0, 0) self.y_velocity = Vec3(0, 0, 0) self.factors = { 'forward': 7.5, 'backward': -7.5, 'left': 2.0, 'right': -2.0, 'crouch': 0.0, } self.movement = { 'forward': 0.0, 'backward': 0.0, 'left': 0.0, 'right': 0.0, 'crouch': 0.0, } self.head_height = Vec3(0, 1.5, 0) self.collides_with = MAP_COLLIDE_BIT | SOLID_COLLIDE_BIT self.grenade_loaded = False self.energy = 1.0 self.left_gun_charge = 1.0 self.right_gun_charge = 1.0 self.primary_color = [1,1,1,1] self.colordict = colordict if colordict else None self.crouching = False self.player = player self.can_jump = False self.crouch_impulse = 0 def get_model_part(self, obj_name): return self.actor.find("**/%s" % obj_name) def create_node(self): self.actor = Actor('walker.egg') if self.colordict: self.setup_color(self.colordict) self.actor.set_pos(*self.spawn_point.pos) self.actor.look_at(*self.spawn_point.heading) self.spawn_point.was_used() self.left_barrel_joint = self.actor.exposeJoint(None, 'modelRoot', 'left_barrel_bone') self.right_barrel_joint = self.actor.exposeJoint(None, 'modelRoot', 'right_barrel_bone') return self.actor def create_solid(self): walker_capsule = BulletGhostNode(self.name + "_walker_cap") self.walker_capsule_shape = BulletCylinderShape(.7, .2, YUp) walker_bullet_np = self.actor.attach_new_node(walker_capsule) walker_bullet_np.node().add_shape(self.walker_capsule_shape) walker_bullet_np.node().set_kinematic(True) walker_bullet_np.set_pos(0,1.5,0) walker_bullet_np.wrt_reparent_to(self.actor) self.world.physics.attach_ghost(walker_capsule) walker_bullet_np.node().setIntoCollideMask(GHOST_COLLIDE_BIT) return None def setup_shape(self, gnodepath, bone, pname): shape = BulletConvexHullShape() gnode = gnodepath.node() geom = gnode.get_geom(0) shape.add_geom(geom) node = BulletRigidBodyNode(self.name + pname) np = self.actor.attach_new_node(node) np.node().add_shape(shape) np.node().set_kinematic(True) np.wrt_reparent_to(bone) self.world.physics.attach_rigid_body(node) return np def setup_color(self, colordict): if colordict.has_key('barrel_color'): color = colordict['barrel_color'] self.get_model_part('left_barrel').setColor(*color) self.get_model_part('right_barrel').setColor(*color) if colordict.has_key('visor_color'): self.get_model_part('visor').setColor(*colordict['visor_color']) if colordict.has_key('body_primary_color'): color = colordict['body_primary_color'] self.primary_color = color for part in ['hull_primary', 'rt_leg_primary', 'lt_leg_primary', 'lb_leg_primary', 'rb_leg_primary', 'left_barrel_ring', 'right_barrel_ring', 'hull_bottom']: self.get_model_part(part).setColor(*color) if colordict.has_key('body_secondary_color'): color = colordict['body_secondary_color'] for part in ['hull_secondary', 'visor_stripe', 'rb_leg_secondary', 'rt_leg_secondary', 'lb_leg_secondary', 'lt_leg_secondary']: self.get_model_part(part).setColor(*color) return def attached(self): self.integrator = Integrator(self.world.gravity) self.world.register_collider(self) self.world.register_updater(self) left_bones = LegBones( self.world.render, self.world.physics, self.actor.exposeJoint(None, 'modelRoot', 'left_hip_bone'), self.actor.exposeJoint(None, 'modelRoot', 'left_foot_bone'), *[self.actor.controlJoint(None, 'modelRoot', name) for name in ['left_top_bone', 'left_bottom_bone']] ) right_bones = LegBones( self.world.render, self.world.physics, self.actor.exposeJoint(None, 'modelRoot', 'right_hip_bone'), self.actor.exposeJoint(None, 'modelRoot', 'right_foot_bone'), *[self.actor.controlJoint(None, 'modelRoot', name) for name in ['right_top_bone', 'right_bottom_bone']] ) self.skeleton = Skeleton(left_bones, right_bones, self.actor.controlJoint(None, 'modelRoot', 'pelvis_bone')) self.skeleton.setup_footsteps(self.world.audio3d) self.head_bone = self.actor.controlJoint(None, 'modelRoot', 'head_bone') self.head_bone_joint = self.actor.exposeJoint(None, 'modelRoot', 'head_bone') self.loaded_missile = Hat(self.head_bone_joint, self.primary_color) self.loaded_grenade = Sack(self.head_bone_joint, self.primary_color) if self.player: self.sights = Sights(self.left_barrel_joint, self.right_barrel_joint, self.world.render, self.world.physics) def collision(self, other, manifold, first): world_pt = manifold.get_position_world_on_a() if first else manifold.get_position_world_on_b() print self, 'HIT BY', other, 'AT', world_pt def handle_command(self, cmd, pressed): if cmd is 'crouch' and pressed: self.crouching = True if self.on_ground: self.can_jump = True if cmd is 'crouch' and not pressed and self.on_ground and self.can_jump: self.crouching = False self.y_velocity = Vec3(0, 6.8, 0) self.can_jump = False if cmd is 'fire' and pressed: self.handle_fire() return if cmd is 'missile' and pressed: if self.loaded_grenade.can_fire(): self.loaded_grenade.toggle_visibility() self.loaded_missile.toggle_visibility() return if cmd is 'grenade' and pressed: if self.loaded_missile.can_fire(): self.loaded_missile.toggle_visibility() self.loaded_grenade.toggle_visibility() return if cmd is 'grenade_fire' and pressed: if self.loaded_missile.can_fire(): self.loaded_missile.toggle_visibility() if not self.loaded_grenade.can_fire(): self.loaded_grenade.toggle_visibility() walker_v = Vec3(self.xz_velocity) walker_v.y = self.y_velocity.y self.loaded_grenade.fire(self.world, walker_v) return self.movement[cmd] = self.factors[cmd] if pressed else 0.0 def handle_fire(self): if self.loaded_missile.can_fire(): self.loaded_missile.fire(self.world) elif self.loaded_grenade.can_fire(): walker_v = self.xz_velocity walker_v.y = self.y_velocity.y self.loaded_grenade.fire(self.world, walker_v) else: p_energy = 0 hpr = 0 if self.left_gun_charge > self.right_gun_charge: origin = self.left_barrel_joint.get_pos(self.world.render) hpr = self.left_barrel_joint.get_hpr(self.world.render) p_energy = self.left_gun_charge if p_energy < MIN_PLASMA_CHARGE: return self.left_gun_charge = 0 else: origin = self.right_barrel_joint.get_pos(self.world.render) hpr = self.right_barrel_joint.get_hpr(self.world.render) p_energy = self.right_gun_charge if p_energy < MIN_PLASMA_CHARGE: return self.right_gun_charge = 0 hpr.y += 180 plasma = self.world.attach(Plasma(origin, hpr, p_energy)) def st_result(self, cur_pos, new_pos): return self.world.physics.sweepTestClosest(self.walker_capsule_shape, cur_pos, new_pos, self.collides_with, 0) def update(self, dt): dt = min(dt, 0.2) # let's just temporarily assume that if we're getting less than 5 fps, dt must be wrong. yaw = self.movement['left'] + self.movement['right'] self.rotate_by(yaw * dt * 60, 0, 0) walk = self.movement['forward'] + self.movement['backward'] start = self.position() cur_pos_ts = TransformState.make_pos(self.position() + self.head_height) if self.on_ground: friction = DEFAULT_FRICTION else: friction = AIR_FRICTION speed = walk pos = self.position() self.move_by(0, 0, speed) direction = self.position() - pos newpos, self.xz_velocity = Friction(direction, friction).integrate(pos, self.xz_velocity, dt) self.move(newpos) # Cast a ray from just above our feet to just below them, see if anything hits. pt_from = self.position() + Vec3(0, 1, 0) pt_to = pt_from + Vec3(0, -1.1, 0) result = self.world.physics.ray_test_closest(pt_from, pt_to, MAP_COLLIDE_BIT | SOLID_COLLIDE_BIT) #this should return 'on ground' information self.skeleton.update_legs(walk, dt, self.world.render, self.world.physics) if self.y_velocity.get_y() <= 0 and result.has_hit(): self.on_ground = True self.crouch_impulse = self.y_velocity.y self.y_velocity = Vec3(0, 0, 0) self.move(result.get_hit_pos()) else: self.on_ground = False current_y = Point3(0, self.position().get_y(), 0) y, self.y_velocity = self.integrator.integrate(current_y, self.y_velocity, dt) self.move(self.position() + (y - current_y)) if self.crouching and self.skeleton.crouch_factor < 1: self.skeleton.crouch_factor += (dt*60)/10 self.skeleton.update_legs(0, dt, self.world.render, self.world.physics) elif not self.crouching and self.skeleton.crouch_factor > 0: self.skeleton.crouch_factor -= (dt*60)/10 self.skeleton.update_legs(0, dt, self.world.render, self.world.physics) #if self.crouch_impulse < 0: goal = self.position() adj_dist = abs((start - goal).length()) new_pos_ts = TransformState.make_pos(self.position() + self.head_height) sweep_result = self.st_result(cur_pos_ts, new_pos_ts) count = 0 while sweep_result.has_hit() and count < 10: moveby = sweep_result.get_hit_normal() self.xz_velocity = -self.xz_velocity.cross(moveby).cross(moveby) moveby.normalize() moveby *= adj_dist * (1 - sweep_result.get_hit_fraction()) self.move(self.position() + moveby) new_pos_ts = TransformState.make_pos(self.position() + self.head_height) sweep_result = self.st_result(cur_pos_ts, new_pos_ts) count += 1 if self.energy > WALKER_MIN_CHARGE_ENERGY: if self.left_gun_charge < 1: self.energy -= WALKER_ENERGY_TO_GUN_CHARGE[0] self.left_gun_charge += WALKER_ENERGY_TO_GUN_CHARGE[1] else: self.left_gun_charge = math.floor(self.left_gun_charge) if self.right_gun_charge < 1: self.energy -= WALKER_ENERGY_TO_GUN_CHARGE[0] self.right_gun_charge += WALKER_ENERGY_TO_GUN_CHARGE[1] else: self.right_gun_charge = math.floor(self.right_gun_charge) if self.energy < 1: self.energy += WALKER_RECHARGE_FACTOR * (dt) if self.player: self.sights.update(self.left_barrel_joint, self.right_barrel_joint)
class Transporter(): def __init__(self, name, aiworld, tradeMap, position=Vec3(-10, 0, 0)): self.name = name self.aiworld = aiworld self.tradeMap = tradeMap self.model = Actor("models/ralph", {"run": "models/ralph-run"}) self.model.reparentTo(render) self.model.setScale(0.5) self.model.setPos(position) self.model.loop("run") self.radius = getRadius(self.model) self.rightHand = self.model.exposeJoint(None, 'modelRoot', 'RightHand') self.cargo = 0 self.money = 10 self.tradeRoute = None self.goal = None self.initAI() def initAI(self): self.ai = AICharacter(self.name, self.model, 100, 10, 10) self.aiworld.addAiChar(self.ai) self.behaviors = self.ai.getAiBehaviors() self.behaviors.obstacleAvoidance(1.0) self.aiworld.addObstacle(self.model) taskMgr.doMethodLater(0.5, self.updateAI, "transporter ai") def buy(self, factory): '''Buy one product from input factory if possible.''' if factory.canSell(): factory.product -= 1 factory.updateDisplay() self.grab(Cargo(factory.productType)) return True return False def sell(self, factory): '''Sell one product to input factory if possible.''' if factory.canBuy(): factory.resource += 1 factory.updateDisplay() self.drop() return True return False def grab(self, cargo): cargo.carryOn(self.rightHand) self.cargo = cargo def drop(self): self.cargo.drop() self.cargo = None def findTradeRoute(self): '''Find the best (shortest) trade route from our current position. Currently uses only distance. ''' lowestDistance = 9999999999 bestRoute = None distance = lowestDistance for x in self.tradeMap.routes: if x.open: distance = x.distance + getXYDistance(self.model, x.start.productNP) if distance < lowestDistance: bestRoute = x lowestDistance = distance return bestRoute def findBuyer(self): '''We have a product, so we don't need a complete trade route. Just find the best (closest) buyer for our product.''' if not self.cargo: return lowestDistance = 9999999999 bestBuyer = None for x in self.tradeMap.factories: if x.canBuy(): if x.resourceType == self.cargo: distance = getXYDistance(self.model, x.resourceNP) if distance < lowestDistance: bestBuyer = x lowestDistance = distance return bestBuyer def setGoal(self, goal): self.goal = goal if not goal == None: print self.name, "'s goal: ", self.goal.name else: print self.name, "'s goal: None" def stop(self): self.behaviors.removeAi("seek") def updateAI(self, task): #self.stop() # If ai has no current goal, try to find one. if (self.goal == None): if (self.tradeRoute == None): self.tradeRoute = self.findTradeRoute() if (self.tradeRoute == None): return Task.again if (self.cargo): self.setGoal(self.tradeRoute.end) else: self.setGoal(self.tradeRoute.start) # If we still don't have a goal just try again later. if (self.goal == None): return Task.again if (self.cargo): # We have the product. Go to resource point for trade route ending. dockingDistance = self.radius + self.goal.getResourceRadius() if (getXYDistance(self.model, self.goal.resourceNP) > dockingDistance): self.behaviors.seek(self.goal.resourceNP, 0.5) else: self.tradeRoute = None if self.sell(self.goal): self.setGoal(None) else: self.setGoal(self.findBuyer()) else: # We have no product. Go to product point of trade route start. dockingDistance = self.radius + self.goal.getProductRadius() if (getXYDistance(self.model, self.goal.productNP) > dockingDistance): self.behaviors.seek(self.goal.productNP, 0.5) else: if not self.buy(self.goal): self.tradeRoute = None self.setGoal(None) return Task.again
class LookingGrippingDemo(ShowBase): def __init__(self): # Initialize the ShowBase class from which we inherit, which will # create a window and set up everything we need for rendering into it. ShowBase.__init__(self) # This code puts the standard title and instruction text on screen self.title = OnscreenText( text="Panda3D: Tutorial - Joint Manipulation", fg=(1, 1, 1, 1), parent=base.a2dBottomRight, align=TextNode.ARight, pos=(-0.1, 0.1), shadow=(0, 0, 0, .5), scale=.08) self.onekeyText = genLabelText("ESC: Quit", 1) self.onekeyText = genLabelText("[1]: Teapot", 2) self.twokeyText = genLabelText("[2]: Candy cane", 3) self.threekeyText = genLabelText("[3]: Banana", 4) self.fourkeyText = genLabelText("[4]: Sword", 5) # Set up key input self.accept('escape', sys.exit) self.accept('1', self.switchObject, [0]) self.accept('2', self.switchObject, [1]) self.accept('3', self.switchObject, [2]) self.accept('4', self.switchObject, [3]) base.disableMouse() # Disable mouse-based camera-control camera.setPos(0, -15, 2) # Position the camera self.eve = Actor( "models/eve", # Load our animated charachter {'walk': "models/eve_walk"}) self.eve.reparentTo(render) # Put it in the scene # Now we use controlJoint to get a NodePath that's in control of her neck # This must be done before any animations are played self.eveNeck = self.eve.controlJoint(None, 'modelRoot', 'Neck') # We now play an animation. An animation must be played, or at least posed # for the nodepath we just got from controlJoint to actually effect the # model self.eve.actorInterval("walk", playRate=2).loop() # Now we add a task that will take care of turning the head taskMgr.add(self.turnHead, "turnHead") # Now we will expose the joint the hand joint. ExposeJoint allows us to # get the position of a joint while it is animating. This is different than # controlJonit which stops that joint from animating but lets us move it. # This is particularly usefull for putting an object (like a weapon) in an # actor's hand self.rightHand = self.eve.exposeJoint(None, 'modelRoot', 'RightHand') # This is a table with models, positions, rotations, and scales of objects to # be attached to our exposed joint. These are stock models and so they needed # to be repositioned to look right. positions = [("teapot", (0, -.66, -.95), (90, 0, 90), .4), ("models/candycane", (.15, -.99, -.22), (90, 0, 90), 1), ("models/banana", (.08, -.1, .09), (0, -90, 0), 1.75), ("models/sword", (.11, .19, .06), (0, 0, 90), 1)] self.models = [] # A list that will store our models objects for row in positions: np = loader.loadModel(row[0]) # Load the model np.setPos(row[1][0], row[1][1], row[1][2]) # Position it np.setHpr(row[2][0], row[2][1], row[2][2]) # Rotate it np.setScale(row[3]) # Scale it # Reparent the model to the exposed joint. That way when the joint moves, # the model we just loaded will move with it. np.reparentTo(self.rightHand) self.models.append(np) # Add it to our models list self.switchObject(0) # Make object 0 the first shown self.setupLights() # Put in some default lighting # This is what we use to change which object it being held. It just hides all of # the objects and then unhides the one that was selected def switchObject(self, i): for np in self.models: np.hide() self.models[i].show() # This task gets the position of mouse each frame, and rotates the neck based # on it. def turnHead(self, task): # Check to make sure the mouse is readable if base.mouseWatcherNode.hasMouse(): # get the mouse position as a LVector2. The values for each axis are from -1 to # 1. The top-left is (-1,-1), the bottom right is (1,1) mpos = base.mouseWatcherNode.getMouse() # Here we multiply the values to get the amount of degrees to turn # Restrain is used to make sure the values returned by getMouse are in the # valid range. If this particular model were to turn more than this, # significant tearing would be visable self.eveNeck.setP(clamp(mpos.getX()) * 50) self.eveNeck.setH(clamp(mpos.getY()) * 20) return Task.cont # Task continues infinitely def setupLights(self): # Sets up some default lighting ambientLight = AmbientLight("ambientLight") ambientLight.setColor((.4, .4, .35, 1)) directionalLight = DirectionalLight("directionalLight") directionalLight.setDirection(LVector3(0, 8, -2.5)) directionalLight.setColor((0.9, 0.8, 0.9, 1)) render.setLight(render.attachNewNode(directionalLight)) render.setLight(render.attachNewNode(ambientLight))
class MayaDemo(ShowBase): R_LEG_JOINTS = ["joint6", "joint7", "joint8"] L_LEG_JOINTS = ["joint10", "joint11", "joint12"] def __init__(self): ShowBase.__init__(self) self.bandit = Actor("banditRiggedNoHat.egg") self.bandit.makeSubpart("r_leg", self.R_LEG_JOINTS) self.bandit.makeSubpart("l_leg", self.L_LEG_JOINTS) headJoint = self.bandit.exposeJoint(None, "modelRoot", "joint5") hat = loader.loadModel("{}_hat.egg".format(random.randint(0, 7))) hat.setPos(0, 0, -0.08) hat.setHpr(-90, 0, 0) hat.setScale(0.35) hat.reparentTo(headJoint) self.bandit.reparentTo(render) r_hip_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[0]) r_hip_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[0]) r_knee_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[1]) r_knee_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[1]) r_ankle_ro = self.bandit.exposeJoint(None, "modelRoot", self.R_LEG_JOINTS[2]) r_ankle_wo = self.bandit.controlJoint(None, "modelRoot", self.R_LEG_JOINTS[2]) distances = np.array([r_hip_ro.getDistance(r_knee_ro), r_knee_ro.getDistance(r_ankle_ro)]) self.r_leg = Leg.Leg(r_hip_ro, r_hip_wo, r_knee_ro, r_knee_wo, r_ankle_ro, r_ankle_wo, distances) l_hip = self.bandit.controlJoint(None, "modelRoot", self.L_LEG_JOINTS[0]) l_knee = self.bandit.controlJoint(None, "modelRoot", self.L_LEG_JOINTS[1]) l_ankle = self.bandit.exposeJoint(None, "modelRoot", self.L_LEG_JOINTS[2]) distances = np.array([l_hip.getDistance(l_knee), l_knee.getDistance(l_ankle)]) #self.l_leg = Leg.Leg(l_hip, l_knee, l_ankle, distances) self.accept("arrow_up", self.r_leg.moveAnkle, [(0, 0, 0.1)]) self.accept("arrow_down", self.r_leg.moveAnkle, [(0, 0, -0.1)]) self.accept("arrow_left", self.r_leg.rotateAnkle, [(0, 0, 10)]) self.accept("arrow_right", self.r_leg.rotateAnkle, [(0, 0, -10)]) # Draws debug skeleton self.bandit.setBin('background', 1) self.walkJointHierarchy(self.bandit, self.bandit.getPartBundle('modelRoot')) self.stream = StreamRead("/dev/input/smartshoes") self.last_t = time.time() taskMgr.add(self.getDeviceData, 'Stream reader') def getDeviceData(self, task): records = self.stream.readFromStream() if records and len(records[0]) == 10: records = map(float, records[0]) angular_velocity, acceleration, magnetic_field = [records[x:x+3] for x in range(0, 9, 3)] # Switch axis orientations angular_velocity[2], angular_velocity[0] = angular_velocity[0], angular_velocity[2] acceleration[2], acceleration[0] = acceleration[0], acceleration[2] magnetic_field[2], magnetic_field[0] = magnetic_field[0], magnetic_field[2] self.r_leg.ankle_rotation.rotationMagic(records[9], angular_velocity, acceleration, magnetic_field) self.r_leg.updateAnkleRotation() return task.again def walkJointHierarchy(self, actor, part, parentNode = None, indent = ""): if isinstance(part, CharacterJoint): np = actor.exposeJoint(None, 'modelRoot', part.getName()) if parentNode and parentNode.getName() != "root": lines = LineSegs() lines.setThickness(3.0) lines.setColor(random.random(), random.random(), random.random()) lines.moveTo(0, 0, 0) lines.drawTo(np.getPos(parentNode)) lnp = parentNode.attachNewNode(lines.create()) lnp.setBin("fixed", 40) lnp.setDepthWrite(False) lnp.setDepthTest(False) parentNode = np for child in part.getChildren(): self.walkJointHierarchy(actor, child, parentNode, indent + " ")
class ToonFPS(DirectObject): notify = directNotify.newCategory('ToonFPS') WeaponName2DamageData = {'pistol': (36.0, 10.0, 150.0, 0.25), 'shotgun': (40.0, 15.0, 155.0, 0.5)} def __init__(self, mg, weaponName = 'pistol'): self.mg = mg self.weaponName = weaponName self.v_model_root = None self.v_model = None self.weapon = None self.track = None self.draw = None self.shoot = None self.reload = None self.empty = None self.cockBack = None self.cockFwd = None self.player_node = None self.shooterTrav = None self.shooterRay = None self.shooterRayNode = None self.shooterHandler = None self.gui = ToonFPSGui(self) self.fsm = ClassicFSM('ToonFPS', [State('off', self.enterOff, self.exitOff), State('alive', self.enterAlive, self.exitAlive), State('dead', self.enterDead, self.exitDead)], 'off', 'off') self.aliveFSM = ClassicFSM('alive', [State('off', self.enterOff, self.exitOff), State('draw', self.enterDraw, self.exitDraw, ['idle']), State('idle', self.enterIdle, self.exitIdle, ['shoot', 'reload']), State('shoot', self.enterShoot, self.exitShoot, ['idle']), State('reload', self.enterReload, self.exitReload, ['idle'])], 'off', 'off') self.fsm.getStateNamed('alive').addChild(self.aliveFSM) self.fsm.enterInitialState() self.aliveFSM.enterInitialState() if self.weaponName == 'pistol': self.ammo = 14 elif self.weaponName == 'shotgun': self.ammo = 7 self.hp = 125 self.max_hp = 125 self.firstPerson = FirstPerson() return def movementTask(self, task): if not inputState.isSet('jump') and not base.localAvatar.walkControls.isAirborne and inputState.isSet('forward') or inputState.isSet('reverse') or inputState.isSet('slideLeft') or inputState.isSet('slideRight'): if base.localAvatar.getAnimState() != 'run': base.localAvatar.setAnimState('run') base.localAvatar.playMovementSfx('run') self.mg.sendUpdate('runningAvatar', [base.localAvatar.doId]) elif inputState.isSet('jump') or base.localAvatar.walkControls.isAirborne: if base.localAvatar.getAnimState() != 'jump': base.localAvatar.setAnimState('jump') base.localAvatar.playMovementSfx(None) self.mg.sendUpdate('jumpingAvatar', [base.localAvatar.doId]) elif base.localAvatar.getAnimState() != 'neutral': base.localAvatar.setAnimState('neutral') base.localAvatar.playMovementSfx(None) self.mg.sendUpdate('standingAvatar', [base.localAvatar.doId]) return Task.cont def enterAlive(self): if self.mg.fsm.getCurrentState().getName() not in ('gameOver', 'announceGameOver', 'finalScores'): base.localAvatar.disableChatInput() self.start() self.resetHp() self.resetAmmo() if self.mg.fsm.getCurrentState().getName() == 'play': self.reallyStart() def exitAlive(self): self.end() self.v_model.reparentTo(hidden) if self.mg.fsm.getCurrentState().getName() != 'play': self.reallyEnd() base.localAvatar.createChatInput() def updatePoints(self): self.points = self.kills - self.deaths def enterDead(self, killer): base.localAvatar.getGeomNode().show() self.gui.end() base.localAvatar.attachCamera() self.freezeCamSfx = base.loadSfx('phase_4/audio/sfx/freeze_cam.wav') self.freezeCamImage = None self.freezeCamImageFile = None base.camera.setZ(base.camera.getZ() + 2.0) taskMgr.add(self.cameraLookAtKillerTask, 'lookAtKiller', extraArgs=[killer], appendTask=True) taskMgr.doMethodLater(2.0, self.startZoomOnKiller, 'startFreezeCam', extraArgs=[killer], appendTask=True) return def startZoomOnKiller(self, killer, task): taskMgr.add(self.__zoomOnKillerTask, 'zoomOnKiller', extraArgs=[killer], appendTask=True) return task.done def __zoomOnKillerTask(self, killer, task): if base.camera.getDistance(killer) <= 10.0 and self.freezeCamSfx.status() == self.freezeCamSfx.READY: base.playSfx(self.freezeCamSfx) if base.camera.getDistance(killer) < 7.0: self.doFreezeCam() return task.done base.camera.setY(base.camera, 60 * globalClock.getDt()) return task.again def doFreezeCam(self): taskMgr.remove('lookAtKiller') self.frameBuffer = PNMImage() base.win.getScreenshot(self.frameBuffer) self.freezeCamTex = Texture() self.freezeCamTex.load(self.frameBuffer) self.freezeCamImage = OnscreenImage(image=self.freezeCamTex, parent=render2d) def cameraLookAtKillerTask(self, killer, task): base.camera.lookAt(killer, 0, 0, 3) return task.cont def exitDead(self): taskMgr.remove('zoomOnKiller') taskMgr.remove('lookAtKiller') taskMgr.remove('startFreezeCam') del self.freezeCamSfx if self.freezeCamImage: self.freezeCamImage.destroy() del self.freezeCamImage self.frameBuffer.clear() self.freezeCamTex.clear() del self.frameBuffer del self.freezeCamTex base.localAvatar.detachCamera() base.localAvatar.getGeomNode().hide() self.gui.start() def load(self): if self.weaponName == 'pistol': self.draw = base.loadSfx('phase_4/audio/sfx/draw_secondary.wav') self.shoot = base.loadSfx('phase_4/audio/sfx/pistol_shoot.wav') self.reload = base.loadSfx('phase_4/audio/sfx/pistol_worldreload.wav') elif self.weaponName == 'shotgun': self.draw = base.loadSfx('phase_4/audio/sfx/draw_primary.wav') self.shoot = base.loadSfx('phase_4/audio/sfx/shotgun_shoot.wav') self.cockBack = base.loadSfx('phase_4/audio/sfx/shotgun_cock_back.wav') self.cockFwd = base.loadSfx('phase_4/audio/sfx/shotgun_cock_forward.wav') self.empty = base.loadSfx('phase_4/audio/sfx/shotgun_empty.wav') self.v_model_root = base.camera.attachNewNode('v_model_root') self.v_model = Actor('phase_4/models/minigames/v_dgm.egg', {'pidle': 'phase_4/models/minigames/v_dgm-pistol-idle.egg', 'pshoot': 'phase_4/models/minigames/v_dgm-pistol-shoot.egg', 'preload': 'phase_4/models/minigames/v_dgm-pistol-reload.egg', 'pdraw': 'phase_4/models/minigames/v_dgm-pistol-draw.egg', 'sidle': 'phase_4/models/minigames/v_dgm-shotgun-idle.egg', 'sshoot': 'phase_4/models/minigames/v_dgm-shotgun-shoot.egg'}) if self.weaponName == 'pistol': self.weapon = loader.loadModel('phase_4/models/props/water-gun.bam') self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.011')) self.weapon.setX(-0.125) self.weapon.setY(0.5) self.weapon.setScale(0.65) elif self.weaponName == 'shotgun': self.weapon = loader.loadModel('phase_4/models/props/shotgun.egg') self.weapon.reparentTo(self.v_model.exposeJoint(None, 'modelRoot', 'Bone.029')) self.weapon.setScale(0.75) self.weapon.setPos(0.45, -1.03, -1.17) self.weapon.setHpr(9.46, 308.19, 75.78) color = random.choice([VBase4(1, 0.25, 0.25, 1), VBase4(0.25, 1, 0.25, 1), VBase4(0.25, 0.25, 1, 1)]) self.weapon.setColorScale(color) self.gui.load() return def start(self): base.camLens.setNear(0.1) self.shooterTrav = CollisionTraverser('ToonFPS.shooterTrav') ray = CollisionRay() rayNode = CollisionNode('ToonFPS.rayNode') rayNode.addSolid(ray) rayNode.setCollideMask(BitMask32(0)) rayNode.setFromCollideMask(CIGlobals.WallBitmask | CIGlobals.FloorBitmask) self.shooterRay = ray self.shooterRayNode = base.camera.attachNewNode(rayNode) self.shooterHandler = CollisionHandlerQueue() self.shooterTrav.addCollider(self.shooterRayNode, self.shooterHandler) self.firstPerson.start() self.v_model_root.reparentTo(base.camera) self.v_model.reparentTo(self.v_model_root) if self.weaponName == 'pistol': self.v_model_root.setZ(-1.8) self.v_model_root.setY(0.3) self.v_model_root.setX(-0.1) self.v_model_root.setH(2) elif self.weaponName == 'shotgun': self.v_model_root.setPos(-0.42, -0.81, -1.7) self.v_model_root.setHpr(359, 352.87, 0.0) self.gui.start() self.firstPerson.disableMouse() self.aliveFSM.request('draw') def reallyStart(self): self.firstPerson.reallyStart() taskMgr.add(self.movementTask, 'toonBattleMovement') def end(self): self.aliveFSM.request('off') if self.firstPerson: self.firstPerson.enableMouse() self.firstPerson.end() taskMgr.remove('toonBattleMovement') if self.mg.fsm.getCurrentState().getName() != 'play': self.fsm.request('off') def reallyEnd(self): if self.shooterRayNode: self.shooterRayNode.removeNode() self.shooterRayNode = None self.shooterRay = None self.shooterTrav = None self.shooterHandler = None if self.firstPerson: self.firstPerson.reallyEnd() if self.v_model_root: self.v_model_root.reparentTo(hidden) if self.v_model: self.v_model.reparentTo(hidden) self.v_model.setPosHpr(0, 0, 0, 0, 0, 0) if self.gui: self.gui.end() base.camLens.setNear(1.0) return def cleanup(self): taskMgr.remove('lookAtKiller') taskMgr.remove('toonBattleMovement') if self.firstPerson: self.firstPerson.cleanup() self.firstPerson = None self.draw = None self.shoot = None self.reload = None self.empty = None self.ammo = None self.fsm = None self.aliveFSM = None self.player_node = None self.min_camerap = None self.max_camerap = None self.hp = None self.max_hp = None if self.v_model: self.v_model.cleanup() self.v_model = None if self.weapon: self.weapon.removeNode() self.weapon = None if self.weapon: self.v_model_root.removeNode() self.v_model_root = None if self.gui: self.gui.cleanup() return def damageTaken(self, amount, avId): if self.hp <= 0.0: killer = self.mg.cr.doId2do.get(avId, None) self.fsm.request('dead', [killer]) self.gui.adjustHpMeter() return def enterDraw(self): self.draw.play() if self.weaponName == 'pistol': self.track = ActorInterval(self.v_model, 'pdraw', playRate=1.6, name='drawTrack') elif self.weaponName == 'shotgun': self.v_model.pose('sidle', 15) self.track = LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut', name='drawTrack') self.track.setDoneEvent(self.track.getName()) self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitDraw(self): if self.track: self.ignore(self.track.getDoneEvent()) self.track.finish() self.track = None return def enterIdle(self): if self.weaponName == 'pistol': self.v_model.loop('pidle') elif self.weaponName == 'shotgun': self.track = Sequence(LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 1, 0), startHpr=(0, 0, 0), blendType='easeInOut'), LerpQuatInterval(self.v_model, duration=2.0, quat=(0, 0, 0), startHpr=(0, 1, 0), blendType='easeInOut')) self.track.loop() self.accept('mouse1', self.requestShoot) if self.ammo <= 0: self.gui.notifyNoAmmo() if self.ammo < 14: self.accept('r', self.aliveFSM.request, ['reload']) def requestShoot(self): if self.mg.fsm.getCurrentState().getName() != 'play': return if self.ammo > 0: self.aliveFSM.request('shoot') else: self.empty.play() def exitIdle(self): self.v_model.stop() if self.track: self.track.finish() self.track = None self.ignore('mouse1') self.ignore('r') return def enterShoot(self): self.shoot.play() if self.weaponName == 'pistol': self.track = ActorInterval(self.v_model, 'pshoot', playRate=2, name='shootTrack') elif self.weaponName == 'shotgun': self.track = Parallel(Sequence(LerpQuatInterval(self.v_model, duration=0.05, quat=(0, 3, 0), startHpr=(0, 0, 0)), LerpQuatInterval(self.v_model, duration=0.1, quat=(0, 0, 0), startHpr=(0, 3, 0))), Sequence(LerpPosInterval(self.v_model, duration=0.05, pos=(0, -0.3, 0), startPos=(0, 0, 0)), LerpPosInterval(self.v_model, duration=0.1, pos=(0, 0, 0), startPos=(0, -0.3, 0)), Wait(0.1))) self.track.setDoneEvent('shootTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() self.ammo -= 1 self.gui.adjustAmmoGui() self.mg.makeSmokeEffect(self.weapon.find('**/joint_nozzle').getPos(render)) self.traverse() def traverse(self): mpos = base.mouseWatcherNode.getMouse() self.shooterRay.setFromLens(base.camNode, mpos.getX(), mpos.getY()) self.shooterTrav.traverse(render) def calcDamage(self, avatar): dmgData = self.WeaponName2DamageData[self.weaponName] maxDamage = dmgData[0] minDistance = dmgData[1] maxDistance = dmgData[2] factor = dmgData[3] distance = base.localAvatar.getDistance(avatar) if distance < minDistance: distance = minDistance elif distance > maxDistance: distance = maxDistance damage = maxDamage - (distance - minDistance) * factor return damage def exitShoot(self): self.ignore('shootTrack') if self.track: self.track.finish() self.track = None return def enterReload(self): self.gui.deleteNoAmmoLabel() if self.weaponName == 'pistol': self.track = Parallel(Sequence(Wait(0.3), Func(self.reload.play), Func(self.resetAmmo)), ActorInterval(self.v_model, 'preload', playRate=1.5), name='reloadTrack') elif self.weaponName == 'shotgun': self.track = Sequence(Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(70, -50, 0), startHpr=(0, 0, 0), blendType='easeIn'), SoundInterval(self.cockBack), SoundInterval(self.cockFwd), Func(self.resetAmmo), Func(self.draw.play), LerpQuatInterval(self.v_model, duration=0.5, quat=(0, 0, 0), startHpr=(70, -50, 0), blendType='easeOut'), name='reloadTrack') self.track.setDoneEvent('reloadTrack') self.acceptOnce(self.track.getDoneEvent(), self.aliveFSM.request, ['idle']) self.track.start() def exitReload(self): self.ignore('reloadTrack') if self.track: self.track.finish() self.track = None return def resetAmmo(self): if self.weaponName == 'pistol': self.ammo = 14 elif self.weaponName == 'shotgun': self.ammo = 7 self.gui.resetAmmo() def resetHp(self): self.hp = self.max_hp self.gui.adjustHpMeter() def enterOff(self): pass def exitOff(self): pass
class IsisAgent(kinematicCharacterController, DirectObject): @classmethod def setPhysics(cls, physics): """ This method is set in src.loader when the generators are loaded into the namespace. This frees the environment definitions (in scenario files) from having to pass around the physics parameter that is required for all IsisObjects """ cls.physics = physics def __init__(self, name, queueSize=100): # load the model and the different animations for the model into an Actor object. self.actor = Actor("media/models/boxman", { "walk": "media/models/boxman-walk", "idle": "media/models/boxman-idle" }) self.actor.setScale(1.0) self.actor.setH(0) #self.actor.setLODAnimation(10,5,2) # slows animation framerate when actor is far from camera, if you can figure out reasonable params self.actor.setColorScale(random.random(), random.random(), random.random(), 1.0) self.actorNodePath = NodePath('agent-%s' % name) self.activeModel = self.actorNodePath self.actorNodePath.reparentTo(render) self.actor.reparentTo(self.actorNodePath) self.name = name self.isMoving = False # initialize ODE controller kinematicCharacterController.__init__(self, IsisAgent.physics, self.actorNodePath) self.setGeomPos(self.actorNodePath.getPos(render)) """ Additional Direct Object that I use for convenience. """ self.specialDirectObject = DirectObject() """ How high above the center of the capsule you want the camera to be when walking and when crouching. It's related to the values in KCC. """ self.walkCamH = 0.7 self.crouchCamH = 0.2 self.camH = self.walkCamH """ This tells the Player Controller what we're aiming at. """ self.aimed = None self.isSitting = False self.isDisabled = False """ The special direct object is used for trigger messages and the like. """ #self.specialDirectObject.accept("ladder_trigger_enter", self.setFly, [True]) #self.specialDirectObject.accept("ladder_trigger_exit", self.setFly, [False]) self.actor.makeSubpart("arms", ["LeftShoulder", "RightShoulder"]) # Expose agent's right hand joint to attach objects to self.player_right_hand = self.actor.exposeJoint( None, 'modelRoot', 'Hand.R') self.player_left_hand = self.actor.exposeJoint(None, 'modelRoot', 'Hand.L') self.right_hand_holding_object = None self.left_hand_holding_object = None # don't change the color of things you pick up self.player_right_hand.setColorScaleOff() self.player_left_hand.setColorScaleOff() self.player_head = self.actor.exposeJoint(None, 'modelRoot', 'Head') self.neck = self.actor.controlJoint(None, 'modelRoot', 'Head') self.controlMap = { "turn_left": 0, "turn_right": 0, "move_forward": 0, "move_backward": 0, "move_right": 0, "move_left": 0, "look_up": 0, "look_down": 0, "look_left": 0, "look_right": 0, "jump": 0 } # see update method for uses, indices are [turn left, turn right, move_forward, move_back, move_right, move_left, look_up, look_down, look_right, look_left] # turns are in degrees per second, moves are in units per second self.speeds = [270, 270, 5, 5, 5, 5, 60, 60, 60, 60] self.originalPos = self.actor.getPos() bubble = loader.loadTexture("media/textures/thought_bubble.png") #bubble.setTransparency(TransparencyAttrib.MAlpha) self.speech_bubble = DirectLabel(parent=self.actor, text="", text_wordwrap=10, pad=(3, 3), relief=None, text_scale=(.3, .3), pos=(0, 0, 3.6), frameColor=(.6, .2, .1, .5), textMayChange=1, text_frame=(0, 0, 0, 1), text_bg=(1, 1, 1, 1)) #self.myImage= self.speech_bubble.setTransparency(TransparencyAttrib.MAlpha) # stop the speech bubble from being colored like the agent self.speech_bubble.setColorScaleOff() self.speech_bubble.component('text0').textNode.setCardDecal(1) self.speech_bubble.setBillboardAxis() # hide the speech bubble from IsisAgent's own camera self.speech_bubble.hide(BitMask32.bit(1)) self.thought_bubble = DirectLabel(parent=self.actor, text="", text_wordwrap=9, text_frame=(1, 0, -2, 1), text_pos=(0, .5), text_bg=(1, 1, 1, 0), relief=None, frameSize=(0, 1.5, -2, 3), text_scale=(.18, .18), pos=(0, 0.2, 3.6), textMayChange=1, image=bubble, image_pos=(0, 0.1, 0), sortOrder=5) self.thought_bubble.setTransparency(TransparencyAttrib.MAlpha) # stop the speech bubble from being colored like the agent self.thought_bubble.setColorScaleOff() self.thought_bubble.component('text0').textNode.setFrameColor( 1, 1, 1, 0) self.thought_bubble.component('text0').textNode.setFrameAsMargin( 0.1, 0.1, 0.1, 0.1) self.thought_bubble.component('text0').textNode.setCardDecal(1) self.thought_bubble.setBillboardAxis() # hide the thought bubble from IsisAgent's own camera self.thought_bubble.hide(BitMask32.bit(1)) # disable by default self.thought_bubble.hide() self.thought_filter = {} # only show thoughts whose values are in here self.last_spoke = 0 # timers to keep track of last thought/speech and self.last_thought = 0 # hide visualizations # put a camera on ralph self.fov = NodePath(Camera('RaphViz')) self.fov.node().setCameraMask(BitMask32.bit(1)) # position the camera to be infront of Boxman's face. self.fov.reparentTo(self.player_head) # x,y,z are not in standard orientation when parented to player-Head self.fov.setPos(0, 0.2, 0) # if P=0, canrea is looking directly up. 90 is back of head. -90 is on face. self.fov.setHpr(0, -90, 0) lens = self.fov.node().getLens() lens.setFov(60) # degree field of view (expanded from 40) lens.setNear(0.2) #self.fov.node().showFrustum() # displays a box around his head #self.fov.place() self.prevtime = 0 self.current_frame_count = 0 self.isSitting = False self.isDisabled = False self.msg = None self.actorNodePath.setPythonTag("agent", self) # Initialize the action queue, with a maximum length of queueSize self.queue = [] self.queueSize = queueSize self.lastSense = 0 def setLayout(self, layout): """ Dummy method called by spatial methods for use with objects. Doesn't make sense for an agent that can move around.""" pass def setPos(self, pos): """ Wrapper to set the position of the ODE geometry, which in turn sets the visual model's geometry the next time the update() method is called. """ self.setGeomPos(pos) def setPosition(self, pos): self.setPos(pos) def reparentTo(self, parent): self.actorNodePath.reparentTo(parent) def setControl(self, control, value): """Set the state of one of the character's movement controls. """ self.controlMap[control] = value def get_objects_in_field_of_vision(self, exclude=['isisobject']): """ This works in an x-ray style. Fast. Works best if you listen to http://en.wikipedia.org/wiki/Rock_Art_and_the_X-Ray_Style while you use it. needs to exclude isisobjects since they cannot be serialized """ objects = {} for obj in base.render.findAllMatches("**/IsisObject*"): if not obj.hasPythonTag("isisobj"): continue o = obj.getPythonTag("isisobj") bounds = o.activeModel.getBounds() bounds.xform(o.activeModel.getMat(self.fov)) if self.fov.node().isInView(o.activeModel.getPos(self.fov)): pos = o.activeModel.getPos(render) pos = (pos[0], pos[1], pos[2] + o.getHeight() / 2) p1 = self.fov.getRelativePoint(render, pos) p2 = Point2() self.fov.node().getLens().project(p1, p2) p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1])) object_dict = {} if 'x_pos' not in exclude: object_dict['x_pos'] = p3[0] if 'y_pos' not in exclude: object_dict['y_pos'] = p3[2] if 'distance' not in exclude: object_dict['distance'] = o.activeModel.getDistance( self.fov) if 'orientation' not in exclude: object_dict['orientation'] = o.activeModel.getH(self.fov) if 'actions' not in exclude: object_dict['actions'] = o.list_actions() if 'isisobject' not in exclude: object_dict['isisobject'] = o # add item to dinctionary objects[o] = object_dict return objects def get_agents_in_field_of_vision(self): """ This works in an x-ray vision style as well""" agents = {} for agent in base.render.findAllMatches("**/agent-*"): if not agent.hasPythonTag("agent"): continue a = agent.getPythonTag("agent") bounds = a.actorNodePath.getBounds() bounds.xform(a.actorNodePath.getMat(self.fov)) pos = a.actorNodePath.getPos(self.fov) if self.fov.node().isInView(pos): p1 = self.fov.getRelativePoint(render, pos) p2 = Point2() self.fov.node().getLens().project(p1, p2) p3 = aspect2d.getRelativePoint(render2d, Point3(p2[0], 0, p2[1])) agentDict = {'x_pos': p3[0],\ 'y_pos': p3[2],\ 'distance':a.actorNodePath.getDistance(self.fov),\ 'orientation': a.actorNodePath.getH(self.fov)} agents[a] = agentDict return agents def in_view(self, isisobj): """ Returns true iff a particular isisobject is in view """ return len( filter(lambda x: x['isisobject'] == isisobj, self.get_objects_in_field_of_vision(exclude=[]).values())) def get_objects_in_view(self): """ Gets objects through ray tracing. Slow""" return self.picker.get_objects_in_view() def control__turn_left__start(self, speed=None): self.setControl("turn_left", 1) self.setControl("turn_right", 0) if speed: self.speeds[0] = speed return "success" def control__turn_left__stop(self): self.setControl("turn_left", 0) return "success" def control__turn_right__start(self, speed=None): self.setControl("turn_left", 0) self.setControl("turn_right", 1) if speed: self.speeds[1] = speed return "success" def control__turn_right__stop(self): self.setControl("turn_right", 0) return "success" def control__move_forward__start(self, speed=None): self.setControl("move_forward", 1) self.setControl("move_backward", 0) if speed: self.speeds[2] = speed return "success" def control__move_forward__stop(self): self.setControl("move_forward", 0) return "success" def control__move_backward__start(self, speed=None): self.setControl("move_forward", 0) self.setControl("move_backward", 1) if speed: self.speeds[3] = speed return "success" def control__move_backward__stop(self): self.setControl("move_backward", 0) return "success" def control__move_left__start(self, speed=None): self.setControl("move_left", 1) self.setControl("move_right", 0) if speed: self.speeds[4] = speed return "success" def control__move_left__stop(self): self.setControl("move_left", 0) return "success" def control__move_right__start(self, speed=None): self.setControl("move_right", 1) self.setControl("move_left", 0) if speed: self.speeds[5] = speed return "success" def control__move_right__stop(self): self.setControl("move_right", 0) return "success" def control__look_left__start(self, speed=None): self.setControl("look_left", 1) self.setControl("look_right", 0) if speed: self.speeds[9] = speed return "success" def control__look_left__stop(self): self.setControl("look_left", 0) return "success" def control__look_right__start(self, speed=None): self.setControl("look_right", 1) self.setControl("look_left", 0) if speed: self.speeds[8] = speed return "success" def control__look_right__stop(self): self.setControl("look_right", 0) return "success" def control__look_up__start(self, speed=None): self.setControl("look_up", 1) self.setControl("look_down", 0) if speed: self.speeds[6] = speed return "success" def control__look_up__stop(self): self.setControl("look_up", 0) return "success" def control__look_down__start(self, speed=None): self.setControl("look_down", 1) self.setControl("look_up", 0) if speed: self.speeds[7] = speed return "success" def control__look_down__stop(self): self.setControl("look_down", 0) return "success" def control__jump(self): self.setControl("jump", 1) return "success" def control__view_objects(self): """ calls a raytrace to to all objects in view """ objects = self.get_objects_in_field_of_vision() self.control__say( "If I were wearing x-ray glasses, I could see %i items" % len(objects)) print "Objects in view:", objects return objects def control__sense(self): """ perceives the world, returns percepts dict """ percepts = dict() # eyes: visual matricies #percepts['vision'] = self.sense__get_vision() # objects in purview (cheating object recognition) percepts['objects'] = self.sense__get_objects() # global position in environment - our robots can have GPS :) percepts['position'] = self.sense__get_position() # language: get last utterances that were typed percepts['language'] = self.sense__get_utterances() # agents: returns a map of agents to a list of actions that have been sensed percepts['agents'] = self.sense__get_agents() print percepts return percepts def control__think(self, message, layer=0): """ Changes the contents of an agent's thought bubble""" # only say things that are checked in the controller if self.thought_filter.has_key(layer): self.thought_bubble.show() self.thought_bubble['text'] = message #self.thought_bubble.component('text0').textNode.setShadow(0.05, 0.05) #self.thought_bubble.component('text0').textNode.setShadowColor(self.thought_filter[layer]) self.last_thought = 0 return "success" def control__say(self, message="Hello!"): self.speech_bubble['text'] = message self.last_spoke = 0 return "success" """ Methods explicitly for IsisScenario files """ def put_in_front_of(self, isisobj): # find open direction pos = isisobj.getGeomPos() direction = render.getRelativeVector(isisobj, Vec3(0, 1.0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew( 'aimRay', 5, [pos, direction], [isisobj.geom]) print "CLOSEST", closestEntry, closestObject if closestObject == None: self.setPosition(pos + Vec3(0, 2, 0)) else: print "CANNOT PLACE IN FRONT OF %s BECAUSE %s IS THERE" % ( isisobj, closestObject) direction = render.getRelativeVector(isisobj, Vec3(0, -1.0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew( 'aimRay', 5, [pos, direction], [isisobj.geom]) if closestEntry == None: self.setPosition(pos + Vec3(0, -2, 0)) else: print "CANNOT PLACE BEHIND %s BECAUSE %s IS THERE" % ( isisobj, closestObject) direction = render.getRelativeVector(isisobj, Vec3(1, 0, 0)) closestEntry, closestObject = IsisAgent.physics.doRaycastNew( 'aimRay', 5, [pos, direction], [isisobj.geom]) if closestEntry == None: self.setPosition(pos + Vec3(2, 0, 0)) else: print "CANNOT PLACE TO LEFT OF %s BECAUSE %s IS THERE" % ( isisobj, closestObject) # there's only one option left, do it anyway self.setPosition(pos + Vec3(-2, 0, 0)) # rotate agent to look at it self.actorNodePath.setPos(self.getGeomPos()) self.actorNodePath.lookAt(pos) self.setH(self.actorNodePath.getH()) def put_in_right_hand(self, target): return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand) def put_in_left_hand(self, target): return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand) def __get_object_in_center_of_view(self): direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.fov.getPos(render) exclude = [ ] #[base.render.find("**/kitchenNode*").getPythonTag("isisobj").geom] closestEntry, closestObject = IsisAgent.physics.doRaycastNew( 'aimRay', 5, [pos, direction], exclude) return closestObject def pick_object_up_with(self, target, hand_slot, hand_joint): """ Attaches an IsisObject, target, to the hand joint. Does not check anything first, other than the fact that the hand joint is not currently holding something else.""" if hand_slot != None: print 'already holding ' + hand_slot.getName() + '.' return None else: if target.layout: target.layout.remove(target) target.layout = None # store original position target.originalHpr = target.getHpr(render) target.disable() #turn off physics if target.body: target.body.setGravityMode(0) target.reparentTo(hand_joint) target.setPosition(hand_joint.getPos(render)) target.setTag('heldBy', self.name) if hand_joint == self.player_right_hand: self.right_hand_holding_object = target elif hand_joint == self.player_left_hand: self.left_hand_holding_object = target hand_slot = target return target def control__pick_up_with_right_hand(self, target=None): if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return "error: no target in reach" else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") print "attempting to pick up " + target.name + " with right hand.\n" if self.can_grasp(target): # object within distance return self.pick_object_up_with(target, self.right_hand_holding_object, self.player_right_hand) else: print 'object (' + target.name + ') is not graspable (i.e. in view and close enough).' return 'error: object not graspable' def control__pick_up_with_left_hand(self, target=None): if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag("isisobj") print "attempting to pick up " + target.name + " with left hand.\n" if self.can_grasp(target): # object within distance return self.pick_object_up_with(target, self.left_hand_holding_object, self.player_left_hand) else: print 'object (' + target.name + ') is not graspable (i.e. in view and close enough).' return 'error: object not graspable' def control__drop_from_right_hand(self): print "attempting to drop object from right hand.\n" if self.right_hand_holding_object is None: print 'right hand is not holding an object.' return False if self.right_hand_holding_object.getNetTag('heldBy') == self.name: self.right_hand_holding_object.reparentTo(render) direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.player_right_hand.getPos(render) heldPos = self.right_hand_holding_object.geom.getPosition() self.right_hand_holding_object.setPosition(pos) self.right_hand_holding_object.synchPosQuatToNode() self.right_hand_holding_object.setTag('heldBy', '') self.right_hand_holding_object.setRotation( self.right_hand_holding_object.originalHpr) self.right_hand_holding_object.enable() if self.right_hand_holding_object.body: quat = self.getQuat() # throw object force = 5 self.right_hand_holding_object.body.setGravityMode(1) self.right_hand_holding_object.getBody().setForce( quat.xform(Vec3(0, force, 0))) self.right_hand_holding_object = None return 'success' else: return "Error: not being held by agent %s" % (self.name) def control__drop_from_left_hand(self): print "attempting to drop object from left hand.\n" if self.left_hand_holding_object is None: return 'left hand is not holding an object.' if self.left_hand_holding_object.getNetTag('heldBy') == self.name: self.left_hand_holding_object.reparentTo(render) direction = render.getRelativeVector(self.fov, Vec3(0, 1.0, 0)) pos = self.player_left_hand.getPos(render) heldPos = self.left_hand_holding_object.geom.getPosition() self.left_hand_holding_object.setPosition(pos) self.left_hand_holding_object.synchPosQuatToNode() self.left_hand_holding_object.setTag('heldBy', '') self.left_hand_holding_object.setRotation( self.left_hand_holding_object.originalHpr) self.left_hand_holding_object.enable() if self.left_hand_holding_object.body: quat = self.getQuat() # throw object force = 5 self.left_hand_holding_object.body.setGravityMode(1) self.left_hand_holding_object.getBody().setForce( quat.xform(Vec3(0, force, 0))) self.left_hand_holding_object = None return 'success' else: return "Error: not being held by agent %s" % (self.name) def control__use_right_hand(self, target=None, action=None): # TODO, rename this to use object with if not action: if self.msg: action = self.msg else: action = "divide" if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag('isisobj') print "Trying to use object", target if self.can_grasp(target): if (target.call(self, action, self.right_hand_holding_object) or (self.right_hand_holding_object and self.right_hand_holding_object.call(self, action, target))): return "success" return str(action) + " not associated with either target or object" return "target not within reach" def control__use_left_hand(self, target=None, action=None): if not action: if self.msg: action = self.msg else: action = "divide" if not target: target = self.__get_object_in_center_of_view() if not target: print "no target in reach" return else: target = render.find("**/*" + target + "*").getPythonTag('isisobj') if self.can_grasp(target): if (target.call(self, action, self.left_hand_holding_object) or (self.left_hand_holding_object and self.left_hand_holding_object.call(self, action, target))): return "success" return str(action) + " not associated with either target or object" return "target not within reach" def can_grasp(self, isisobject): distance = isisobject.activeModel.getDistance(self.fov) print "distance = ", distance return distance < 5.0 def is_holding(self, object_name): return ((self.left_hand_holding_object and (self.left_hand_holding_object.getPythonTag('isisobj').name == object_name)) \ or (self.right_hand_holding_object and (self.right_hand_holding_object.getPythonTag('isisobj').name == object_name))) def empty_hand(self): if (self.left_hand_holding_object is None): return self.player_left_hand elif (self.right_hand_holding_object is None): return self.player_right_hand return False def has_empty_hand(self): return (self.empty_hand() is not False) def control__use_aimed(self): """ Try to use the object that we aim at, by calling its callback method. """ target = self.__get_object_in_center_of_view() if target.selectionCallback: target.selectionCallback(self, dir) return "success" def sense__get_position(self): x, y, z = self.actorNodePath.getPos() h, p, r = self.actorNodePath.getHpr() #FIXME # neck is not positioned in Blockman nh,np,nr = self.agents[agent_id].actor_neck.getHpr() left_hand_obj = "" right_hand_obj = "" if self.left_hand_holding_object: left_hand_obj = self.left_hand_holding_object.getName() if self.right_hand_holding_object: right_hand_obj = self.right_hand_holding_object.getName() return {'body_x': x, 'body_y': y, 'body_z': z,'body_h':h,\ 'body_p': p, 'body_r': r, 'in_left_hand': left_hand_obj, 'in_right_hand':right_hand_obj} def sense__get_vision(self): self.fov.node().saveScreenshot("temp.jpg") image = Image.open("temp.jpg") os.remove("temp.jpg") return image def sense__get_objects(self): return dict([x.getName(), y] for (x, y) in self.get_objects_in_field_of_vision().items()) def sense__get_agents(self): curSense = time() agents = {} for k, v in self.get_agents_in_field_of_vision().items(): v['actions'] = k.get_other_agents_actions(self.lastSense, curSense) agents[k.name] = v self.lastSense = curSense return agents def sense__get_utterances(self): """ Clear out the buffer of things that the teacher has typed, FIXME: this doesn't work right now """ return [] utterances = self.teacher_utterances self.teacher_utterances = [] return utterances def debug__print_objects(self): text = "Objects in FOV: " + ", ".join(self.sense__get_objects().keys()) print text def add_action_to_history(self, action, args, result=0): self.queue.append((time(), action, args, result)) if len(self.queue) > self.queueSize: self.queue.pop(0) def get_other_agents_actions(self, start=0, end=None): if not end: end = time() actions = [] for act in self.queue: if act[0] >= start: if act[0] < end: actions.append(act) else: break return actions def update(self, stepSize=0.1): self.speed = [0.0, 0.0] self.actorNodePath.setPos(self.geom.getPosition() + Vec3(0, 0, -0.70)) self.actorNodePath.setQuat(self.getQuat()) # the values in self.speeds are used as coefficientes for turns and movements if (self.controlMap["turn_left"] != 0): self.addToH(stepSize * self.speeds[0]) if (self.controlMap["turn_right"] != 0): self.addToH(-stepSize * self.speeds[1]) if self.verticalState == 'ground': # these actions require contact with the ground if (self.controlMap["move_forward"] != 0): self.speed[1] = self.speeds[2] if (self.controlMap["move_backward"] != 0): self.speed[1] = -self.speeds[3] if (self.controlMap["move_left"] != 0): self.speed[0] = -self.speeds[4] if (self.controlMap["move_right"] != 0): self.speed[0] = self.speeds[5] if (self.controlMap["jump"] != 0): kinematicCharacterController.jump(self) # one jump at a time! self.controlMap["jump"] = 0 if (self.controlMap["look_left"] != 0): self.neck.setR(bound(self.neck.getR(), -60, 60) + stepSize * 80) if (self.controlMap["look_right"] != 0): self.neck.setR(bound(self.neck.getR(), -60, 60) - stepSize * 80) if (self.controlMap["look_up"] != 0): self.neck.setP(bound(self.neck.getP(), -60, 80) + stepSize * 80) if (self.controlMap["look_down"] != 0): self.neck.setP(bound(self.neck.getP(), -60, 80) - stepSize * 80) kinematicCharacterController.update(self, stepSize) """ Update the held object position to be in the hands """ if self.right_hand_holding_object != None: self.right_hand_holding_object.setPosition( self.player_right_hand.getPos(render)) if self.left_hand_holding_object != None: self.left_hand_holding_object.setPosition( self.player_left_hand.getPos(render)) #Update the dialog box and thought windows #This allows dialogue window to gradually decay (changing transparancy) and then disappear self.last_spoke += stepSize / 2 self.last_thought += stepSize / 2 self.speech_bubble['text_bg'] = (1, 1, 1, 1 / (self.last_spoke + 0.01)) self.speech_bubble['frameColor'] = (.6, .2, .1, .5 / (self.last_spoke + 0.01)) if self.last_spoke > 2: self.speech_bubble['text'] = "" if self.last_thought > 1: self.thought_bubble.hide() # If the character is moving, loop the run animation. # If he is standing still, stop the animation. if (self.controlMap["move_forward"] != 0) or (self.controlMap["move_backward"] != 0) or (self.controlMap["move_left"] != 0) or (self.controlMap["move_right"] != 0): if self.isMoving is False: self.isMoving = True else: if self.isMoving: self.current_frame_count = 5.0 self.isMoving = False total_frame_num = self.actor.getNumFrames('walk') if self.isMoving: self.current_frame_count = self.current_frame_count + (stepSize * 250.0) if self.current_frame_count > total_frame_num: self.current_frame_count = self.current_frame_count % total_frame_num self.actor.pose('walk', self.current_frame_count) elif self.current_frame_count != 0: self.current_frame_count = 0 self.actor.pose('idle', 0) return Task.cont def destroy(self): self.disable() self.specialDirectObject.ignoreAll() self.actorNodePath.removeNode() del self.specialDirectObject kinematicCharacterController.destroy(self) def disable(self): self.isDisabled = True self.geom.disable() self.footRay.disable() def enable(self): self.footRay.enable() self.geom.enable() self.isDisabled = False """ Set camera to correct height above the center of the capsule when crouching and when standing up. """ def crouch(self): kinematicCharacterController.crouch(self) self.camH = self.crouchCamH def crouchStop(self): """ Only change the camera's placement when the KCC allows standing up. See the KCC to find out why it might not allow it. """ if kinematicCharacterController.crouchStop(self): self.camH = self.walkCamH