Hi, i’ve only recently started learning how to do panda3d/python and it’s been a really rough experience for me. Honestly, it’s one of the toughest engines/languages i’ve ever learnt.
I’ve been having annoying indentation issues since forever, but i just cannot see what is wrong with my code. Maybe another pair of eyes would help. Thanks.
import sys
import direct.directbase.DirectStart
import math
from direct.showbase.DirectObject import DirectObject
from direct.showbase.ShowBase import ShowBase
from direct.showbase.InputStateGlobal import inputState
from direct.directtools.DirectGeometry import LineNodePath
from direct.gui.OnscreenText import OnscreenText
from direct.gui.DirectGui import *
from direct.gui.OnscreenImage import OnscreenImage
# the above import helps with keyboard
from panda3d.core import AmbientLight
from panda3d.core import DirectionalLight
from panda3d.core import Vec2
from panda3d.core import Vec3
from panda3d.core import Vec4
from panda3d.core import Material
from panda3d.core import Point3
from panda3d.core import TransformState
from panda3d.core import BitMask32
from panda3d.core import Material
from panda3d.bullet import BulletWorld
from panda3d.bullet import BulletPlaneShape
from panda3d.bullet import BulletBoxShape
from panda3d.bullet import BulletSphereShape
from panda3d.bullet import BulletRigidBodyNode
from panda3d.bullet import BulletDebugNode
from panda3d.bullet import ZUp
from panda3d.bullet import BulletGhostNode
class Main(DirectObject):
#Define the state of the game and level
gameState = 'INIT'
gameLevel = 1
count = 0
win = False
timer = 60
# _____INIT_____
def __init__(self):
base.setBackgroundColor(0.1, 0.1, 0.8, 1)
base.setFrameRateMeter(True)
#Position of camera
base.cam.setPos(0, -25, 10)
base.cam.lookAt(0, 0, 0)
#base.cam.lookAt(self.boxN.getPos())
#Splashscreen
self.imageObject = OnscreenImage(image = 'media/SplashScreen.jpg', pos = (0,0,0), scale = (1.4,1,1))
# Stuff
self.lastBullet = 0
# Light
alight = AmbientLight('ambientLight')
alight.setColor(Vec4(0.5, 0.5, 0.5, 1))
alightNP = render.attachNewNode(alight)
dlight = DirectionalLight('directionalLight')
dlight.setDirection(Vec3(1, 1, -1))
dlight.setColor(Vec4(0.7, 0.7, 0.7, 1))
dlightNP = render.attachNewNode(dlight)
render.clearLight()
render.setLight(alightNP)
render.setLight(dlightNP)
# Input
self.accept('escape', self.doExit)
self.accept('r', self.doReset)
self.accept('f1', self.toggleWireframe)
self.accept('f2', self.toggleTexture)
self.accept('f3', self.toggleDebug)
self.accept('f5', self.doScreenshot)
#self.accept('1', self.doShoot, [True])
#self.accept('2', self.doShoot, [False])
inputState.watchWithModifiers('forward', 'w')
inputState.watchWithModifiers('up', 'q')
inputState.watchWithModifiers('reverse', 's')
inputState.watchWithModifiers('down', 'e')
inputState.watchWithModifiers('turnLeft', 'a')
inputState.watchWithModifiers('turnRight', 'd')
inputState.watchWithModifiers('shoot', 'space')
self.pFrom = Point3(0,0,0)
self.pTo = Point3(0,0,0)
x = 0
x = 0
#Continue text
self.welcomeText = OnscreenText(text = 'Press space key to start', pos = (-0.5, 0.9), scale = 0.07)
self.welcomeText.hide()
# ^ hides text
# Task
taskMgr.add(self.update, 'updateWorld')
# Physics
self.setup()
# ____HANDLER_____
def processInput(self, dt):
force = Vec3(0,0,0)
torque = Vec3(0,0,0)
tankHead = self.boxNP.getH()
headGradian = tankHead * (math.pi/180.0)
x = 1.0*math.sin(headGradian)
y = 1.0*math.cos(headGradian)
#force.setX(-x)
#force.setY(y)
if inputState.isSet('forward'):
force.setX(-x)
force.setY(y)
if inputState.isSet('reverse'):
force.setX(x)
force.setY(-y)
#if inputState.isSet('left'):
# force.setX(-headX)
# force.setX(headX)
#if inputState.isSet('right'):
# force.setY(headY)
if inputState.isSet('turnLeft'): torque.setZ(0.5)
if inputState.isSet('turnRight'): torque.setZ(-0.5)
if inputState.isSet('up'):
self.pTo.addZ(0.5)
if inputState.isSet('down'):
self.pTo.addZ(-0.5)
if (self.lastBullet <= 0):
if inputState.isSet('shoot'):
self.doShoot(True)
force *= 20.0
torque *= 5.0
self.boxNP.node().setActive(True)
self.boxNP.node().applyCentralForce(force)
self.boxNP.node().applyTorque(torque)
def doExit(self):
self.cleanup()
sys.exit(1)
def doReset(self):
self.cleanup()
self.setup()
self.timerText.hide()
self.text.hide()
base.cam.setPos(self.boxNP.getPos().x,self.boxNP.getPos().y - 25, self.boxNP.getPos().z + 15)
base.cam.lookAt(self.boxNP.getPos())
self.gameState = 'PLAY'
def toggleWireframe(self):
base.toggleWireframe()
def toggleTexture(self):
base.toggleTexture()
def toggleDebug(self):
if self.debugNP.isHidden():
self.debugNP.show()
else:
self.debugNP.hide()
def doScreenshot(self):
base.screenshot('Bullet')
def drawLines(self):
# draws lines for the ray
self.lines.reset()
# lines reset for translation purpose
self.lines.drawLines([(self.pFrom,self.pTo)])
self.lines.create()
def drawBounding(self):
self.boundingNorth.reset()
self.boundingNorth.drawLines([(self.b1From,self.b1To)])
self.boundingNorth.create()
self.boundingSouth.reset()
self.boundingSouth.drawLines([(self.b2From, self.b2To)])
self.boundingSouth.create()
self.boundingWest.reset()
self.boundingWest.drawLines([(self.b3From, self.b3To)])
self.boundingWest.create()
self.boundingEast.reset()
self.boundingEast.drawLines([(self.b4From, self.b4To)])
self.boundingEast.create()
def getDirection(self, getObject, getLength):
heading = getObject.getH()
pitch = getObject.getP()
headingRadian = math.radians(heading)
pitchRadian = math.radians(pitch)
z = getLength*math.sin(pitchRadian)
adjacent = getLength*math.cos(pitchRadian)
x = adjacent*math.sin(headingRadian)
y = adjacent*math.cos(headingRadian)
x*=-1
return Vec3(x,y,z)
def doShoot(self, ccd):
# Get from/to points from mouse click
#pMouse = base.mouseWatcherNode.getMouse()
pFrom = self.boxNP.getPos() + self.getDirection(self.boxNP, 1.425)#1.425
pTo = self.boxNP.getPos() + self.getDirection(self.boxNP, 5.0)
# initial velocity
v = pTo - pFrom
#ratio = v.length()/40
v.normalize()
v *= 25.0
# Create bullet
shape = BulletBoxShape(0.2)
bullet = BulletRigidBodyNode('Bullet')
bulletNP = self.worldNP.attachNewNode(bullet)
bulletNP.node().addShape(shape)
bulletNP.node().setMass(1.0)
bulletNP.node().setDeactivationEnabled(False)
bulletNP.node().setLinearVelocity(v)
bulletNP.setPos(pFrom)
bulletNP.setHpr(self.boxNP.getHpr())
print bulletNP.getPos()
bulletNP.setCollideMask(BitMask32.allOn())
self.bulletvisualNP = loader.loadModel('smiley')
self.bulletvisualNP.setScale(0.3)
self.bulletvisualNP.clearModelNodes()
self.bulletvisualNP.reparentTo(bulletNP)
self.lastBullet = 3
if ccd:
bulletNP.node().setCcdMotionThreshold(1e-7)
bulletNP.node().setCcdSweptSphereRadius(0.50);
self.world.attachRigidBody(bulletNP.node())
# Remove the bullet again after 10 seconds
taskMgr.doMethodLater(1,self.doRemove,'doRemove', extraArgs=[bulletNP], appendTask=True)
def playGame(self):
print "Entered playGame function"
self.menuImage.hide()
self.playButton.hide()
self.instButton.hide()
self.exitButton.hide()
self.text.setText("Press ADWS to aim. 1 to fire")
self.gameState = 'PLAY'
def Inst(self):
self.gameState = 'INST'
print "Entered instructions function"
self.playButton.hide()
self.instButton.hide()
self.exitButton.hide()
self.backButton = DirectButton( text = ("Back"), scale = .1, command = self.doContinue)
def doContinue(self):
if (self.gameState == 'INIT') or (self.gameState == 'INST'):
self.gameState = 'MENU'
self.imageObject.hide()
self.menuImage.show()
# Add Buttons here
self.playButton = DirectButton( text = ("Start Game"), scale =.2,pos =(0,0,0.5), command =self.playGame)
self.instButton = DirectButton( text = ("Instructions"), scale = .2, command = self.Inst)
self.exitButton = DirectButton( text = ("Exit"), scale = .2,pos=(0,0,-0.5), command = self.doExit)
return
if self.gameState == 'NEXT':
self.gamelevel += 1
self.doReset()
def update(self, task):
dt = globalClock.getDt()
if self.gameState == "INIT":
#Progress bar can be implemented here
self.timerText.hide()
if self.count == 0:
loader.loadModel('smiley')
self.count +=1
if self.count == 1:
loader.loadModel('frowney')
#splashscreen
self.menuImage = OnscreenImage( image = 'media/Menu.jpg', pos = (0,0,0), scale=(1.4,1,1))
self.menuImage.hide()
self.count+=1
if self.count == 2:
self.text.show()
#self.imageObject.hide()
self.accept('space', self.doContinue)
#waits for a key press
if self.gameState == 'PLAY':
base.cam.setPos(0,-50,18)
base.cam.lookAt(self.boxNP.getPos())
#base.cam.setH(self.boxNP.getH())
self.processInput(dt)
self.timer -= dt;
self.lastBullet -= dt;
self.timerText.setText("Time Left: %s" % int(self.timer))
self.timerText.show()
self.lineCollision()
self.drawBounding()
#self.processContacts()
self.world.doPhysics(dt, 20, 1.0/180.0)
self.drawLines()
if self.gameState == 'INST':
self.processInput(dt)
if self.gameState == 'NEXT':
self.world.doPhysics(dt, 20, 1.0/180.0)
return task.cont
#INIT - load everything
#PLAY - Process userinput, check collision
#NEXT - Increase game level and reset game (check doReset, it should go back to gameState)
#Process Contacts, checks contacts between bullets and boxes.
def doRemove(self,bulletNP, task):
self.world.removeRigidBody(bulletNP.node())
self.bulletvisualNP.removeNode()
if (self.win == False):
self.text.setText("Failed! Press Space to continue!")
return task.done
def lineCollision(self):
result1 = self.world.rayTestAll(self.b1From, self.b1To)
if result1.hasHits():
for hit in result1.getHits():
self.boxNP.setPos(self.boxNP.getPos().x, hit.getHitPos().y-2, hit.getHitPos().z)
result2 = self.world.rayTestAll(self.b2From, self.b2To)
if result2.hasHits():
for hit in result2.getHits():
self.boxNP.setPos(self.boxNP.getPos().x, hit.getHitPos().y+2, hit.getHitPos().z)
result3 = self.world.rayTestAll(self.b3From, self.b3To)
if result3.hasHits():
for hit in result3.getHits():
self.boxNP.setPos(self.boxNP.getPos().x+2, hit.getHitPos().y, hit.getHitPos().z)
result4 = self.world.rayTestAll(self.b4From, self.b4To)
if result4.hasHits():
for hit in result4.getHits():
self.boxNP.setPos(self.boxNP.getPos().x-2, hit.getHitPos().y+2, hit.getHitPos().z)
# ____TASK___
#def processContacts(self):
#for box in self.boxes:
# result = self.world.contactTestPair(box, self.smiley)
# if result.getNumContacts() > 0:
# self.text.setText("Success")
# self.gameState = 'NEXT'
# self.win = True
def cleanup(self):
self.world = None
self.worldNP.removeNode()
self.worldNP = None
self.lines.reset()
# ____SETUP___
def setup(self):
self.worldNP = render.attachNewNode('World')
# Stuff Placement
self.boxes = []
self.createBox(Vec3(8,8,1),Vec3(0,0,23))
# World
self.debugNP = self.worldNP.attachNewNode(BulletDebugNode('Debug'))
self.debugNP.show()
self.world = BulletWorld()
self.world.setGravity(Vec3(0, 0, -9.81))
self.world.setDebugNode(self.debugNP.node())
# Plane
shape = BulletPlaneShape(Vec3(0, 0, 1), 0)
body = BulletRigidBodyNode('Ground')
bodyNP = self.worldNP.attachNewNode(body)
bodyNP.node().addShape(shape)
bodyNP.setPos(0, 0, -1)
bodyNP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(bodyNP.node())
# Aiming line
self.lines = LineNodePath(parent = render, thickness = 3.0, colorVec = Vec4(1,0,0,1))
# Bounding
self.boundingNorth = LineNodePath(parent = render, thickness =5.0, colorVec = Vec4(1,0,0,1))
self.b1From = Point3(-30,50,0)
self.b1To = Point3(30,50,0)
self.boundingSouth = LineNodePath(parent = render, thickness =5.0, colorVec = Vec4(1,0,0,1))
self.b2From = Point3(-30,-20,0)
self.b2To = Point3(30,-20,0)
self.boundingWest = LineNodePath(parent = render, thickness =5.0, colorVec = Vec4(1,0,0,1))
self.b3From = Point3(-30,50,0)
self.b3To = Point3(-30,-20,0)
self.boundingEast = LineNodePath(parent = render, thickness =5.0, colorVec = Vec4(1,0,0,1))
self.b4From = Point3(30,50,0)
self.b4To = Point3(30,-20,0)
# Boxes
shape = BulletBoxShape(Vec3(1, 1, 1))
self.boxNP = self.worldNP.attachNewNode(BulletRigidBodyNode('Tank'))
self.boxNP.node().setMass(5.0)
self.boxNP.node().addShape(shape)
self.boxNP.setPos(0, 0, 2)
self.boxNP.setCollideMask(BitMask32(0x0f))
self.world.attachRigidBody(self.boxNP.node())
visualNP = loader.loadModel('media/box.egg')
tex = loader.loadTexture('media/wood.png')
visualNP.setTexture(tex, 1)
visualNP.setPos(0,0,0)
visualNP.setScale(2)
visualNP.reparentTo(self.boxNP)
self.lines.reparentTo(self.boxNP)
#self.pFrom = Point3(self.boxNP.getPos() + self.getDirection(self.boxNP, 1.4))
#self.pTo = Point3(self.boxNP.getPos() + self.getDirection(self.boxNP, 2.0))
#self.pFrom = Point3(self.boxNP.getPos().x ,self.boxNP.getPos().y-1,self.boxNP.getPos().x)
#self.pTo = Point3(0,self.boxNP.getPos().y+20,self.boxNP.getPos().z+10)
self.pFrom = Point3(self.boxNP.getPos().x ,self.boxNP.getPos().y,self.boxNP.getPos().x) + self.getDirection(self.boxNP, 1.0)
self.pTo = Point3(self.boxNP.getPos()) + self.getDirection(self.boxNP, 5.0)
#setup text
self.text = OnscreenText(text = 'Sonicomi!~',pos = (-0.5, 0.5), scale = 0.09)
self.timerText = OnscreenText(text = '', pos = (0.5,0.5), scale = 0.09)
def createBox(self,size,pos):
shape = BulletBoxShape(size)
self.box = BulletRigidBodyNode('Obstacle')
bodyNP = self.worldNP.attachNewNode(self.box)
bodyNP.node().addShape(shape)
bodyNP.node().setMass(1.0)
bodyNP.node().setFriction(1.0)
bodyNP.node().setDeactivationEnabled(False)
bodyNP.setPos(pos)
bodyNP.setCollideMask(BitMask32.allOn())
self.world.attachRigidBody(bodyNP.node())
visNP = loader.loadModel('models/box.egg')
visNP.setScale(size*2)
visNP.clearModelNodes()
visNP.reparentTo(bodyNP)
self.boxes.append(self.box)
game = Main()
run()