I am trying to add a spherical hitbox around the player in my program. However, when I try and show the sphere, it doesn’t show. I don’t know what is wrong. Thanks in advance for your help.
Here is my code (excuse my excessive comments, I am an idiot who will forget things if they aren’t clear):
#imports animatable objects
from direct.actor.Actor import Actor
from panda3d.core import Vec3
#this are shapes for the collision boxes of the entities
from panda3d.core import CollisionTube, CollisionNode, CollisionSphere, CollisionHandlerQueue
FRICTION = 200
#Entity holds the player, hooligan and trap
class Entity():
def __init__(self,pos,modelName,modelAnimations,colliderName):
self.entityInstance = Actor(modelName,modelAnimations)
self.entityInstance.reparentTo(render)
self.entityInstance.setPos(pos)
self.moving = None
#this sets velocity and acceleration
self.velocity = Vec3(0,0,0)
self.acceleration = 50.0
self.speedCap = 50
#This adds a collision node, so that collisions can registered
pcColNode = CollisionNode(colliderName)
#this assigns a tube shaped collision box
pcColNode.addSolid(CollisionSphere(0,0,0,8))
self.collider = self.entityInstance.attachNewNode(pcColNode)
self.collider.show()
def update(self,time):
#the entity adjusts itself to the distance
#it should have moved in the time since last update
self.entityInstance.setPos(self.entityInstance.getPos() + self.velocity*time)
speed=self.velocity.length()
#this checks if the speed variable exceed the speedCap variable
#if so, it changes the velocity and speed to reflect the speedCap
if speed > self.speedCap:
self.velocity.normalize()
self.velocity = self.velocity * self.speedCap
speed = self.speedCap
#this checks whether the player has let go of the w button
if not self.moving:
#if they have, it calculates how much the player should have slowed down
frictionValue = FRICTION*time
#if the player should have stopped by now,
#it sets the velocity to 0
if frictionValue > speed:
self.velocity.set(0,0,0)
#otherwise, it slows down the velocity to the appropriate amount.
else:
#this creates a friction vector (which will be a negative number)
#based on how much the player should have slowed down
#if then 'adds' (it's a negative number) from self.velocity
#which scales down the player's velocity
frictionVector = -self.velocity
frictionVector.normalize()
frictionVector = frictionVector * frictionValue
self.velocity = self.velocity + frictionVector
#PC stands for Player Character
class PC(Entity):
def __init__(self):
Entity.__init__(self,
#this sets the initial location of the panda
Vec3(0,0,0),
"models/panda-model",
{
#I will eventually put animations here
},
"player"
)
#This scales the panda down to fit on the screen
self.entityInstance.setScale(0.010,0.010,0.010)
base.collisionHandler.addCollider(self.collider,self.entityInstance)
base.collisionDetector.addCollider(self.collider,base.collisionHandler)
#this contains things that need to be updated as the PC class runs
def update(self, keys, time):
Entity.update(self,time)
#tells us whether the player is currently moving
self.moving = False
#If a movement key is currently being pressed
#or has been released
#this moves in the Panda character
#in the correct direction
if keys["up"]:
self.moving=True
self.velocity.addY(self.acceleration*time)
if keys["left"]:
self.moving = True
self.velocity.addX(-self.acceleration*time)
if keys["down"]:
self.moving = True
self.velocity.addY(-self.acceleration*time)
if keys ["right"]:
self.moving = True
self.velocity.addX(self.acceleration*time)
#self.pandaActor = Actor("models/panda-model")
#assigns panda model to scene graph, rendering it
#self.pandaActor.reparentTo(self.render)
#sets position to center of screen
#self.pandaActor.setPos(0,0,0)
#scales down panda to fit in center of screen
#self.pandaActor.setScale(0.010,0.010,0.010)
#import statements go here
#showbase is used to display the Panda3D window to the user
from direct.showbase.ShowBase import ShowBase
#window properties is used to decide the size and other
#miscellaneous properties of the windows
from panda3d.core import WindowProperties
#screen info is used to detect the size of the user's
#monitor so that the window is appropriately sized
#only get_monitors is installed because that is the only module used
from screeninfo import get_monitors
#directGUI is used to create the menu for the game
from direct.gui.DirectGui import *
#actor is used to create moving 'actors' like enemies, traps and the player
from direct.actor.Actor import Actor
#Panda3Actors holds all the 'actors' used in this program
from Panda3Actors import *
#Vec3 and Vec4 are used to store floating point vectors
from panda3d.core import Vec3,Vec4
#these are all used for the Panda3D physics engine
from panda3d.core import CollisionTube,CollisionNode, CollisionTraverser, CollisionHandlerPusher, CollisionSphere
#Game is the class that contains/ will contain most of the game's framework e.g arena, physics
#It is also the first class used upon starting the game
class Game(ShowBase):
def __init__ (self):
#ShowBase loads most of Panda3D modules
#Here, it loads the window the game is displayed on
ShowBase.__init__ (self)
#this fetches the resolution of the monitor the user is using
monitor = get_monitors()
#get_monitors() returns a list, a string is needed
#Converts monitor to a string so that string manipulation can be used
monitor = str(monitor)
#This function takes a search term and string index
#Uses them to extract a substring of the monitor string containing the
#height or width featured in the monitor string
def findScreenAttribute(searchTerm,endPoint):
startPos = monitor.find(searchTerm)
endPos = monitor[startPos:endPoint]
pos1 = endPos.find("=")
pos2 = endPos.find(",")
return(endPos[pos1+1:pos2])
#Here the function is called, to find the resolution
width = (findScreenAttribute("width=",30))
height = (findScreenAttribute("height=",50))
#These values are converted to integers so they can be used by SetSize
width = int(width)
height = int(height)
#The window size is set to the width and height variables
WindowSize = WindowProperties()
WindowSize.setSize(width,height)
self.win.requestProperties(WindowSize)
#This is the whole opening menu
self.startMenuBackground = DirectFrame(frameColor = (0, 0, 0, 1),
frameSize = (-1, 1, -1, 1),
parent = render2d)
self.startMenu = DirectFrame(frameColor = (1,1,1,0))
#this sets the font of all menus
self.font = loader.loadFont("Assets/ModeSeven.ttf")
#The title, e.g. "Panda 3" in center of page
title = DirectLabel(text = "Panda 3",
parent = self.startMenu,
pos = (0,0, 0.7),
scale = 0.3,
text_fg = (1,1,1,1),
#Relief is the background for the text, this removes the default grey background
relief = None,
text_font = self.font
)
#pandaImage is the image that displays in the centre of the screen
pandaImage = OnscreenImage(image='Assets/PandaImage.png', pos = (0,0,0),
scale = 0.3,
parent=self.startMenu
)
#the START button on the opening menu
btn = DirectButton(text = "START",
command = self.gameStart,
parent = self.startMenu,
scale = 0.2,
pos = (0,0,-0.7),
frameSize = (-2, 2, -1, 1.5),
#this removes the default border from button, making it a plain square
relief = DGG.FLAT,
#this sets button to white
frameColor = (1,1,1,1),
text_font = self.font
)
btn = DirectButton(text = "LEADERBOARD",
command = self.openLeaderboard,
parent = self.startMenu,
scale = 0.2,
pos = (-0.95,0,-0.7),
text_scale = 0.5,
frameSize = (-2, 2, -1, 1),
#removes border from button, making it plain square
relief = DGG.FLAT,
#this sets button to white
frameColor = (1,1,1,1),
text_font = self.font
)
btn = DirectButton(text = "EXIT",
command = self.quitGame,
parent = self.startMenu,
scale = 0.2,
pos = (0.95,0,-0.7),
text_scale = 0.7,
frameSize = (-2, 2, -1, 1),
#removes border from button, making it a plain square
relief = DGG.FLAT,
#this sets button to white
frameColor = (1,1,1,1),
text_font = self.font
)
self.startMenu.show()
#Panda3D has default mouse control, I am not using that so I disable it
self.disableMouse()
#Panda3D operates on a scene graph, a series of interconnected nodes
#that dictate the heirarchy of objects
#this is how Panda3D renders objects
#this loads the model
self.arena = loader.loadModel("Assets/Arena.obj")
#this loads the texture
arenaTexture = loader.loadTexture("Assets/ArenaTexture.psd")
#this puts the texture on the model
self.arena.setTexture(arenaTexture)
#this adds the arena model to the scene graph
#allowing it to be rendered
self.arena.reparentTo(render)
#self.startMenu.hide()
#self.startMenuBackground.hide()
#.obj models load into Panda3D sideways
#this rotates the model so that it's a horizontal orientation
#P stands for Pitch
self.arena.setP(90)
#This sets the camera to a high position so that it can view the arena
self.camera.setPos(0,0,200)
#this rotates the camera so it's facing down
self.camera.setP(-90)
self.keyLog = {
"up": False,
"left": False,
"down": False,
"right": False}
#This notifies Panda3D to check if these keys change
#And registers the change if they do
self.accept("w", self.changeKeyLog, ["up",True])
self.accept("w-up", self.changeKeyLog, ["up",False])
self.accept("a", self.changeKeyLog, ["left",True])
self.accept("a-up",self.changeKeyLog, ["left",False])
self.accept("s", self.changeKeyLog, ["down",True])
self.accept("s-up", self.changeKeyLog, ["down",False])
self.accept("d", self.changeKeyLog, ["right", True])
self.accept("d-up", self.changeKeyLog, ["right", False])
#this detects when collisions happen
self.collisionDetector = CollisionTraverser()
#this dictates how the program responds when a collision happens
self.collisionHandler = CollisionHandlerPusher()
self.collisionHandler.setHorizontal(True)
#This is the task manager for Panda3D
#I will use the taskUpdate method for things that need to be checked
#As the program runs e.g. player movement
self.taskUpdate = taskMgr.add(self.update, "update")
self.pc = None
def update(self,task):
#this sets timeElapsed to the time elapsed since the last update
timeElapsed=globalClock.getDt()
#this checks if the pc is created yet
#If so, it calls the pc.update method(in Panda3Actors)
#passing in the keyLog and the task
if self.pc is not None:
self.pc.update(self.keyLog,timeElapsed)
return task.cont
#This updates the values in the keylog dictionary
#It's used to correct the dictionary after keys are pressed by the user
def changeKeyLog(self, key, keyState):
self.keyLog[key] = keyState
print("Testing: ", key, " == ", keyState)
def gameStart(self):
self.startMenu.hide()
self.startMenuBackground.hide()
#Player is created
self.pc = PC()
print("Button clicked")
def openLeaderboard(self):
print("Button clicked")
def quitGame(self):
print("Button Clicked")
#runGame will be the first process to run, as it starts the game
runGame = Game()
runGame.run()