2

I want to make my game "go back" to the main menu and I was wondering If I can use the gamewindow function "inside" its own so that it would create a "reset". Basically, If my sprite were to collide and it says "game over" I would like to press the "back" button and If I were to press play again it would show a "reseted" game where the "timer", the "asteroid", the "ship", goes back to the beginning as If I were playing a new game again.

I was also wondering if any of the errors given to me mean anything to my problem now??

The code/game is mostly working. It just doesn't have that "reset" purpose.

Here's the errors:

"C:\Users\user\AppData\Local\Programs\Python\Python38-32\python.exe" "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py"
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:261: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if bullet_state is "fire":
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:322: SyntaxWarning: "is" with a literal. Did you mean "=="?
  if bullet_state is "ready":
pygame 1.9.6
Hello from the pygame community. https://www.pygame.org/contribute.html
B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py:171: DeprecationWarning: an integer is required (got type float).  Implicit conversion to integers using __int__ is deprecated, and may be removed in a future version of Python.
  display.blit(ammoboximg,(x,y))
Traceback (most recent call last):
  File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 374, in <module>
    gamewindow()
  File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
    gamewindow()
  File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
    gamewindow()
  File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 315, in gamewindow
    gamewindow()
  File "B:/PROGRAMMING RELATED/PYTHON PROJECTS/FINAL.py", line 330, in gamewindow
    keys = pygame.key.get_pressed()
pygame.error: video system not initialized

Process finished with exit code 1

Here's the whole code:

# initialization of pygame
import pygame
import random
import math


pygame.init()
# creating the display
display = pygame.display.set_mode((500, 500))

# title & icon
spaceship = pygame.image.load("Space Blitz Sprites/spaceship.png")
pygame.display.set_icon(spaceship)
pygame.display.set_caption("SpaceBlitz")

# main menu sprites
spaceblitz = pygame.image.load("Space Blitz Sprites/spaceblitz.png")
play = pygame.image.load("Space Blitz Sprites/play.png")
howtoplay = pygame.image.load("Space Blitz Sprites/howtoplay.png")
about = pygame.image.load("Space Blitz Sprites/about.png")
quit = pygame.image.load("Space Blitz Sprites/quit.png")

# inside main menu
instruction = pygame.image.load("Space Blitz Sprites/instruction.png")
back = pygame.image.load("Space Blitz Sprites/back.png")
aboutdev = pygame.image.load("Space Blitz Sprites/aboutdev.png")

# main menu music
music = pygame.mixer.music.load("Space Blitz Sprites/mountaintrails.mp3")

# PlayerSpriteMovement
playerimg = pygame.image.load("Space Blitz Sprites/spaceship.png")
playerX = 250
playerY = 400
velocity = 3
clock = pygame.time.Clock()

# Bullet
bulletimg = pygame.image.load("Space Blitz Sprites/bullet.png")
bulletX = 0
bulletY = playerY
bulletx_change = 0
bulletY_change = 8
bullet_state = "ready"
bullet_ammo = 5
bulletfont = pygame.font.Font('freesansbold.ttf', 16)
# Ammo Box
ammoboximg = pygame.image.load('Space Blitz Sprites/ammo.png')
ammoboxX = random.randint(0,468)
ammoboxY = random.randint(-1000,-800)
ammoboxY_change = -1.5

# Asteroid
asteroidimg = []
asteroidX = []
asteroidY = []
asteroidX_change = []
asteroidY_change = []
no_of_enemies = 40

def mainmenu():
    global menuselect
    global spaceblitz
    menu = True
    pygame.mixer.music.play(50)
    pygame.mixer.music.set_volume(0.2)
    while menu:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    pos = pygame.mouse.get_pos()
                    if start.collidepoint(pos):
                        menu = False
                        menuselect = 1
                        pygame.mixer.music.stop()
                    if controls.collidepoint(pos):
                        menu = False
                        menuselect = 2
                        pygame.mixer.music.stop()
                    if developer.collidepoint(pos):
                        menu = False
                        menuselect = 3
                        pygame.mixer.music.stop()
                    if exit.collidepoint(pos):
                        menu = False
                        menuselect = 4

        display.fill((0, 0, 0))
        display.blit(spaceblitz, (170,150))
        start = display.blit(play, (170,250))
        controls = display.blit(howtoplay, (170,300))
        developer = display.blit(about, (170,350))
        exit = display.blit(quit, (170,400))
        pygame.display.flip()
        pygame.display.update()

