Beispiel #1
0
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())
Beispiel #2
0
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)
Beispiel #4
0
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)
Beispiel #7
0
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))
Beispiel #8
0
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)
Beispiel #9
0
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
Beispiel #10
0
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
Beispiel #11
0
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
Beispiel #13
0
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
Beispiel #17
0
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)
Beispiel #18
0
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
Beispiel #19
0
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)
Beispiel #20
0
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
Beispiel #21
0
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()
Beispiel #23
0
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()
Beispiel #24
0
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
Beispiel #25
0
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
Beispiel #26
0
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]
Beispiel #27
0
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()
Beispiel #28
0
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
Beispiel #29
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
Beispiel #31
0
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
Beispiel #32
0
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 + "  ")
Beispiel #33
0
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)
Beispiel #34
0
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)
Beispiel #35
0
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)
Beispiel #36
0
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
Beispiel #38
0
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)
Beispiel #39
0
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
Beispiel #40
0
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))
Beispiel #41
0
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 + "  ")
Beispiel #42
0
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
Beispiel #43
0
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