今日のエッセイ
おなじみの気まぐれゲームプログラミングです。
プログラム言語はPythonのPygameです。
タイトル:「THE SHOOTER」
シューティングパズルゲームです。
上から落ちてくる緑の四角い物体を、水色の四角いのを左右のカーソルキーで操作してスペースキーで撃つと得点です。
緑の四角に水色の四角が接触するか、一番下を通り過ぎるとHPが減ります。
HPが0以下になるとゲームオーバーで、ゲームが止まり、4秒後にウインドウが閉じます。
HPは数値と黄色いバーで表示します。
バーはHPが減るとオレンジに変わっていきます。
10000点でHPが20回復、緑の四角を撃墜するごとに1回復します。
○プログラム
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((60, 60)) #size of image
self.image.fill((0,230,230))
self.rect = self.image.get_rect()
self.rect.centerx = SCREEN_WIDTH // 2
self.rect.bottom = SCREEN_HEIGHT - 10
self.speed_x = 0
def update(self):
self.speed_x = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.speed_x = -5
if keys[pygame.K_RIGHT]:
self.speed_x = 5
self.rect.x += self.speed_x
if self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
if self.rect.left < 0:
self.rect.left = 0
プレイヤー(水色の四角)のクラスです。
位置や動き、スピードを設定します。
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((80, 80))
self.image.fill((0,220,50))
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width)
self.rect.y = random.randint(-100, -50)
self.speed_y = random.randint(3, 6) #enemy speed #random.randint(a,b) range [a,b]
def update(self):
global hitnumber #calling of global value in class
self.rect.y += self.speed_y
if self.rect.top > SCREEN_HEIGHT: #out of enemy for screen height
self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width)
self.rect.y = random.randint(-100, -50)
self.speed_y = random.randint(3, 6) #enemy speed
hitnumber -= 2
if hitnumber < -1:
gameover = fontgo.render("GameOver.Try for the Next.", True, (250,150,0))
screen.blit(gameover, (180, 290))
pygame.display.flip() # Update the display
pygame.time.wait(4000) # Wait for 4 seconds before exiting
pygame.quit()
sys.exit()#Game Exit
敵キャラクターの動きを設定するクラスです。
テキスト表示の時は、pygame.display.flip()関数がないと表示されません。
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((5, 10))
self.image.fill((250,220,0))
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
self.speed_y = -10
def update(self):
self.rect.y += self.speed_y
if self.rect.bottom < 0:
self.kill()
プレイヤーのショットの動きを設定します。
self.rect.bottom = yは画面の上端です。
上端をすぎたらself.kill()関数でショットを消去します。
class HPBar(pygame.sprite.Sprite):
def __init__(self, max_health, width, height, color, outline_color):
super().__init__()
self.max_health = max_health
self.current_health = max_health
self.width = width
self.height = height
self.color = color
self.outline_color = outline_color
# Create a surface for the HP bar
self.image = pygame.Surface((width, height))
self.rect = self.image.get_rect()
self.update() # Initial update to set HP bar to full health
def update(self):
# Calculate fill ratio
fill_ratio = self.current_health / self.max_health
fill_width = int(self.width * fill_ratio)
# Fill the HP bar
self.image.fill(self.outline_color)
pygame.draw.rect(self.image, self.color, pygame.Rect(0, 0, fill_width, self.height))
def set_health(self, health):
# Set current health and update the HP bar
self.current_health = health
self.update()
def decrease_health(self, amount):
# Decrease current health by the given amount
self.current_health = amount
#self.current_health -= amount
if self.current_health < 0:
self.current_health = 0
self.update()
def increase_health(self, amount):
# Increase current health by the given amount
self.current_health += amount
#self.current_health += amount
if self.current_health > self.max_health:
self.current_health = self.max_health
self.update()
HPの減少を設定するクラスです。
def decrease_health(self, amount)でバーが減少します。
self.current_health = amountだとHPの数値を受け取ります。
self.current_health = -amountだと減少し続けます。
def increase_health(self, amount)は、増やす時に使います。
今回は、使用しません。
hpbar = HPBar(max_health=hitnumber, width=250, height=25,
color=(255,210,0), outline_color=(255,150,0))
クラスで設定したHPバーを表示します。
color=(r,g,b)でバーの色をRGBカラー(0〜255)で設定します。
outline_color=(255,150,0)で減少した後の色を設定します。
running = True
while running:
clock.tick(60)
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:
bullet = Bullet(player.rect.centerx, player.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
スペースキーを押した時のショットの設定です。
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits:
score += 100 # Increment score when enemy is destroyed
hitnumber += 1
if score == 10000:
hitnumber += 20
enemy = Enemy()
all_sprites.add(enemy)
enemies.add(enemy)
ショットが敵(水色の四角)に当たった時の処理です。
hits = pygame.sprite.spritecollide(player, enemies, False)
if hits: #Player hits enemy.
hitnumber -= 1
if hitnumber < 0:
gameover = fontgo.render("GameOver.Try for the Next.", True, (250,150,0))
screen.blit(gameover, (180, 290))
pygame.display.flip() # Update the display
pygame.time.wait(4000) # Wait for 4 seconds before exiting
pygame.quit()
sys.exit() #Game Exit
プレイヤーと敵の衝突判定です。
hitnumberがHPの数値となります。
0を下回るとゲームオーバーの表示をします。
pygame.quit()とsys.exit()でゲームが止まり、ウインドウを閉じますが、プログラムは稼働しているので、ctr+cやエディタの停止でプログラムを止めます。
○全体のプログラム
import pygame
import sys
import random
pygame.init()
# Screen
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
hitnumber = 50
# Set up the screen
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
pygame.display.set_caption("THE SHOOTER")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((60, 60)) #size of image
self.image.fill((0,230,230))
self.rect = self.image.get_rect()
self.rect.centerx = SCREEN_WIDTH // 2
self.rect.bottom = SCREEN_HEIGHT - 10
self.speed_x = 0
def update(self):
self.speed_x = 0
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.speed_x = -5
if keys[pygame.K_RIGHT]:
self.speed_x = 5
self.rect.x += self.speed_x
if self.rect.right > SCREEN_WIDTH:
self.rect.right = SCREEN_WIDTH
if self.rect.left < 0:
self.rect.left = 0
class Enemy(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((80, 80))
self.image.fill((0,220,50))
self.rect = self.image.get_rect()
self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width)
self.rect.y = random.randint(-100, -50)
self.speed_y = random.randint(3, 6) #enemy speed #random.randint(a,b) range [a,b]
def update(self):
global hitnumber #calling of global value in class
self.rect.y += self.speed_y
if self.rect.top > SCREEN_HEIGHT: #out of enemy for screen height
self.rect.x = random.randint(0, SCREEN_WIDTH - self.rect.width)
self.rect.y = random.randint(-100, -50)
self.speed_y = random.randint(3, 6) #enemy speed
hitnumber -= 2
if hitnumber < -1:
gameover = fontgo.render("GameOver.Try for the Next.", True, (250,150,0))
screen.blit(gameover, (180, 290))
pygame.display.flip() # Update the display
pygame.time.wait(4000) # Wait for 4 seconds before exiting
pygame.quit()
sys.exit()#Game Exit
class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y):
super().__init__()
self.image = pygame.Surface((5, 10))
self.image.fill((250,220,0))
self.rect = self.image.get_rect()
self.rect.centerx = x
self.rect.bottom = y
self.speed_y = -10
def update(self):
self.rect.y += self.speed_y
if self.rect.bottom < 0:
self.kill()
class HPBar(pygame.sprite.Sprite):
def __init__(self, max_health, width, height, color, outline_color):
super().__init__()
self.max_health = max_health
self.current_health = max_health
self.width = width
self.height = height
self.color = color
self.outline_color = outline_color
# Create a surface for the HP bar
self.image = pygame.Surface((width, height))
self.rect = self.image.get_rect()
self.update() # Initial update to set HP bar to full health
def update(self):
# Calculate fill ratio
fill_ratio = self.current_health / self.max_health
fill_width = int(self.width * fill_ratio)
# Fill the HP bar
self.image.fill(self.outline_color)
pygame.draw.rect(self.image, self.color, pygame.Rect(0, 0, fill_width, self.height))
def set_health(self, health):
# Set current health and update the HP bar
self.current_health = health
self.update()
def decrease_health(self, amount):
# Decrease current health by the given amount
self.current_health = amount
#self.current_health -= amount
if self.current_health < 0:
self.current_health = 0
self.update()
def increase_health(self, amount):
# Increase current health by the given amount
self.current_health += amount
#self.current_health += amount
if self.current_health > self.max_health:
self.current_health = self.max_health
self.update()
score = 0 # Initialize score variable
font = pygame.font.Font(None, 40) # Font for displaying score
fonthp = pygame.font.Font(None, 40)
fontgo = pygame.font.Font(None, 50) # displaying Gameover
# Create an HP bar instance
hpbar = HPBar(max_health=hitnumber, width=250, height=25,
color=(255,210,0), outline_color=(255,150,0))
all_sprites = pygame.sprite.Group()
bullets = pygame.sprite.Group()
enemies = pygame.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(8):
enemy = Enemy()
all_sprites.add(enemy)
enemies.add(enemy)
clock = pygame.time.Clock()
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet = Bullet(player.rect.centerx, player.rect.top)
all_sprites.add(bullet)
bullets.add(bullet)
all_sprites.update()
hits = pygame.sprite.groupcollide(enemies, bullets, True, True)
for hit in hits:
score += 100 # Increment score when enemy is destroyed
hitnumber += 1
if score == 10000:
hitnumber += 20
enemy = Enemy()
all_sprites.add(enemy)
enemies.add(enemy)
hits = pygame.sprite.spritecollide(player, enemies, False)
if hits: #Player hits enemy.
hitnumber -= 1
if hitnumber < 0:
gameover = fontgo.render("GameOver.Try for the Next.", True, (250,150,0))
screen.blit(gameover, (180, 290))
pygame.display.flip() # Update the display
pygame.time.wait(4000) # Wait for 4 seconds before exiting
pygame.quit()
sys.exit() #Game Exit
screen.fill((250,220,200))
all_sprites.draw(screen)
# Display score
score_text = font.render("1P:" + str(score), True, (0,200,250))
screen.blit(score_text, (10, 10)) #text position
#Update the display
pygame.display.flip()
hp=fonthp.render("HP:" + str(hitnumber), True, (0,250,150))
screen.blit(hp, (150, 10))
pygame.display.flip()
# Decrease HP by hitnumber
hpbar.decrease_health(hitnumber)
# Draw the HP bar
screen.blit(hpbar.image, (250, 10))
pygame.display.flip()
pygame.quit()
sys.exit()