def controls():
    global menuselect
    global menu
    controls = True
    while controls:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    pos = pygame.mouse.get_pos()
                    if balik.collidepoint(pos):
                        controls = False
                        menu = True
                        menuselect = 0
        balik = display.blit(back, (0,450))
        display.blit(instruction, (0,0))
        pygame.display.flip()
        pygame.display.update()
        display.fill((0, 0, 0))

def developers():
    global menuselect
    global menu
    dev = True
    while dev:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    pos = pygame.mouse.get_pos()
                    if balik.collidepoint(pos):
                        dev = False
                        menu = True
                        menuselect = 0
        balik = display.blit(back, (0, 450))
        display.blit(aboutdev, (0, 0))
        pygame.display.flip()
        pygame.display.update()
        display.fill((0, 0, 0))

# Asteroid
for r in range(no_of_enemies):
    asteroidimg.append(pygame.image.load("Space Blitz Sprites/asteroid.png"))
    asteroidX.append(random.randint(-100, 500))
    asteroidY.append(random.randint(-300, -30))
    asteroidX_change.append(0)
    asteroidY_change.append(2)




# Game Over Text
overfont = pygame.font.Font('freesansbold.ttf',32)


# Sprite image
def player(x, y):
    display.blit(playerimg, (x, y))

def fire_bullet(x, y):
    global bullet_state
    if bullet_ammo > -1:
        bullet_state = "fire"
        display.blit(bulletimg, (x + 9, y + -7))
    else:
        bullet_state = "ready"

def ammobox(x,y):
    display.blit(ammoboximg,(x,y))

def AmBoxCollision(ammoboxX,ammoboxY,playerX,playerY):
    ammoboxdistance = math.sqrt((math.pow(ammoboxX - playerX, 2)) + (math.pow(ammoboxY - playerY, 2)))
    if ammoboxdistance < 27:
        return True
    else:
        return False

def ammo():
    global bullet_ammo
    global ammo_decrease
    ammo_decrease = 1
    bullet_ammo -= ammo_decrease



def asteroid(x, y, r):
    display.blit(asteroidimg[r], (x, y))




def BulCollision(asteroidX, asteroidY, bulletX, bulletY):
    buldistance = math.sqrt((math.pow(bulletX - asteroidX, 2)) + (math.pow(bulletY - asteroidY, 2)))
    if buldistance < 27:
        return True
    else:
        return False
def PlayCollision(asteroidX, asteroidY, playerX, playerY):
    playdistance = math.sqrt((math.pow(playerX - asteroidX, 2)) + (math.pow(playerY - asteroidY, 2)))
    if playdistance < 27:
        return True
    else:
        return False
def gameover_screen():
    overtext = overfont.render("GAME OVER",True,(255,255,255))
    display.blit(overtext, (150,250))

