[Pygame] Level switch not working.

Started by
8 comments, last by NicoG 13 years, 1 month ago
I am trying to get it to switch levels whenever the boss is killed on the previous stage. I am not receiving an error whenever the code runs, but it isn't switching the stage at all. It should switch right after the boss dies.

Level.py

import pygame, random
from pygame.locals import *
from Constant import *

class Level(pygame.sprite.Sprite):
def __init__(self, id):
pygame.sprite.Sprite.__init__(self, self.containers)
self.id = id
if self.id == 1:
self.image = pygame.image.load(IMG_PATH + "Stage1.bmp")
self.image = self.image.convert()
self.speed = 0.5
self.finished = False
if self.id == 2:
self.image = pygame.image.load(IMG_PATH + "Stage2.bmp")
self.image = self.image.convert()
self.speed = 0.7
self.finished = False

self.rect = self.image.get_rect()
self.distance = 0
self.reset()

def reset(self):
self.rect.bottom = RESOLUTION[1]

def update(self):
self.rect.top += self.speed
if self.rect.top >= 0:
self.reset()
self.distance += 10

def draw(self,map):
self.map = map
self.map.blit(self.image,(0,0))


Main.py

import pygame, time, random
from pygame.locals import *
from Constant import *
from Ship import *
from Enemy import *
from Bullet import *
from PowerUp import *
from Ebullet import *
from Level import *
from Boss import *
from Bbullet import *

class Game:
def __init__(self):
pygame.display.set_caption(CAPTION)
self.screen = pygame.display.set_mode(RESOLUTION)
self.song = pygame.mixer.Sound(SFX_PATH +"Intro.ogg")
self.shotfx = pygame.mixer.Sound(SFX_PATH + "shot.ogg")

self.all = pygame.sprite.RenderUpdates()
self.levels = pygame.sprite.RenderUpdates()
self.enemies = pygame.sprite.RenderClear()
self.shots = pygame.sprite.RenderClear()
self.powerups = pygame.sprite.RenderClear()
self.ebullets = pygame.sprite.RenderClear()
self.boss = pygame.sprite.RenderUpdates()
self.bbullets = pygame.sprite.RenderClear()

Ship.containers = self.all
Enemy.containers = self.all, self.enemies
Bullet.containers = self.all, self.shots
PowerUp.containers = self.all, self.powerups
Ebullet.containers = self.all, self.ebullets
Level.containers = self.levels
Boss.containers = self.all
Bbullet.containers = self.all, self.bbullets

self.ship = Ship()
self.boss = Boss(1)
self.bg = pygame.Surface(RESOLUTION)
self.bg = self.bg.convert()
self.bg.fill((123,200,100))
self.lvlid = 1
self.levels.lvl = Level(self.lvlid)

self.intro = pygame.image.load(IMG_PATH + "ss.bmp")
self.intro = self.intro.convert()

self.clock = pygame.time.Clock()
self.font = pygame.font.Font("rnc.ttf", 20)
self.paused = False
self.enemycount = 0
self.score = 0
self.lives = 3
self.enemydied = 0

def pause(self):
while self.paused:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
self.paused ^= 1
if event.key == K_p:
self.paused ^= 1

def splash(self):
curtime = 0
while curtime < 5000:
curtime = pygame.time.get_ticks()
self.screen.blit(self.intro,(0,0))
pygame.display.flip()
self.menu()

def checklevel(self):
if self.lvlid == 2:
if self.levels.lvl.finished == True:
self.levels.lvl.distance = 0
self.levels.lvl = Level(self.lvlid)
self.levels.lvl.finished == False

def menu(self):
option = 1

self.song.play(-1)

while 1:
self.screen.blit(self.bg,(0,0))
self.clock.tick(45)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
return
if event.key == K_p:
self.paused ^= 1
if event.key == K_UP:
option = 1
if event.key == K_DOWN:
option = 2
if event.key == K_RETURN:
if option == 1:
for s in self.all.sprites():
pygame.sprite.Sprite.kill(s)
if not self.ship.alive():
self.ship = Ship()
self.lives = 3
self.score = 0
self.gameloop()
if option == 2:
pygame.quit()
return

