Poodletooth-iLand/toontown/pets/PetMoverAI.py

187 lines
4.5 KiB
Python

from panda3d.core import *
from direct.interval.IntervalGlobal import *
from direct.fsm.FSM import *
import random, math
estateRadius = 130
estateCenter = (0, -40)
houseRadius = 15
houses = ((60, 10), (42, 75), (-37, 35), (80, -80), (-70, -120), (-55, -40))
dist = 2
def inCircle(x, y, c=estateCenter, r=estateRadius):
center_x, center_y = c
square_dist = (center_x - x) ** 2 + (center_y - y) ** 2
return square_dist <= r ** 2
def housePointCollision(x, y):
for i, h in enumerate(houses):
if inCircle(x, y, h, houseRadius):
return 1
return 0
def generatePos():
def get():
r = random.randint(0, estateRadius) - estateRadius / 2
r2 = random.randint(0, estateRadius) - estateRadius / 2
x = r + estateCenter[0]
y = r2 + estateCenter[1]
assert inCircle(x, y)
return x, y
p = get()
while housePointCollision(*p):
p = get()
return p
def lineInCircle(pt1, pt2, circlePoint, circleRadius=houseRadius):
x1, y1 = pt1
x2, y2 = pt2
dist = math.hypot(x2 - x1, y2 - y1)
if dist == 0:
return 0
dx = (x2 - x1) / dist
dy = (y2 - y1) / dist
t = dx * (circlePoint[0] - x1) + dy * (circlePoint[1] - y1)
ex = t * dx + x1
ey = t * dy + y1
d2 = math.hypot(ex - circlePoint[0], ey - circlePoint[1])
return d2 <= circleRadius
def houseCollision(pt1, pt2):
for i, h in enumerate(houses):
if lineInCircle(pt1, pt2, h):
return 1
return 0
def generatePath(start, end):
points = [start]
if not houseCollision(start, end):
points.append(end)
return points
while True:
next = generatePos()
while houseCollision(points[-1], next):
next = generatePos()
points.append(next)
if not houseCollision(next, end):
points.append(end)
return points
def angle(A, B):
ax = A.getX()
ay = A.getY()
bx = B.getX()
by = B.getY()
return math.atan2(by-ay, bx-ax)
class PetMoverAI(FSM):
def __init__(self, pet):
self.pet = pet
FSM.__init__(self, 'PetMoverAI-%d' % self.pet.doId)
self.chaseTarget = None
self.__seq = None
self.fwdSpeed = 10.0
self.rotSpeed = 360.0
self.__moveFromStill()
self.__chaseCallback = None
def enterStill(self):
taskMgr.doMethodLater(random.randint(15, 60), self.__moveFromStill, self.pet.uniqueName('next-state'))
def exitStill(self):
taskMgr.remove(self.pet.uniqueName('next-state'))
def __moveFromStill(self, task=None):
choices = ["Wander"]
nextState = random.choice(choices)
self.request(nextState)
def enterWander(self):
target = self.getPoint()
self.walkToPoint(target)
def getPoint(self):
x, y = generatePos()
return Point3(x, y, 0)
def walkToPoint(self, target):
here = self.pet.getPos()
dist = Vec3(here - target).length()
self.__seq = Sequence(Func(self.pet.lookAt, target), Func(self.pet.setP, 0), self.pet.posInterval(dist / self.fwdSpeed, target, here),
Func(self.__stateComplete))
self.__seq.start()
def exitWander(self):
if self.__seq:
self.__seq.pause()
self.__seq = None
def __stateComplete(self):
try:
self.request("Still")
except:
pass
def destroy(self):
self.demand("Off")
def setFwdSpeed(self, speed):
self.fwdSpeed = speed
def getFwdSpeed(self):
return self.fwdSpeed
def setRotSpeed(self, speed):
self.rotSpeed = speed
def getRotSpeed(self):
return self.rotSpeed
def lock(self):
if self.state != "Still":
self.demand("Still")
def enterChase(self, target=None):
if not target:
target = hidden.attachNewNode('target')
target.setPos(self.getPoint())
pos = target.getPos()
theta = angle(self.pet.getPos(), pos) * (math.pi / 180)
dx = dist * math.cos(theta)
dy = dist * math.sin(theta)
self.walkToPoint(Point3(pos.getX() - dx, pos.getY() - dy, pos.getZ()))
def exitChase(self):
if self.__chaseCallback:
self.__chaseCallback()
self.__chaseCallback = None
if self.__seq:
self.__seq.pause()
self.__seq = None
def walkToAvatar(self, av, callback=None):
if callback:
self.__chaseCallback = callback
self.demand("Chase", av)