# mainloop
def gamewindow():
    global menuselect
    global playerX
    global playerY
    global velocity
    global clock
    global bulletX
    global bulletY
    global bulletY_change
    global bullet_state
    global asteroidX
    global asteroidY
    global asteroidY_change
    global no_of_enemies
    global ammoboxX
    global ammoboxY
    global ammoboxY_change
    global dev
    global menu
    global bullet_ammo
    global ammo_decrease
    global passed_time
    font = pygame.font.Font(None, 54)
    font_color = pygame.Color('white')
    start_time = pygame.time.get_ticks()
    run_timer = True
    running = True

    while running:
        clock.tick(60)
        display.fill((0, 0, 0))
        AmmoBoxCollision = AmBoxCollision(ammoboxX,ammoboxY,playerX,playerY)
        if AmmoBoxCollision:
            ammoboxY = random.randint(-1000, -800)
            ammoboxX = random.randint(0, 468)
            if bullet_ammo <= 4 and bullet_ammo > -1:
                bullet_ammo += 1
            if bullet_ammo == -1:
                bullet_ammo +=2


        if bullet_ammo == -1 or bullet_ammo == 0:
            bullet_text = bulletfont.render("Ammo:%d" % bullet_ammo, True, (0, 0, 0))
            display.blit(bullet_text, (10, 468))
            noammo = bulletfont.render("NO AMMO",True,(255,255,255))
            display.blit(noammo,(10,468))
        else:
            bullet_text = bulletfont.render("Ammo:%d" % bullet_ammo, True, (255, 255, 255))
            display.blit(bullet_text, (10, 468))

        if bullet_state is "fire":
            fire_bullet(bulletX, bulletY)
            bulletY -= bulletY_change

        if bulletY <= 0:
            bulletY = playerY
            bullet_state = "ready"

        for r in range(no_of_enemies):
            asteroid(asteroidX[r], asteroidY[r], r)
            asteroidY[r] += asteroidY_change[r]
            if asteroidY[r] >= 500:
                asteroidY[r] = random.randint(-300, -30)
                asteroidX[r] = random.randint(-100, 500)

            Bulletcollision = BulCollision(asteroidX[r], asteroidY[r], bulletX, bulletY)
            if Bulletcollision:
                bulletY = playerY
                bullet_state = "ready"
                asteroidX[r] = random.randint(-100, 500)
                asteroidY[r] = random.randint(-300, -30)

            # Game over
            PlayerCollision = PlayCollision(asteroidX[r], asteroidY[r], playerX, playerY)

            if PlayerCollision:
                for j in range(no_of_enemies):
                    asteroidY_change[j] = 0
                    asteroidY[j] = random.randint(-300, -30)
                    asteroidX[j] = random.randint(-100, 500)
                    asteroidY_change[j] = 2

                velocity = 0
                bulletY_change = 0
                bulletY = 600
                ammoboxY_change = 0
                run_timer = False
                gameover_screen()
                playerX = 250
                playerY = 400
                velocity = 3


        # movement
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()

            if event.type == pygame.MOUSEBUTTONDOWN:
                if event.button == 1:
                    pos = pygame.mouse.get_pos()
                    if balik.collidepoint(pos):
                        running = False
                        menu = True
                        menuselect = 0


            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:
                    if bullet_ammo <= 5 and bullet_ammo > -1:
                        if bullet_state is "ready":
                            bulletX = playerX
                            bulletY = playerY
                            fire_bullet(bulletX, bulletY)
                            ammo()


        # player movement
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            playerX -= velocity

        if keys[pygame.K_RIGHT]:
            playerX += velocity

        if keys[pygame.K_DOWN]:
            playerY += velocity

        if keys[pygame.K_UP]:
            playerY -= velocity

        # Border
        if playerX <= 0:
            playerX = 0
        elif playerX >= 468:
            playerX = 468
        if playerY <= 0:
            playerY = 0
        elif playerY >= 468:
            playerY = 468

        if ammoboxY > 500:
            ammoboxY = random.randint(-1000,-800)
            ammoboxX = random.randint(0,468)
        ammobox(ammoboxX,ammoboxY)
        ammoboxY -= ammoboxY_change

        if run_timer:
            current_time = pygame.time.get_ticks()
            passed_time = current_time - start_time

        text = font.render(str(passed_time / 1000), True, font_color)
        display.blit(text, (50, 50))
        balik = display.blit(back, (350, 450))
        player(playerX, playerY)
        pygame.display.update()

mainmenu()
while True:
        if menuselect == 0:
            mainmenu()
        elif menuselect == 1:
            gamewindow()
        elif menuselect == 2:
            controls()
        elif menuselect == 3:
            developers()
        elif menuselect == 4:
            pygame.quit()

Here's where I would like to put my reset button (in either the PlayerCollision or balik.collidepoint(pos))

        if PlayerCollision:
            for j in range(no_of_enemies):
                asteroidY_change[j] = 0
                asteroidY[j] = random.randint(-300, -30)
                asteroidX[j] = random.randint(-100, 500)
                asteroidY_change[j] = 2

            velocity = 0
            bulletY_change = 0
            bulletY = 600
            ammoboxY_change = 0
            run_timer = False
            gameover_screen()
            playerX = 250
            playerY = 400
            velocity = 3


    # movement
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()

        if event.type == pygame.MOUSEBUTTONDOWN:
            if event.button == 1:
                pos = pygame.mouse.get_pos()
                if balik.collidepoint(pos):
                    running = False
                    menu = True
                    menuselect = 0


        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                if bullet_ammo <= 5 and bullet_ammo > -1:
                    if bullet_state is "ready":
                        bulletX = playerX
                        bulletY = playerY
                        fire_bullet(bulletX, bulletY)
                        ammo()

I'm sorry if I'm asking a lot of question. This is my first ever code in python (or programming in general) so I don't really know how most of the stuff works. Plus, the code is a mixture of my code and my group-mate's code so half of the code in this program is unfamiliar to me. Tips for future coding practice is highly appreciated but I just want to finish my game right now so I would like to finish the current (and last) problem that I encountered.