self.screen.blit(self.bg,(0,0))
ren = self.font.render("Testing a Menu",1,(0,100,0))
self.screen.blit(ren,(100,200))
if option == 1:
ren = self.font.render("> New Game",1,(0,150,0))
self.screen.blit(ren,(100,250))
ren = self.font.render("Quit Game",1,(0,100,0))
self.screen.blit(ren,(100,300))
if option == 2:
ren = self.font.render("> Quit Game",1,(0,150,0))
self.screen.blit(ren,(100,300))
ren = self.font.render("New Game",1,(0,100,0))
self.screen.blit(ren,(100,250))
pygame.display.flip()

def gameloop(self):
#self.screen.blit(self.bg,(0,0))
self.levels.lvl.update()
self.paused = False
self.enemies.add(Enemy(200,random.randint(1,10)))
self.enemies.add(Enemy(400,random.randint(1,10)))
global Ebullet
global Bbullet

while 1:
self.clock.tick(45)
#self.screen.blit(self.bg,(0,0))
self.levels.update()
self.all.update()
self.pause()
self.checklevel()

for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
return
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
return
if event.key == K_p:
self.paused ^= 1
if event.key == K_z:
if self.lives > 0:
self.shots.add(Bullet(self.ship.rect.midtop,0))
if self.ship.powered == True:
self.shots.add(Bullet(self.ship.rect.midtop,1))
self.shots.add(Bullet(self.ship.rect.midtop,-1))
self.shotfx.play()

if self.levels.lvl.distance == 6000:
self.boss = Boss(self.levels.lvl.id)
elif self.levels.lvl.distance < 6000:
self.enemycount += 100
if self.enemycount > 1000:
self.enemies.add(Enemy(random.randint(1,799),random.randint(1,10)))
self.enemycount = 0

if pygame.sprite.groupcollide(self.shots,self.enemies,1,1):
self.score += 50
self.enemydied += 1
self.sp = random.randint(1,40)
if self.sp == 1:
self.powerups.add(PowerUp(random.randint(30,750)))

if pygame.sprite.spritecollide(self.ship,self.powerups,1):
self.ship.powered = True

if pygame.sprite.spritecollide(self.ship,self.ebullets,1):
self.ship.powered = False
self.lives -= 1
self.ship.rect.center = (400,500)
if self.lives <= 0:
self.ship.kill()

if pygame.sprite.spritecollide(self.ship, self.bbullets,1):
self.ship.powered = False
self.lives -= 1
self.ship.rect.center = (400,500)
if self.lives <= 0:
self.ship.kill()

if pygame.sprite.spritecollide(self.boss,self.shots,0):
self.boss.hp -= 1
#for shot in self.shots.sprites():
#pygame.sprite.Sprite.kill(shot)
if self.boss.hp <= 0:
self.levels.lvl.finished == True
self.lvlid += 1
self.boss.kill()

self.levels.update()
self.levels.draw(self.screen)
self.all.draw(self.screen)
pygame.display.flip()


def run():
pygame.init()
pygame.mixer.init()
game = Game()
game.splash()

if __name__ == "__main__":
run()
Advertisement
I don't know anything about pygame but try just printing the boss's health to the corner of the screen. Maybe it's not being decremented?
I am not at home to check it but the boss is dying whenever I damage him enough, so I am not sure why he health wouldn't be going down.

I am not at home to check it but the boss is dying whenever I damage him enough, so I am not sure why he health wouldn't be going down.


Again, I know nothing about the language... but... it LOOKS like you have no method to HANDLE loading the next level. Your level.Update doesn't check for a level change. You check when the class is defined but not if it's changed after the deceleration.
Hello

I am pretty familiar with python. From the looks of your code, it looks like a side scroller space shooter. Cool. I do not know if it was the copy and paste, but your indents are all wrong in the code. I think it was the copy and paste.

Anyway, I see where you want to change the level, I also see that you will overwrite the levels.lvl with a new levevel passing a 2. Not sure why you want to set the distance to 0 and set finished to false as overwriting the variable will set those in the constructer.

But check your indents anyway in your checklevel function. If everything under that line is not indented properly, it will think it is not in there.

