245 lines
9.8 KiB
Python
245 lines
9.8 KiB
Python
import math
|
|
import random
|
|
from direct.showbase.PythonUtil import *
|
|
from direct.showbase.DirectObject import DirectObject
|
|
from direct.task import Task
|
|
from panda3d.core import *
|
|
from direct.fsm import FSM
|
|
from direct.distributed import DistributedSmoothNode
|
|
from otp.avatar import ShadowCaster
|
|
from otp.otpbase import OTPGlobals
|
|
from toontown.racing.FlyingGag import FlyingGag
|
|
from toontown.battle import MovieUtil
|
|
|
|
class Piejectile(DirectObject, FlyingGag):
|
|
physicsCalculationsPerSecond = 60
|
|
maxPhysicsDt = 1.0
|
|
physicsDt = 1.0 / float(physicsCalculationsPerSecond)
|
|
maxPhysicsFrames = maxPhysicsDt * physicsCalculationsPerSecond
|
|
|
|
def __init__(self, sourceId, targetId, type, name):
|
|
FlyingGag.__init__(self, 'flyingGag', base.race.pie)
|
|
self.billboard = False
|
|
self.race = base.race
|
|
self.scale = 1
|
|
self.imHitMult = 1
|
|
self.wallCollideTrack = None
|
|
self.curSpeed = 0
|
|
self.acceleration = 0
|
|
self.count = 0
|
|
self.name = name
|
|
self.physicsObj = None
|
|
self.ownerId = sourceId
|
|
self.targetId = targetId
|
|
self.ownerAv = None
|
|
self.ownerKart = None
|
|
self.hasTarget = 0
|
|
self.deleting = 0
|
|
self.d2t = 0
|
|
self.lastD2t = 0
|
|
self.startTime = globalClock.getFrameTime()
|
|
self.timeRatio = 0
|
|
self.maxTime = 8
|
|
self.rotH = randFloat(-360, 360)
|
|
self.rotP = randFloat(-90, 90)
|
|
self.rotR = randFloat(-90, 90)
|
|
self.ownerKart = base.cr.doId2do.get(base.race.kartMap.get(sourceId, None), None)
|
|
if targetId != 0:
|
|
self.targetKart = base.cr.doId2do.get(base.race.kartMap.get(targetId, None), None)
|
|
self.hasTarget = 1
|
|
if self.ownerId == localAvatar.doId:
|
|
startPos = self.ownerKart.getPos(render)
|
|
else:
|
|
startPos = self.ownerKart.getPos(render)
|
|
self.setPos(startPos[0], startPos[1], startPos[2])
|
|
self.__setupCollisions()
|
|
self.setupPhysics()
|
|
self.__enableCollisions()
|
|
self.forward = NodePath('forward')
|
|
self.forward.setPos(0, 1, 0)
|
|
self.splatTaskName = 'splatTask %s' % self.name
|
|
if self.hasTarget:
|
|
self.splatTask = taskMgr.doMethodLater(self.maxTime, self.splat, self.splatTaskName)
|
|
else:
|
|
self.splatTask = taskMgr.doMethodLater(self.maxTime / 2.5, self.splat, self.splatTaskName)
|
|
self.reparentTo(render)
|
|
|
|
def delete(self):
|
|
taskMgr.remove(self.taskName)
|
|
self.__undoCollisions()
|
|
self.physicsMgr.clearLinearForces()
|
|
FlyingGag.delete(self)
|
|
self.deleting = 1
|
|
self.ignoreAll()
|
|
|
|
def remove(self):
|
|
self.delete()
|
|
|
|
def setAvId(self, avId):
|
|
self.avId = avId
|
|
|
|
def setRace(self, doId):
|
|
self.race = base.cr.doId2do.get(doId)
|
|
|
|
def setOwnerId(self, ownerId):
|
|
self.ownerId = ownerId
|
|
|
|
def setType(self, type):
|
|
self.type = type
|
|
|
|
def setPos(self, x, y, z):
|
|
DistributedSmoothNode.DistributedSmoothNode.setPos(self, x, y, z)
|
|
|
|
def getVelocity(self):
|
|
return self.actorNode.getPhysicsObject().getVelocity()
|
|
|
|
def setupPhysics(self):
|
|
self.physicsMgr = PhysicsManager()
|
|
self.physicsEpoch = globalClock.getFrameTime()
|
|
self.lastPhysicsFrame = 0
|
|
integrator = LinearEulerIntegrator()
|
|
self.physicsMgr.attachLinearIntegrator(integrator)
|
|
fn = ForceNode('windResistance')
|
|
fnp = NodePath(fn)
|
|
fnp.reparentTo(render)
|
|
windResistance = LinearFrictionForce(0.2)
|
|
fn.addForce(windResistance)
|
|
self.physicsMgr.addLinearForce(windResistance)
|
|
self.windResistance = windResistance
|
|
fn = ForceNode('engine')
|
|
fnp = NodePath(fn)
|
|
fnp.reparentTo(self)
|
|
engine = LinearVectorForce(0, 0, 3)
|
|
fn.addForce(engine)
|
|
self.physicsMgr.addLinearForce(engine)
|
|
self.engine = engine
|
|
self.physicsMgr.attachPhysicalNode(self.node())
|
|
self.physicsObj = self.actorNode.getPhysicsObject()
|
|
ownerAv = base.cr.doId2do[self.ownerId]
|
|
ownerVel = self.ownerKart.getVelocity()
|
|
ownerSpeed = ownerVel.length()
|
|
rotMat = Mat3.rotateMatNormaxis(self.ownerKart.getH(), Vec3.up())
|
|
ownerHeading = rotMat.xform(Vec3.forward())
|
|
throwSpeed = 50
|
|
throwVel = ownerHeading * throwSpeed
|
|
throwVelCast = Vec3(throwVel[0], throwVel[1], throwVel[2] + 50)
|
|
self.actorNode.getPhysicsObject().setVelocity(self.ownerKart.getVelocity() + throwVelCast)
|
|
lookPoint = render.getRelativePoint(self.ownerKart, Point3(0, 10, 0))
|
|
self.lookAt(lookPoint)
|
|
self.taskName = 'updatePhysics%s' % self.name
|
|
taskMgr.add(self.__updatePhysics, self.taskName, priority=25)
|
|
|
|
def checkTargetDistance(self):
|
|
if self.hasTarget:
|
|
return self.getDistance(self.targetKart)
|
|
else:
|
|
return 0
|
|
|
|
def splatTarget(self):
|
|
if self.targetId == base.localAvatar.getDoId() and base.race.localKart:
|
|
base.race.localKart.splatPie()
|
|
self.race.effectManager.addSplatEffect(spawner=self.targetKart, parent=self.targetKart)
|
|
taskMgr.remove(self.splatTaskName)
|
|
self.removeNode()
|
|
self.remove()
|
|
|
|
def splat(self, optional = None):
|
|
self.race.effectManager.addSplatEffect(spawner=self)
|
|
taskMgr.remove(self.splatTaskName)
|
|
self.removeNode()
|
|
self.remove()
|
|
|
|
def __updatePhysics(self, task):
|
|
if self.deleting:
|
|
return Task.done
|
|
self.timeRatio = (globalClock.getFrameTime() - self.startTime) / self.maxTime
|
|
self.windResistance.setCoef(0.2 + 0.8 * self.timeRatio)
|
|
if base.cr.doId2do.get(self.targetId) == None:
|
|
self.hasTarget = 0
|
|
self.lastD2t = self.d2t
|
|
self.d2t = self.checkTargetDistance()
|
|
if self.hasTarget:
|
|
targetDistance = self.d2t
|
|
distMax = 100
|
|
if self.d2t > distMax:
|
|
targetDistance = distMax
|
|
targetVel = self.targetKart.getVelocity()
|
|
targetPos = self.targetKart.getPos()
|
|
targetAim = Point3(targetPos[0] + targetVel[0] * (targetDistance / distMax), targetPos[1] + targetVel[1] * (targetDistance / distMax), targetPos[2] + targetVel[2] * (targetDistance / distMax))
|
|
self.lookAt(targetPos)
|
|
if self.d2t < 7 and self.hasTarget:
|
|
self.splatTarget()
|
|
return Task.done
|
|
self.count += 1
|
|
dt = globalClock.getDt()
|
|
physicsFrame = int((globalClock.getFrameTime() - self.physicsEpoch) * self.physicsCalculationsPerSecond)
|
|
numFrames = min(physicsFrame - self.lastPhysicsFrame, self.maxPhysicsFrames)
|
|
self.lastPhysicsFrame = physicsFrame
|
|
if self.hasTarget:
|
|
targetVel = self.targetKart.getVelocity()
|
|
targetSpeed = targetVel.length()
|
|
if self.d2t - 10 * self.physicsDt > self.lastD2t:
|
|
self.engine.setVector(Vec3(0, 150 + 150 * self.timeRatio + targetSpeed * (1.0 + 1.0 * self.timeRatio) + self.d2t * (1.0 + 1.0 * self.timeRatio), 12))
|
|
else:
|
|
self.engine.setVector(Vec3(0, 10 + 10 * self.timeRatio + targetSpeed * (0.5 + 0.5 * self.timeRatio) + self.d2t * (0.5 + 0.5 * self.timeRatio), 12))
|
|
else:
|
|
self.engine.setVector(Vec3(0, 100, 3))
|
|
for i in xrange(int(numFrames)):
|
|
pitch = self.gagNode.getP()
|
|
self.gagNode.setP(pitch + self.rotH * self.physicsDt)
|
|
roll = self.gagNode.getR()
|
|
self.gagNode.setR(roll + self.rotP * self.physicsDt)
|
|
heading = self.gagNode.getH()
|
|
self.gagNode.setH(heading + self.rotR * self.physicsDt)
|
|
self.physicsMgr.doPhysics(self.physicsDt)
|
|
|
|
if self.count % 60 == 0:
|
|
pass
|
|
return Task.cont
|
|
|
|
def __setupCollisions(self):
|
|
self.cWallTrav = CollisionTraverser('ProjectileWall')
|
|
self.cWallTrav.setRespectPrevTransform(True)
|
|
self.collisionNode = CollisionNode(self.name)
|
|
self.collisionNode.setFromCollideMask(OTPGlobals.WallBitmask)
|
|
self.collisionNode.setIntoCollideMask(BitMask32.allOff())
|
|
cs = CollisionSphere(0, 0, 0, 7)
|
|
self.collisionNode.addSolid(cs)
|
|
sC = self.attachNewNode(self.collisionNode)
|
|
self.collisionNodePath = NodePath(self.collisionNode)
|
|
self.wallHandler = CollisionHandlerPusher()
|
|
base.cTrav.addCollider(sC, self.wallHandler)
|
|
self.wallHandler.addCollider(self.collisionNodePath, self)
|
|
cRay = CollisionRay(0.0, 0.0, 40000.0, 0.0, 0.0, -1.0)
|
|
pieFloorRayName = 'pieFloorRay%s' % self.name
|
|
cRayNode = CollisionNode(pieFloorRayName)
|
|
cRayNode.addSolid(cRay)
|
|
cRayNode.setFromCollideMask(OTPGlobals.FloorBitmask)
|
|
cRayNode.setIntoCollideMask(BitMask32.allOff())
|
|
self.cRayNodePath = self.attachNewNode(cRayNode)
|
|
self.lifter = CollisionHandlerGravity()
|
|
self.lifter.setGravity(32.174 * 3.0)
|
|
self.lifter.setOffset(OTPGlobals.FloorOffset)
|
|
self.lifter.setReach(40.0)
|
|
self.lifter.addCollider(self.cRayNodePath, self)
|
|
base.cTrav.addCollider(self.cRayNodePath, self.lifter)
|
|
|
|
def __undoCollisions(self):
|
|
base.cTrav.removeCollider(self.cRayNodePath)
|
|
|
|
def __enableCollisions(self):
|
|
self.cQueue = []
|
|
self.cRays = NodePath('stickProjectileToFloor')
|
|
self.cRays.reparentTo(self.gag)
|
|
x = self.gag.getX()
|
|
y = self.gag.getY()
|
|
rayNode = CollisionNode('floorcast')
|
|
ray = CollisionRay(x, y, 40000.0, 0.0, 0.0, -1.0)
|
|
rayNode.addSolid(ray)
|
|
rayNode.setFromCollideMask(OTPGlobals.FloorBitmask)
|
|
rayNode.setIntoCollideMask(BitMask32.allOff())
|
|
rayNodePath = self.cRays.attachNewNode(rayNode)
|
|
cQueue = CollisionHandlerQueue()
|
|
self.cWallTrav.addCollider(rayNodePath, cQueue)
|
|
self.cQueue.append(cQueue)
|
|
self.collisionNodePath.reparentTo(self)
|