Moyk
  • 47
  • 4

1 Answers1

2

As you say, you've just started and are learning. Very good! You've just run into a problem that you can learn a lot from: adding new features. Generally, this question would be better suited on the code review stack exchange but I think it's also suited here.

So what's the problem exactly? You say you want to have your game "go back" to the main menu. You suggest an implementation that (I find) difficult to follow and follow up with a bunch of code that I'm sure that works but is difficult (for me) to read. I honestly find it very impressive how much you've been able to write, especially since it's your first time coding!


In my opinion, your real problem isn't how to "go back", rather, it is how to make your code fixeable/updateable. A very good lesson to learn. There's a couple reasons why your current code is difficult to update:

  • All your code is in one file, making it hard to navigate
  • You have global variables, which can be hard to track
  • You use many hard coded values which are hard to change/keep track of

Why is this a problem? If you want to change something you cannot find where to change what because you cannot find anything because there's so much code everywhere. Then, once you find it, you cannot really know what everything is because of the global variables. Lastly, the hard coded values make it impossible to know if you've fixed everything, or forgot a number causing a bug (for instance, you want to make the screen twice as big, change all the picture sizes, but forget to update the speed).


So how do you change this?

Well, first try splitting up your code so it's easier to find things. I like to put things in folders like this:

my_project/
    main.py
    .gitignore
    core/
        game_mechanics/
            player.py
            bullet.py
            asteroid.py
        game_setup/
            main_menu.py
            run_game.py
    config/
        config.yaml
    utils/
        read_config.py
    tests/
        test1.py
        test2.py

This may seem daunting, so let's run past what everything is:

Main.py: your main file which you run. It looks something like this:

from example_file import example_function

def main(config):
    while True:
        settings = main_menu()
        play_game(settings)

if __name__ == '__main__':
    config = load_config()
    main(config)

When you run main.py it will load the config, and then run the main components. This file should be very short so it's easy to understand what is happening. Here for instance, you get the settings from running main_menu() and then play the game using those settings. When the game quits, the main menu is shown again.

Next is the .gitignore file that you'll need if you use git. If you don't know what this is/does you should google it, it will make your life much easier.

In your core folder you have all the main functions specific to the game. This is where you put most of your code. It is important to split it up into logical files so you can easily find what goes where.

In your utils folder you have utility functions you'll want to share between projects.

In your config folder you can store the settings. This should contain all the "number or letter values" you use, this way you don't have to go through your code manually changing number everywhere (and maybe forgetting one), but instead pass it along.

This solves your problem of having to find where what is. Everything is ordered nicely and you can easily find it. If you want to change large functionalities (like adding a new menu) you can do this in the main file which is easy to do.


The next problem is the use of global variables. You have quite a number of them and this makes it hard to track which value is what. It may be clear to you know, but imagine when you come back in a year and values change 'randomly', how do you find where what changes?

Instead, try to pass things to your functions like this:

def square_n(n):
    return n * n 

a = 5
a_squared = square_n(a)

This makes it much easier to read what happens where.


Lastly, as mentioned before the hard coded values make everything very difficult to update. Take the example with doubling the screen size. You make everything twice as large, but forget to double one speed component (because you overlooked it). This could be a "weird bug" that takes some time to fix. Instead try to save all these values in your config, and pass them along as shown above. This would look something like this:

def print_hello_world_n_times(n):
    for i in range(n):
        print("hello world")

config = load_config()
# config = {'a': 5, 'b': 10}
a = config['a']
print_hello_world_n_times(a)

I'm sorry I won't be giving you a copy-paste solution to your problem. I think it's much more useful for you to restructure your code yourself and then see how much easier it is to change its functionality.

Success!

Nathan
  • 3,558
  • 1
  • 18
  • 38
  • My groupmate and I found a way to "reset" the game without doing this because of time constraint but I'll be sure to do this in the future or do this in our current project to make it more organized. With that said, can you please elaborate more about your statement "All your code is in one file, making it hard to navigate" as I didn't know that you can separate codes to make it more organized. Can you please tell me what to search so I can learn more about this method? – Moyk Feb 11 '20 at 11:39
  • 1
    @Moyk glad you were able to make it work, well done! You should look up how to importing other files https://docs.python.org/3/tutorial/modules.html – Nathan Feb 11 '20 at 11:44