Let's get a feel for how this works by creating a preloader to load our models before the game starts.

  1. Create a blank new file in Notepad++. Save it as PreloaderClass_01.py. Then, add these two import lines to the top of the file:
    from direct.gui.DirectGui import *
    from pandac.PandaModules import *
    
  2. It would be easy to just have the preloader load the models and be done with it, but that wouldn't be any different than having a black screen when the game loads. We'd accomplish nothing. We need our preloader to show the loading progress, and that means we need to create some GUI elements. Add in the class definition and __init__ method, and have them look like this:
    class Preloader:
    def __init__(self, fonts):
    self.createGraphics(fonts)
    
  3. Next, we'll add in that createGraphics method we just made a call to. We're going to do this in one big shot because the method is going to look very similar to the methods we used to create the HUD components. Even so, let's make sure we get everything right.
    def createGraphics(self, fonts):
    self.modTS = TextureStage("Modulate")
    self.modTS.setMode(TextureStage.MModulate)
    self.frame = DirectFrame(frameSize = (-.3, .3, -.2, .2),
    frameColor = (1,1,1,0),
    parent = base.aspect2d)
    loaderEgg = loader.loadModel("../Models/EnergyBar.egg")
    self.loaderBG = loaderEgg.find("**/EnergyBG")
    self.loaderBar = loaderEgg.find("**/EnergyBar")
    self.loaderFrame = loaderEgg.find("**/EnergyFrame")
    self.loaderBG.reparentTo(self.frame)
    self.loaderBar.reparentTo(self.loaderBG)
    self.loaderFrame.reparentTo(self.loaderBG)
    self.loaderBG.setPos(0, 0, -.2)
    alpha = loader.loadTexture("../Images/LoaderAlpha.png")
    alpha.setFormat(Texture.FAlpha)
    alpha.setWrapU(Texture.WMClamp)
    self.loaderBar.setTexture(self.modTS, alpha)
    self.text = DirectLabel(
    text = "Loading Suicide Jockeys...",
    text_font = fonts["orange"], text_scale = .1,
    text_fg = (1,1,1,1), relief = None,
    text_align = TextNode.ACenter,
    parent = self.frame)
    return
    
  4. Scroll back up to the __init__ method and add this line to it:
    self.prepLoadGroup()
    
  5. That line will call this new method, which we should add to the bottom of the class:
    def prepLoadGroup(self):
    self.models = ["../Models/Track.egg",
    "../Models/Planet.egg",
    "../Models/Ground.egg",
    "../Models/LinearPinkSkySphere.bam",
    "../Models/TargetCone.bam",
    "../Models/ShieldBar.egg",
    "../Models/SpeedBar.egg",
    "../Models/EnergyBar.egg",
    "../Models/RedCycle.bam",
    "../Models/RedTurr.bam",
    "../Models/YellowCycle.bam",
    "../Models/YellowTurr.bam",
    "../Models/GreenCycle.bam",
    "../Models/GreenTurr.bam",
    "../Models/BlueCycle.bam",
    "../Models/BlueTurr.bam",
    "../Models/Disc.bam",
    "../Models/MachineGun.bam",
    "../Models/Cannon.bam",
    "../Models/LaserFlash.bam",
    "../Models/LaserProj.bam",
    "../Models/Explosions/Laserburst1.bam",
    "../Models/Explosions/Laserburst2.bam",
    "../Models/Explosions/Laserburst3.bam"]
    self.totalItems = len(self.models)
    return
    
  6. Scroll back up to the __init__ method again; we have a bit more code to add there. Before we start loading anything, we need to set the loading bar to be initially empty, force a new frame to be displayed, and create a variable that will let us count how many things we've loaded so far. Add these lines to the bottom of the __init__ method:
    self.loaderBar.setTexOffset(self.modTS, .015, 0)
    base.graphicsEngine.renderFrame()
    base.graphicsEngine.renderFrame()
    self.itemCount = 0
    
  7. We're all set to start loading things now. We'll use a for loop to iterate over the list of paths to make it happen:
    for M in self.models:
    item = loader.loadModel(M)
    self.itemCount += 1
    progress = self.itemCount / float(self.totalItems)
    self.loaderBar.setTexOffset(self.modTS,
    -progress + .015, 0)
    base.graphicsEngine.renderFrame()
    base.graphicsEngine.renderFrame()
    
  8. There's just one more thing to do in the __init__ method. Add this line to the very bottom of the method:
    self.destroy()
    
  9. And, finally, we need to add in that destroy method. Here it is; place it at the bottom of the class:
    def destroy(self):
    self.loaderBG.removeNode()
    self.text.destroy()
    self.frame.destroy()
    
  10. Resave the file with the same name and open WorldClass_00.py.
  11. Add this line to the imports of custom classes:
    from PreloaderClass_01 import Preloader
    
  12. Find the spot in the __init__ method where we load up our fonts. Right after that, add this line:
    preloader = Preloader(self.fonts)
    
  13. Resave the file with the name WorldClass_01.py and run the game. We'll see something like this as the game loads up:
Time for action - creating a preloader to load models