That's one of the reasons why I like python, it forces you to have good habits with proper indention to prevent spagetti code.
Scratch what I said, Enders right I believe, in your checklevel function, everything after the if statement needs to be indented.
The rules for python and indention is pretty simple. Every time you have a colon ":" if you want to make a line a child to it, indent that line one more time. It is the same for everything; functions, if statements, for loops, ext...
And it doesn't have to be indent. The python intrepter can also recongnize spaces being used for code blocks.

And I think the actuall checklevel code should handle the increase in player level. So with the indents and change to player level, the checklevel code could look like this.


def checklevel(self):
if self.levels.lvl.finished == true:
self.lvlid += 1
self.levels.lvl = Level(self.lvlid)
The reason the indentions are all messed up is from whenever I copied it from komodo edit. I am been trying to get this to work and I changed some things up and I am still getting problems. I am currently having trouble with it not changing the boolean variables back after they get changed whenever the boss dies. The variable for the level id keeps getting incremented and it will not set finished back to false.
Here is the main.py
http://pastebin.com/dRa2QNWx
Here is the level.py
http://pastebin.com/6sZnYUjj
Alright I found it if you still need help.

I only see one self.levels.lvl.update() in the code. And it is outside of your main loop. You could put it in the main loop somewhere like so:


if pygame.sprite.spritecollide(self.boss,self.shots,0):
self.boss.hp -= 1
#for shot in self.shots.sprites():
#pygame.sprite.Sprite.kill(shot)
if self.boss.hp <= 0:
self.boss.isdead = True
if self.boss.isdead == True:
self.levels.lvl.finished = True
if self.levels.lvl.id == 1:
self.levels.lvl.id = 2
self.boss.kill()
self.boss.isdead = False
elif self.levels.lvl.id == 2:
self.levels.lvl.id = 3
self.boss.kill()
#self.boss.isdead = False
#self.levels.lvl.distance = 0
print self.levels.lvl.finished
print self.levels.lvl.id
print self.boss.isdead
else:
self.levels.lvl.finished = False

self.levels.lvl.update()


That way the Level's changelevel code will run. Hope this helps.
I would implement an easy statemachine. Sorry, I am not very good with python, so I will use c++, but I guess you can translate it:



class IGameState
{
public:
IGameState()
: m_reset_me(false)
{}

virtual ~IGameState(){}
virtual void initGameState() = 0;
virtual void onEnterGameState() = 0;
virtual void onLeaveGameState() = 0;
virtual IGameState* clone() = 0;
};



enum eGameState
{
STATE_NOTHING,
STATE_MENU,
STATE_CREDITS,
STATE_GAME,
STATE_HIGHSCORES,
};

class GameStateManager : public boost::noncopyable
{
typedef std::map<eGameState, IGameState*> TGameStateMap;

public:
GameStateManager();
virtual ~GameStateManager();
void assignGameState(eGameState state, IGameState* ptr);
void removeGameState(eGameState state, IGameState* ptr);
void changeGameState(eGameState state);

private:
TGameStateMap m_states;
eGameState m_current_state;
};


So, this is very straight forward. The class IGameState is an interface and the 3 functions need to be implemented by a derived class. Just make an enum for every state and a class for every state.
[font="Monaco,"]
[/font]
[font="Monaco,"]initGameState : i[/font][font="Monaco,"]s called when the state is to be loaded. That is the moment when it is added to the GameStateManager, but you can change that ofc. [/font]
[font="Monaco,"]onEnterGameState : is called when the GameState has changed from A to B and the new state has its first run. [/font]
[font="Monaco,"]onLeaveGameState : is called when the state is left. So you can cleanup shit and reset vars etc, just how your Game needs it. [/font]
[font="Monaco,"] [/font]
[font="Monaco,"]This way you can control very nicely the order of whats happening when in your game. [/font]
[font="Monaco,"]I hope this helps and excuse the c++, if you got questions and don't understand it, feel free to ask :).[/font]
If you say "pls", because it is shorter than "please", I will say "no", because it is shorter than "yes"
http://nightlight2d.de/

This topic is closed to new replies.

Advertisement