I am making a space shooter. Enemies spawn at top of the screen, and when(if) they get to the bottom I want to unload them. I wrote a method similar to one from asteroids example:
-loads enemy as local variable and passes it to a list
After that in update task I move enemies and check which enemies have passed the remove border. Enemies who have done so are added to another list. Enemy list = Enemy list - Remove list. At the next frame I set remove list to empty.
So every reference to enemy who have crossed the line is removed, and it is also removed. But they don’t get removed, they are still rendered, just not updated.
Here is the code. Sry for not commenting everything, but didn’t start commenting it from beginning, and it is a bit long and unreadable.
#Import libraries
from direct.showbase.ShowBase import ShowBase
from direct.task import Task
from pandac.PandaModules import VBase4, VBase3, TransparencyAttrib
from panda3d.core import AmbientLight, DirectionalLight, Vec4, Vec3
import sys
import random
class Astro(ShowBase):
def __init__(self):
#First line must be all 0s, or first line of enemies will spawn early. Not sure why it happens, but not gonna bang my head a lot over it.
self.level1 = [[0,0,0,0,0,0,0,0,0],
[1,1,1,1,1,1,1,1,1],
[0,1,0,1,1,0,1,0,0],
[0,0,1,0,0,1,0,0,0]] #Level layout: 0-don't spawn anything, 1-spawn Spaceship, 2-HVF
ShowBase.__init__(self)
#Load Textures for faster loading when enemy requests it(not sure if ti works)
self.tex = []
for i in range(1,22):
Tex = self.loader.loadTexture("Models/Enemies/Trox/Tex"+str(i)+".jpg")
self.tex.append(Tex)
#Load backgrounds
self.background1 = self.loader.loadModel("Models/Background/Background.egg")
self.background2 = self.loader.loadModel("Models/Background/Background.egg")
self.background1.setPos(0,0,0)
self.background2.setPos(0,32,0)
self.background1.reparentTo(self.render)
self.background2.reparentTo(self.render)
base.oobe()
#Load player model
self.player = self.loader.loadModel("Models/Player/Player.egg")
self.player.setPos(0,-10,1)
self.player.reparentTo(self.render)
#Load player laser
self.laser = self.loader.loadModel("Models/Player/Laser/Laser.egg")
self.laser.setSy(0)
self.laser.setPos(self.player,0,0.95,-0.2)
self.laser.reparentTo(self.render)
#Camera stuff
base.disableMouse()
self.camera.setPos(0,0,45)
self.camera.setHpr(0,-90,0)
#Update Task
self.taskMgr.add(self.updateTask, "update")
#Keyboard setup
self.keyboardSetup()
#Lights
self.createEnvironment()
#base.oobe()
self.firetime = 1 #Time since last fire
self.firelength = 0#Length of fire
self.elapsedfire = 0#Used this to disable constant space pressing hack
self.line = 0#Map line used to spawn enemies
self.spawn = 0#If it is 1 spawn enemies
self.oldt=0#Used to check if enough time has passed since last spawn
self.HVFlist = []#List of High Velocity Fighter enemies
self.shiplist = []
def keyboardSetup(self):
self.keyMap = {"left":0, "right":0, "forward":0, "backward":0, "fire":0}
self.accept("escape", sys.exit)
self.accept("arrow_left", self.setKey, ["left",1])
self.accept("arrow_left-up", self.setKey, ["left",0])
self.accept("arrow_right", self.setKey, ["right",1])
self.accept("arrow_right-up", self.setKey, ["right",0])
self.accept("arrow_up", self.setKey, ["forward",1])
self.accept("arrow_up-up", self.setKey, ["forward",0])
self.accept("arrow_down", self.setKey, ["backward",1])
self.accept("arrow_down-up", self.setKey, ["backward",0])
self.accept("space", self.setKey, ["fire",1])
self.accept("space-up", self.setKey, ["fire",0])
#If spawn is enabled and map didn't come to the end, spawn enemy that is in the list
def loadEnemies(self):
if (self.spawn==1 and self.line<=len(self.level1)):
for n in range(9):
if self.level1[self.line-1][n-1] == 2:
HVF = self.loader.loadModel("Models/Enemies/HVF/fighter.egg")
self.HVFlist.append(HVF)
HVF.setPos(3.5*n-14,15,2)
HVF.setScale(0.1)
HVF.reparentTo(self.render)
if self.level1[self.line-1][n-1] == 1:
ship = self.loader.loadModel("Models/Enemies/Trox/ship.egg")
tex = self.loader.loadTexture("Models/Enemies/Trox/Tex"+str(random.randrange(1,23))+".jpg")
ship.setTexture(tex,1)
ship.setScale(1.25)
self.shiplist.append(ship)
ship.setPos(3.5*n-14,15,1)
ship.reparentTo(self.render)
def updateEnemies(self):
self.shipremove = []
for i in range(len(self.HVFlist)):
self.HVFlist[i-1].setY(self.HVFlist[i-1].getY()-3*self.time)
for i in range(len(self.shiplist)):
self.shiplist[i-1].setY(self.shiplist[i-1].getY()-10*self.time)
if self.shiplist[i-1].getY()<-13:
self.shipremove.append(self.shiplist[i-1])
self.shiplist = list(set(self.shiplist)-set(self.shipremove))
#Lights
def createEnvironment(self):
#Creates ambient light for brighter shadows
ambientLight = AmbientLight("ambientLight")
ambientLight.setColor(Vec4(.6, .6, .6, 1))
self.render.setLight(self.render.attachNewNode(ambientLight))
#Creates directional light to light up the player
directionalLight = DirectionalLight("directionalLight")
directionalLight.setColor(VBase4(0.8, 0.8, 0.5, 1))
dlnp = self.render.attachNewNode(directionalLight)
dlnp.setPos(0,0,260)
dlnp.lookAt(self.player)
self.render.setLight(dlnp)
def setKey(self, key, value):
self.keyMap[key] = value
#Update task
def updateTask(self, task):
self.time = (globalClock.getDt() * 1)#Frame independent time
self.oldt+=self.time#Spawn timer
if self.oldt>=2:#Spawn timer check
self.oldt=0
self.line+=1
self.spawn=1
else:
self.spawn=0
self.updateBack()
self.updatePlayer()
self.updateLaser()
self.loadEnemies()
self.updateEnemies()
return Task.cont
#Making the backgrounds tile
def updateBack(self):
speed = 1
self.background1.setY(self.background1.getY() - self.time * speed)
self.background2.setY(self.background2.getY() - self.time * speed)
if (self.background1.getY() < -30):
self.background1.setY(self.background2.getY() + 32)
if (self.background2.getY() < -30):
self.background2.setY(self.background1.getY() + 32)
#Making the player respond to controls
def updatePlayer(self):
speed = 10
bankspeed = 45
#If the player presses left arrow make him go left and rotate the ship
if (self.keyMap["left"]!=0):
if self.player.getX()>-14.5:
self.player.setX(self.player.getX()-speed*self.time)
if self.player.getX()<-14.5:
self.player.setX(-14.5)
self.player.setR(self.player.getR()-bankspeed*self.time)
if (self.player.getR() < -30):
self.player.setR(-30)
#Ditto for the right arrow
elif (self.keyMap["right"]!=0):
if self.player.getX()<14.5:
self.player.setX(self.player.getX()+speed*self.time)
if self.player.getX()>14.5:
self.player.setX(14.5)
self.player.setR(self.player.getR()+bankspeed*self.time)
if (self.player.getR() > 30):
self.player.setR(30)
#If neither right nor left arrow are pressed auto return
elif (self.player.getR() > 0):
self.player.setR(self.player.getR()-(bankspeed+1)*self.time)
if (self.player.getR() < 0):
self.player.setR(0)
elif (self.player.getR() < 0):
self.player.setR(self.player.getR()+(bankspeed+1)*self.time)
if (self.player.getR() > 0):
self.player.setR(0)
#Go forward
if self.keyMap["forward"] != 0:
if self.player.getY()<11:
self.player.setY(self.player.getY() + self.time * speed)
if self.player.getY()>11:
self.player.setY(11)
#Go backward
elif self.keyMap["backward"] != 0:
if self.player.getY()> -11:
self.player.setY(self.player.getY() - self.time * speed)
if self.player.getY()< -11:
self.player.setY(-11)
#Firing laser
def updateLaser(self):
self.firetime += self.time
self.laser.setPos(self.player,0,0.95,-0.2)
if (self.keyMap["fire"] != 0 and self.firetime >= 0.5):
self.laser.setSy(25)
self.firelength += self.time
if self.firelength > 1:
self.firetime = 0
self.firelength = 0
else:
self.laser.setSy(0)
self.elapsedfire += self.time
app = Astro()
app.run()