Pygame 3

Opgave 19

In opgave 17 introduceerden we kogels. De kogel vertrekt echter niet van het midden van het ruimteschip. Pas de code aan, zodat de kogel vanuit het midden van het ruimteschip vertrekt.

Opgave 20

In onderstaande code introduceren we een vijand.

_images/enemyship.png

Net zoals voor de kogels en de speler, houden we ook voor het vijandelijke schip de positie en de verplaatsing bij in variabelen:

  • enemy_x: positie op de X-as (horizontaal)

  • enemy_y: positie op de Y-as (vertikaal)

  • enemy_x_change: verplaatsing op de X-as

  • enemy_y_change: verplaatsing op de Y-as

import pygame

WIDTH = 800
HEIGHT = 600

pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))


sound = pygame.mixer.Sound("bow.wav")
player = pygame.image.load("ship.png")
bullet = pygame.image.load("bullet.png")
enemy = pygame.image.load("enemyship.png")

# Positie van de speler, en verplaatsing van de speler
x = WIDTH / 2
y = HEIGHT - 110
xchange = 0
ychange = 0

# Positie van de kogel, en verplaatsing van de kogel
bullet_x = 0
bullet_y = 0
bullet_x_change = 0
bullet_y_change = 0

# Positie van de vijand, en verplaatsing van de vijand
enemy_x = WIDTH - 200
enemy_y = 0
enemy_x_change = 0
enemy_y_change = 0.05


running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                sound.play()
                bullet_x = x - 50
                bullet_y = y
                bullet_x_change = -0.5
            elif event.key == pygame.K_LEFT:
                xchange = -0.1
            elif event.key == pygame.K_RIGHT:
                xchange = 0.1
            elif event.key == pygame.K_UP:
                ychange = -0.1
            elif event.key == pygame.K_DOWN:
                ychange = 0.1
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                xchange = 0
            elif event.key == pygame.K_RIGHT:
                xchange = 0
            if event.key == pygame.K_UP:
                ychange = 0
            elif event.key == pygame.K_DOWN:
                ychange = 0
    # Verplaats de speler
    x += xchange
    y += ychange

    # Verplaats de kogel
    bullet_x += bullet_x_change
    bullet_y += bullet_y_change

    # Verplaats de vijand
    enemy_x += enemy_x_change
    enemy_y += enemy_y_change

    # Als de vijand buiten het scherm gaat,
    # plaats hem dan terug bovenaan het scherm
    # if enemy_y ...
    #    enemy_y = ...

    # Teken de speler, de vijand en  de kogel
    screen.fill("white")
    screen.blit(player, (x, y))
    screen.blit(enemy, (enemy_x, enemy_y))
    screen.blit(bullet, (bullet_x, bullet_y))

    pygame.display.flip()

Link naar opgave20.py

Als het vijandelijke ruimteschip onderaan het scherm geraakt, blijft het ruimteschip zich verder naar onder verplaatsen. Erg veel nut heeft dit niet, aangezien het ruimteschip niet meer zichtbaar is voor de speler.

Pas de code aan zodat het ruimteschip zich terug bovenaan het scherm bevindt zodra de Y positie van het schip zich buiten het scherm bevindt. Dus, zodra Y groter is dan de schermhoogte.

_images/ship.png

Opgave 21

De aanpassing in opgave 20 zorgde ervoor dat het ruimteschip terug bovenaan het scherm verscheen. Hierdoor lijkt het alsof er een nieuwe vijand aankomt. Helaas komt de vieuwe vijand op exact dezelfde positie als de vorige vijand. Pas de code aan zodat de vijand telkens op een nieuwe willekeurige horizontale positie verschijnt met behulp van de random.randint functie.

Opgave 22

Ons ruimteschip kan nu schieten, er verschijnen ook vijanden, maar we kunnen de vijand helaas nog niet raken.

import pygame
from pygame import Rect

WIDTH = 800
HEIGHT = 600

pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))


sound = pygame.mixer.Sound("bow.wav")
explosion = pygame.mixer.Sound("explosion.wav")
player = pygame.image.load("ship.png")
bullet = pygame.image.load("bullet.png")
enemy = pygame.image.load("enemyship.png")

# Positie van de speler, en verplaatsing van de speler
x = WIDTH / 2
y = HEIGHT - 110
xchange = 0
ychange = 0

# Positie van de kogel, en verplaatsing van de kogel
bullet_x = 0
bullet_y = 0
bullet_x_change = 0
bullet_y_change = 0

# Positie van de vijand, en verplaatsing van de vijand
enemy_x = WIDTH - 200
enemy_y = 0
enemy_x_change = 0
enemy_y_change = 0.05

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                sound.play()
                bullet_x = x
                bullet_y = y
                bullet_y_change = -0.5
            elif event.key == pygame.K_LEFT:
                xchange = -0.1
            elif event.key == pygame.K_RIGHT:
                xchange = 0.1
            elif event.key == pygame.K_UP:
                ychange = -0.1
            elif event.key == pygame.K_DOWN:
                ychange = 0.1
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                xchange = 0
            elif event.key == pygame.K_RIGHT:
                xchange = 0
            if event.key == pygame.K_UP:
                ychange = 0
            elif event.key == pygame.K_DOWN:
                ychange = 0

    # Verplaats de speler
    x += xchange
    y += ychange

    # Verplaats de kogel
    bullet_x += bullet_x_change
    bullet_y += bullet_y_change

    # Verplaats de vijand
    enemy_x += enemy_x_change
    enemy_y += enemy_y_change

    # Als de vijand buiten het scherm gaat,
    # plaats hem dan terug bovenaan het scherm
    if enemy_y > HEIGHT:
        enemy_y = 0

    # Kijk of er een botsing is
    enemy_rect = Rect(enemy_x, enemy_y, 32, 32)
    bullet_rect = Rect(bullet_x, bullet_y, 8, 8)
    if enemy_rect.colliderect(bullet_rect):
        print("hit", enemy_rect, bullet_rect)

    # Teken de speler, de vijand en  de kogel
    screen.fill("white")
    screen.blit(player, (x, y))
    screen.blit(enemy, (enemy_x, enemy_y))
    screen.blit(bullet, (bullet_x, bullet_y))

    pygame.display.flip()

