I have an idea of game that it will have a pet system.
I want my pet follow the path that player just walk by.
but I can’t imagine how to do it.
can I have some advice?
now I have these sort of codes. but it doesn’t do as I want yet.
(please feel free to let me know if this way doesn’t work)
import random
from math import ceil
from common import Common
from interface import DamageFrame
from piece import Seedbed
from item import *
from panda3d.core import CollisionBox, CollisionCapsule, Vec2, Vec3, Point2, Point3, TextNode
from direct.actor.Actor import Actor
from direct.gui.DirectFrame import DirectFrame
from direct.interval.IntervalGlobal import Sequence, Func, Wait
from direct.showbase.PythonUtil import fitDestAngle2Src
class Character():
# Default atrributes
model = "assets/models/King"
center = Point3(-0.3, -0.3, 0)
shape = Point3(0.3, 0.3, 1.25)
collSurface = Point3(0.2, 0.2, 0)
yVector = Vec2(0, 1)
pos2d = Point2()
update = True
speed = 1
run_speed = 2
attack_speed = 1
attackAnimDelay = 0.001
dodge_force = 10
dodge_distance = 1
dodge_position = Point3(0, 0, 0)
dodge_direction = Point3(0, 0, 0)
dodge_key = False
jump_force = 0.25
jump_count = 0
jump_limit = 2
toAngle = 180
is_attacking = False
is_moving = False
is_jumping = False
is_blocking = False
is_dodging = False
is_on_floor = False
is_dead = False
is_changemap = True
into_mask = 4
from_mask = 1
action_into_mask = False
action_from_mask = 3
response_into_mask = 3
response_from_mask = False
relation = 0
regen = False
def __init__(self, pos=False):
# Default position/velocity/acceleration
self.name = self.__class__.__name__.replace("_", " ")
self.position = Vec3(0, 0, 0)
self.velocity = Vec3(0, 0, 0)
self.acceleration = Vec3(0, 0, 0)
# new generate object key
self.objKey = int(max([*Common.ShowBase.objectList], default=0))+1 if Common.ShowBase.objectList else 0
# Create actor model
self.obj = Actor(self.model)
self.obj.setScale(0.5)
self.obj.reparentTo(Common.ShowBase.render)
if pos is not False:
pos = Common.ShowBase.getSqrPos(pos)
self.position = pos
coll_box = CollisionBox(self.center, self.shape)
collider = Common.ShowBase.setCollisionHandler(
collSolid=coll_box,
IntoMask=self.into_mask,
FromMask=self.from_mask,
event=True,
queue=True,
collName='char-node'
)
collider.reparentTo(self.obj)
collider.node().setTag("char", str(self.objKey))
# Response Collider
coll_box = CollisionBox(self.center, self.shape)
self.action_collider = Common.ShowBase.setCollisionHandler(
collSolid=coll_box,
IntoMask=self.response_into_mask,
FromMask=self.response_from_mask,
queue=True,
collName='char-node'
)
self.action_collider.reparentTo(self.obj)
self.action_collider.node().setTag("char", str(self.objKey))
# Action Collider
coll_box = CollisionCapsule((0, 0.6, 0.5), (0, 1.25, 0.5), 0.25)
self.action_collider = Common.ShowBase.setCollisionHandler(
collSolid=coll_box,
IntoMask=self.action_into_mask,
FromMask=self.action_from_mask,
queue=True,
show=True,
collName='action-node'
)
self.action_collider.reparentTo(self.obj)
self.action_collider.node().setTag("char", str(self.objKey))
# Create an HUD
self.HUD = DirectFrame(
frameColor=(0, 0, 0, 0),
frameSize=(-0.15, 0.15, -0.25, 0.25),
parent=Common.Interface.gameGUI
)
self.HUD.setBin("HUD", 0)
text = TextNode('name')
text.setFont(Common.Interface.font)
text.setText(self.name)
text.setTextScale(0.06)
text.setTextColor(1, 1, 1, 1)
text.setAlign(TextNode.ACenter)
textNode = Common.ShowBase.render2d.attachNewNode(text)
textNode.setPos((0, 0, 0.2))
textNode.reparentTo(self.HUD)
textNode.hide()
# Append object to base
Common.ShowBase.charList[self.objKey] = { "from": self, "into": None }
Common.ShowBase.objectList[self.objKey] = self
setattr(Common.ShowBase, self.__class__.__name__.lower(), self)
self.atkseq = Sequence(Wait(self.attackAnimDelay), Func(self.startOffense), Wait(self.attack_speed), Func(self.finishOffense))
self.defseq = Sequence(Func(self.startDefense), Wait(1))
self.dgeseq = Sequence(Func(self.startDodge), Wait(0.5), Func(self.finishDodge))
self.regen = Sequence(Wait(5), Func(self.updateRegeneration))
self.regen.loop()
class Ally(Character):
type = "pet"
targetType = ("monster")
attackAnimDelay = 1
attackDistance = 0.75
traceDistance = 8.5
is_tracing = False
speed = 0.3
mobility = True
aggressive = False
def __init__(self, pos=False):
super().__init__(pos)
Common.ShowBase.taskMgr.add(self.updateTracking, "updateTracking")
def updateTracking(self, task):
# try:
dt = globalClock.getDt()
fromAngle = self.obj.getH()
target = self.findTarget()
vectorToTarget = target['coordinates']
vectorToTarget2D = target['heading']
distanceToTarget = target['distance']
trackToAttack = target['trackToAttack']
if trackToAttack is not False:
if self.aggressive is not False and distanceToTarget < self.attackDistance * self.traceDistance:
self.is_tracing = True
if self.is_tracing is not False and distanceToTarget < self.attackDistance * self.traceDistance:
if not self.is_attacking:
heading = self.yVector.signedAngleDeg(vectorToTarget2D)
self.obj.hprInterval(0.05, (fitDestAngle2Src(fromAngle, heading), 0, 0)).start()
else:
self.is_tracing = False
if self.mobility is not False and self.is_tracing is not False:
if not self.is_attacking and distanceToTarget > self.attackDistance and distanceToTarget < self.attackDistance * self.traceDistance:
vectorToTarget.normalize()
self.velocity += vectorToTarget * self.speed * dt
else:
self.velocity.set(0, 0, 0)
if not self.is_attacking and distanceToTarget <= self.attackDistance:
self.doOffense()
else:
if not self.is_attacking:
heading = self.yVector.signedAngleDeg(vectorToTarget2D)
self.obj.hprInterval(0.05, (fitDestAngle2Src(fromAngle, heading), 0, 0)).start()
if distanceToTarget > 0.75:
vectorToTarget.normalize()
self.velocity += vectorToTarget * Common.ShowBase.player.speed * dt
else:
self.velocity.set(0, 0, 0)
# except:
# print("An exception occurred on \"updateTracking\"")
return task.cont
def findTarget(self):
target = False
enemyList = dict()
for i in Common.ShowBase.charList:
if Common.ShowBase.charList[i]['from'].type in self.targetType:
target = Common.ShowBase.charList[i]['from']
vectortoTarget = target.obj.getPos() - self.obj.getPos()
vectortoTarget2D = vectortoTarget.getXy()
distanceToTarget = vectortoTarget2D.length()
enemyList.update({i: {"coordinates": vectortoTarget, "heading": vectortoTarget2D, "distance": distanceToTarget, "trackToAttack": True}})
if enemyList:
target = min(enemyList.items(), key=lambda x: x[1]['distance'])[1]
if target is not False and target['distanceToTarget'] < self.attackDistance * self.traceDistance:
return target
else:
vectortoTarget = Common.ShowBase.player.obj.getPos() - self.obj.getPos()
vectortoTarget2D = vectortoTarget.getXy()
distanceToTarget = vectortoTarget2D.length()
return {"coordinates": vectortoTarget, "heading": vectortoTarget2D, "distance": distanceToTarget, "trackToAttack": False}
class Robot(Ally):
def __init__(self, pos=False):
Ally.__init__(self, pos)
self.status = { "hp":100, "sp":10, "mp":0, "maxhp":100, "maxsp":10, "maxmp":0, "patk":1, "pdef":1, "matk":1, "mdef":1, "gold":0 }