Link naar opgave22.py

In bovenstaand voorbeeld wordt code toegevoegd die telkens test of er een botsing plaatsvindt tussen de kogel en de vijand. Indien de kogel de vijand raakt, wordt “hit” op het scherm getoond.

Hier zien we het stukje code dat deze test uitvoert:


    # Kijk of er een botsing is
    enemy_rect = Rect(enemy_x, enemy_y, 32, 32)
    bullet_rect = Rect(bullet_x, bullet_y, 8, 8)
    if enemy_rect.colliderect(bullet_rect):
        print("hit", enemy_rect, bullet_rect)

Pas de code aan zodat er een explosie afgespeeld wordt, als de vijand geraakt werd.

Opgave 23

Je merkte vast dat de detectie van botsingen tussen kogels en vijanden niet erg nauwkeurig was. Soms raak je de vijand, maar verschijnt er toch geen “hit”. Dit komt door het incorrect instellen van de rechthoek waarmee de botsing gedetecteerd werd.

Pas de code uit opgave 22 aan zodat dit probleem verholpen wordt.

Opgave 24

Hoewel ons spel nog zeer eenvoudig is, gebruikt het enorm veel CPU-tijd. Dit komt omdat we onze while-lus voortdurend uitvoeren, zonder enige onderbreking. Dus, in plaats van het blitten van de sprites (tekeningen) aan een bepaalde framerate (b.v. 60FPS) doen we dit momenteel zo veel mogelijk.

We passen de code nu aan zodat er na elke hertekening van het scherm gewacht wordt. De belasting van de CPU is nu aanzienlijk lager.

import random
import pygame
from pygame import Rect

WIDTH = 800
HEIGHT = 600

pygame.init()
pygame.mixer.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))

# Start de klok
clock = pygame.time.Clock()


sound = pygame.mixer.Sound("bow.wav")
explosion = pygame.mixer.Sound("explosion.wav")
player = pygame.image.load("ship.png")
bullet = pygame.image.load("bullet.png")
enemy = pygame.image.load("enemyship.png")


# Positie van de speler, en verplaatsing van de speler
x = WIDTH / 2
y = HEIGHT - 110
xchange = 0
ychange = 0

# Positie van de kogel, en verplaatsing van de kogel
bullet_x = 0
bullet_y = 0
bullet_x_change = 0
bullet_y_change = 0

# Positie van de vijand, en verplaatsing van de vijand
enemy_x = WIDTH - 200
enemy_y = 0
enemy_x_change = 0
enemy_y_change = 0.05

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_SPACE:
                sound.play()
                bullet_x = x
                bullet_y = y
                bullet_y_change = -0.5
            elif event.key == pygame.K_LEFT:
                xchange = -0.1
            elif event.key == pygame.K_RIGHT:
                xchange = 0.1
            elif event.key == pygame.K_UP:
                ychange = -0.1
            elif event.key == pygame.K_DOWN:
                ychange = 0.1
        elif event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                xchange = 0
            elif event.key == pygame.K_RIGHT:
                xchange = 0
            if event.key == pygame.K_UP:
                ychange = 0
            elif event.key == pygame.K_DOWN:
                ychange = 0

    # Verplaats de speler
    x += xchange
    y += ychange

    # Verplaats de kogel
    bullet_y += bullet_y_change

    # Verplaats de vijand
    enemy_x += enemy_x_change
    enemy_y += enemy_y_change

    # Als de vijand buiten het scherm gaat,
    # plaats hem dan terug bovenaan het scherm
    if enemy_y > HEIGHT:
        enemy_y = 0
        enemy_x = random.randint(0, WIDTH)

    # Kijk of er een botsing is
    enemy_rect = Rect(enemy_x, enemy_y, 32, 32)
    bullet_rect = Rect(bullet_x, bullet_y, 8, 8)
    if enemy_rect.colliderect(bullet_rect):
        explosion.play()
        print("hit")

    # Teken de speler, de vijand en  de kogel
    screen.fill("white")
    screen.blit(player, (x, y))
    screen.blit(enemy, (enemy_x, enemy_y))
    screen.blit(bullet, (bullet_x, bullet_y))

    pygame.display.flip()

    # Wacht zodanig dat we maximal 60 FPS halen
    clock.tick(60)

Link naar opgave24.py

Probleem is nu dat alle bewegingen veel trager verlopen. Dit komt doordat voor de aanpassing de code b.v. 1000 maal per seconde uitgevoerd werd, en nu maximaal 60 keer per seconde.

Bijvoorbeeld, voor de vijand werd onderstaande code uitgevoerd:

enemy_y_change = 0.05
enemy_y += enemy_y_change

Hierdoor zou de vijand zich 1000x0.05 pixels per seconde verplaatsen, dus 50 pixels per seconde. Met de aangepaste code verplaatst de vijand zich nu slechts 60x0.05 pixels per second, dus 3 pixels per seconde.

Pas de code aan zodat zowel je eigen ruimteschip als de kogels als het vijandelijke ruimteschip vlotter bewegen.