実施報告01:Pygame Platformer
このnoteではChatGPTを使った報告を書こうと思っていたのですが、今回の話題は次のチュートリアルの実施報告が主体でChatGTPの関与が少ないのでタイトルからChatGPTを外しました。これからもいろいろと脱線しますが、よろしくご了承ください。
いろんな概念
今回のプログラムに含まれるのは次のような概念です。
1. Collision Detection
2. Player movement(realistic sideways movement)
3. Jump mechanics
4. Gravity and Friction
5. Random Level Generation
6. Warpable screen movement
7. Scrolling the screen(creating an infinite height)
8. Creating a Score counter
9. "Game Over" Mechanic
10. Random Platform movement
Part1-Setting the Foundation
まず、最初に今回のゲームの基礎を述べます。
初期化と定数
import pygame
from pygame.locals import *
pygame.init()
vec = pygame.math.Vector2 # 2 for two dimensional
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
とりあえずは、この初期化と必要な定数を設定します。
この結果は下記になります。
Player and Platform Classes
ここではPlayerとPlatformClassとして表示します。
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((30, 30))
self.surf.fill((128,255,40))
self.rect = self.surf.get_rect(center = (10, 420))
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((WIDTH, 20))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
PT1 = platform()
P1 = Player()
各々のClassは固定の大きさ、各々の色、最後に各々の四角形を決めます。最終的に二つのオブジェクトPT1,P1を得ます。
Sprites Groups + Game Loop
前期で作ったPT1とP1をそのまま使うのでなく、Groupの一員としてあつかい、いろんなスプライトを容易に扱えるようにします。
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
displaysurface.fill((0,0,0))
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
pygame.display.update()
FramePerSec.tick(FPS)
具体的には一つ一つ、PT1、P1でなく、下記の形でグループ化の効果が示される。
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
この時点の結果は次に示されます。
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
Implementing Movement
Playerを動かすためにClassに位置、速度、加速度の(x、y)方向の成分を追加します。ちなみにvecはベクトルの意味ですね。
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((30, 30))
self.surf.fill((128,255,40))
self.rect = self.surf.get_rect()
self.pos = vec((10, 385))
self.vel = vec(0,0)
self.acc = vec(0,0)
次にmoveの関数を付け加えます。
def move(self):
self.acc = vec(0,0)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
一般的に動かすときのプログラムは次になります。
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
また、X方向の両端まで行けば反対側から動かすようにます。
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
これでPlayerを動かすためには、つぎを記述します。
P1.move()
ちょっと細切れのCodeになりましたが、無事、前のCodeに挿入できたでしょうか? P1.move()の位置が難しかったかもしれません。
次に今までのコードを示します。
import pygame
from pygame.locals import *
import sys
pygame.init()
vec = pygame.math.Vector2
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((30, 30))
self.surf.fill((128,255,40))
self.rect = self.surf.get_rect()
self.pos = vec((10, 385))
self.vel = vec(0,0)
self.acc = vec(0,0)
def move(self):
self.acc = vec(0,0)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((WIDTH, 20))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
PT1 = platform()
P1 = Player()
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
displaysurface.fill((0,0,0))
P1.move()
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
pygame.display.update()
FramePerSec.tick(FPS)
結果はつぎのようになります。
Part2 – Gravity and Jumping
Implementing Gravity
今まで、X軸方向に加速度を考慮したので、Y軸方向に重力加速度を考慮するのはただつぎのようにmove関数のvec(0,0)をvec(0,0.5)とするだけでいい。
def move(self):
self.acc = vec(0,0.5)
pressed_keys = pygame.key.get_pressed()
...
...
The effects of Gravity
一寸プログラムをいじって下記に動画を示します。
次に衝突の問題があります。
...
def update(self):
hits = pygame.sprite.spritecollide(P1 , platforms, False)
if hits:
self.pos.y = hits[0].rect.top + 1
self.vel.y = 0
...
...
platforms = pygame.sprite.Group()
platforms.add(PT1)
ここでは新しいcodeが二つあります。一つは衝突の判定、もう一つは新しくはPlatformのGroupの作成です。なお、spritecollideの第3のパラメーターは通常Falseでいいかと思います。
あと、二つのことが重要です。一つは着地の際にPlayerの速度をゼロにすること、一つはPlayerの位置をplatformの上に接地させないといけません。
この結果を下に示します。
Player Jumping
重力の影響を入れることができたので次はジャンプの機能を追加します。これはすごく簡単です。上へ行くには負の速度を与えます。
def jump(self):
self.vel.y = -15
次にスペースキーを押したときにジャンプさせるために次のcodeを追加します。
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
...
...
これだけだと、スペースキーを押すとすぐに飛び上がり、重力で落ちてくるという感じが出ません。スペースキーを押すと一度だけ効いてあとは重力で落ちてきたいのです。
def update(self):
hits = pygame.sprite.spritecollide(P1 ,platforms, False)
if P1.vel.y > 0:
if hits:
self.vel.y = 0
self.pos.y = hits[0].rect.top + 1
上記の if codeを追加することでPlayerが落ちてくるときに衝突判定をし、その時に速度をゼロ、地上に接地としている。
ダブルジャンプの問題はつぎのcodeを挿入します。
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits:
self.vel.y = -15
Part2 を終えるにあたり、全体のCodeを整理しておきます。
import pygame
from pygame.locals import *
import sys
import random
pygame.init()
vec = pygame.math.Vector2 #2 for two dimensional
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
#self.image = pygame.image.load("character.png")
self.surf = pygame.Surface((30, 30))
self.surf.fill((128,255,40))
self.rect = self.surf.get_rect()
self.pos = vec((10, 360))
self.vel = vec(0,0)
self.acc = vec(0,0)
def move(self):
self.acc = vec(0,0.5)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits:
self.vel.y = -15
def update(self):
hits = pygame.sprite.spritecollide(P1 ,platforms, False)
if P1.vel.y > 0:
if hits:
self.vel.y = 0
self.pos.y = hits[0].rect.top + 1
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((WIDTH, 20))
self.surf.fill((255,0,0))
self.rect = self.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
def move(self):
pass
PT1 = platform()
P1 = Player()
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
platforms = pygame.sprite.Group()
platforms.add(PT1)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
displaysurface.fill((0,0,0))
P1.update()
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
entity.move()
pygame.display.update()
FramePerSec.tick(FPS)
結果をここに示します。
Part3-Level Generation
Initial Level Generation
レベル生成コードを二つの部分に分けます。
最初のコードはゲーム開始時に一回だけ実行されます。
for x in range(random.randint(5, 6)):
pl = platform()
platforms.add(pl)
all_sprites.add(pl)
上記のコードは5~6のPlatformを生成します
Updating the Platform Class
ランダムなレベル生成のためにplatformの拡張をします。
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((random.randint(50,100), 12))
self.surf.fill((0,255,0))
self.rect = self.surf.get_rect(center = (random.randint(0,WIDTH-10),
random.randint(0, HEIGHT-30)))
当然、今までのplatformは別扱いしなければなりません。
PT1.surf = pygame.Surface((WIDTH, 20))
PT1.surf.fill((255,0,0))
PT1.rect = PT1.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
Infinite Scrolling Screen
キャラクターが無限に上に移動できる機能を作成する必要があります。次のコードをゲームループに挿入してください。
if P1.rect.top <= HEIGHT / 3:
P1.pos.y += abs(P1.vel.y)
for plat in platforms:
plat.rect.y += abs(P1.vel.y)
if plat.rect.top >= HEIGHT:
plat.kill()
・ if P1.rect.top <= HEIGHT / 3:
Playerの位置がHEIGHT/3でこの中のコード if statement が実行されます。この位置は実験的に決められました
・ P1.pos.y += abs(P1.vel.y)
p1をその速度で動かします。絶対値をつけて速度値から府の符号を削除します
・ for plat in platforms:
・ plat.rect.y += abs(P1.vel.y)
playerだけでなく、すべてのplatformについても行います。
・ if plat.rect.top >= HEIGHT:
・ plat.kill()
画面からはみ出したplatformはすべて破壊されます。
Random Level Generation
platformは画面の上の方まで作っておき、playerが上に移動するとこれらのplatformが表示されます。
def plat_gen():
while len(platforms) < 7 :
width = random.randrange(50,100)
p = platform()
p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
platforms.add(p)
all_sprites.add(p)
このCodeの簡単な説明です
・ while len(platforms) < 7 :
実験結果と深い考察で決められたようです(^^♪
・ width = random.randrange(50,100)
多様性のためランダムな幅を追加
・ p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
platforms.add(p)
all_sprites.add(p)
画面の表示部分の真上にplatformを作成して配置します。platforms Groupとall_sprites Groupに追加されます。
ちょっと難しくなりましたが、次にCodeを示します。
import pygame
from pygame.locals import *
import sys
import random
pygame.init()
vec = pygame.math.Vector2
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((30, 30))
self.surf.fill((255,255,0))
self.rect = self.surf.get_rect()
self.pos = vec((10, 360))
self.vel = vec(0,0)
self.acc = vec(0,0)
def move(self):
self.acc = vec(0,0.5)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits:
self.vel.y = -15
def update(self):
hits = pygame.sprite.spritecollide(P1 ,platforms, False)
if P1.vel.y > 0:
if hits:
self.vel.y = 0
self.pos.y = hits[0].rect.top + 1
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((random.randint(50,100), 12))
self.surf.fill((0,255,0))
self.rect = self.surf.get_rect(center = (random.randint(0,WIDTH-10),
random.randint(0, HEIGHT-30)))
def move(self):
pass
def plat_gen():
while len(platforms) < 7 :
width = random.randrange(50,100)
p = platform()
p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
platforms.add(p)
all_sprites.add(p)
PT1 = platform()
P1 = Player()
PT1.surf = pygame.Surface((WIDTH, 20))
PT1.surf.fill((255,0,0))
PT1.rect = PT1.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
platforms = pygame.sprite.Group()
platforms.add(PT1)
for x in range(random.randint(5, 6)):
pl = platform()
platforms.add(pl)
all_sprites.add(pl)
while True:
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
if P1.rect.top <= HEIGHT / 3:
P1.pos.y += abs(P1.vel.y)
for plat in platforms:
plat.rect.y += abs(P1.vel.y)
if plat.rect.top >= HEIGHT:
plat.kill()
displaysurface.fill((0,0,0))
P1.update()
plat_gen()
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
entity.move()
pygame.display.update()
FramePerSec.tick(FPS
結果を下記に示します。
最初にランダムに数枚のページを作ったのが理解できます(^^♪ ちょっとできないなというのも出てきました。
Part4-Improving the game
このセクションでは次の小さな修正を追加します。
・ プレイヤーがプラットフォームに着地する方法を修正する
・ ジャンプ機構の改善
・ プラットフォーム生成の改善 (プラットフォーム間の衝突)
pygameでゲームを作成するのは簡単ですが、それを改善して完成させることは一つの挑戦です。以下には幾つかの小さい改善についてすべて説明します。
The Jump Mechanic
ここではジャンプの種類を大きなジャンプと小さなジャンプに分けます。
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
...
...
self.jumping = False
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits and not self.jumping:
self.jumping = True
self.vel.y = -15
def cancel_jump(self):
if self.jumping:
if self.vel.y < -3:
self.vel.y = -3
最初の変更は、self.jumping という新しい変数の追加です。これを使用して、プレイヤーがジャンプ位置にいるかどうかを判断します。
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
P1.cancel_jump()
スペースバーをさまざまな時間押すことで、ジャンプの持続時間と大きさを変えることができ、短いジャンプと長いジャンプの両方を行うことができました。
Platform Generation
近すぎたplatformを整理するために次の関数を作ります。
def check(platform, groupies):
if pygame.sprite.spritecollideany(platform,groupies):
return True
else:
for entity in groupies:
if entity == platform:
continue
if (abs(platform.rect.top - entity.rect.bottom) < 50) and (abs(platform.rect.bottom - entity.rect.top) < 50):
return True
C = False
次にplat_gen()関数を修正します。
def plat_gen():
while len(platforms) < HARD :
width = random.randrange(50,100)
p = platform()
C = True
while C:
p = platform()
p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
C = check(p, platforms)
platforms.add(p)
all_sprites.add(p)
Player Landing
def update(self):
hits = pygame.sprite.spritecollide(self ,platforms, False)
if self.vel.y > 0:
if hits:
if self.pos.y < hits[0].rect.bottom:
self.pos.y = hits[0].rect.top +1
self.vel.y = 0
self.jumping = False
if self.pos.y < lowest.rect.bottom:
プレイヤーの y 位置がプラットフォームの下部を超えなくなるまで、「着陸」が登録されないようにします。
いままでの議論をまとめると、つぎのようになります。
import pygame
from pygame.locals import *
import sys
import random
pygame.init()
vec = pygame.math.Vector2 #2 for two dimensional
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
#self.image = pygame.image.load("character.png")
self.surf = pygame.Surface((30, 30))
self.surf.fill((255,255,0))
self.rect = self.surf.get_rect()
self.pos = vec((10, 360))
self.vel = vec(0,0)
self.acc = vec(0,0)
self.jumping = False
def move(self):
self.acc = vec(0,0.5)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits and not self.jumping:
self.jumping = True
self.vel.y = -15
def cancel_jump(self):
if self.jumping:
if self.vel.y < -3:
self.vel.y = -3
def update(self):
hits = pygame.sprite.spritecollide(self ,platforms, False)
if self.vel.y > 0:
if hits:
if self.pos.y < hits[0].rect.bottom:
self.pos.y = hits[0].rect.top +1
self.vel.y = 0
self.jumping = False
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((random.randint(50,100), 12))
self.surf.fill((0,255,0))
self.rect = self.surf.get_rect(center = (random.randint(0,WIDTH-10),
random.randint(0, HEIGHT-30)))
def move(self):
pass
def check(platform, groupies):
if pygame.sprite.spritecollideany(platform,groupies):
return True
else:
for entity in groupies:
if entity == platform:
continue
if (abs(platform.rect.top - entity.rect.bottom) < 40) and (abs(platform.rect.bottom - entity.rect.top) < 40):
return True
C = False
def plat_gen():
while len(platforms) < 6:
width = random.randrange(50,100)
p = platform()
C = True
while C:
p = platform()
p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
C = check(p, platforms)
platforms.add(p)
all_sprites.add(p)
PT1 = platform()
P1 = Player()
PT1.surf = pygame.Surface((WIDTH, 20))
PT1.surf.fill((255,0,0))
PT1.rect = PT1.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
platforms = pygame.sprite.Group()
platforms.add(PT1)
for x in range(random.randint(4,5)):
C = True
pl = platform()
while C:
pl = platform()
C = check(pl, platforms)
platforms.add(pl)
all_sprites.add(pl)
while True:
P1.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
P1.cancel_jump()
if P1.rect.top <= HEIGHT / 3:
P1.pos.y += abs(P1.vel.y)
for plat in platforms:
plat.rect.y += abs(P1.vel.y)
if plat.rect.top >= HEIGHT:
plat.kill()
plat_gen()
displaysurface.fill((0,0,0))
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
entity.move()
pygame.display.update()
FramePerSec.tick(FPS)
結果の初期状態を示します。purattoformが程よい間隔で並べられているようですね・
Pygame Platformer – Completing the Game
前のセクションまででほとんどのことは終了した。あと少し、次のようなことを行います。
・ ゲームオーバー画面
・ スコアシステム
・ ムービングプラットフォーム
Implementing a Game Over Screen
import time
...
...
while True:
...
...
...
if P1.rect.top > HEIGHT:
for entity in all_sprites:
entity.kill()
time.sleep(1)
displaysurface.fill((255,0,0))
pygame.display.update()
time.sleep(1)
pygame.quit()
sys.exit()
if P1.rect.top > HEIGHT:
最後、失敗すると画面下にplayerは画面外へ落ちていくが、その時点ですべてのスプライトは強制終了となり、画面が赤になり、ゲームオーバーとなります。
High Score
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
...
...
self.jumping = False
self.score = 0 ##
...
...
def update(self):
hits = pygame.sprite.spritecollide(self ,platforms, False)
if self.vel.y > 0:
if hits:
if self.pos.y < hits[0].rect.bottom:
if hits[0].point == True: ##
hits[0].point = False ##
self.score += 1 ##
self.pos.y = hits[0].rect.top +1
self.vel.y = 0
self.jumping = False
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
...
...
self.moving = True
self.point = True ##
...
...
PT1.moving = False
PT1.point = False ##
...
...
while True:
...
...
...
displaysurface.fill((0,0,0))
f = pygame.font.SysFont("Verdana", 20) ##
g = f.render(str(P1.score), True, (123,255,0)) ##
displaysurface.blit(g, (WIDTH/2, 10)) ##
for entity in all_sprites:
...
Moving Platforms in Pygame
class platform(pygame.sprite.Sprite):
def __init__(self):
...
...
self.speed = random.randint(-1, 1)
self.moving = True
def move(self):
if self.moving == True:
self.rect.move_ip(self.speed,0)
if self.speed > 0 and self.rect.left > WIDTH:
self.rect.right = 0
if self.speed < 0 and self.rect.right < 0:
self.rect.left = WIDTH
...
...
...
PT1.moving = False
最終的なCodeはつぎのようになります。
import pygame
from pygame.locals import *
import sys
import random
import time
pygame.init()
vec = pygame.math.Vector2 #2 for two dimensional
HEIGHT = 450
WIDTH = 400
ACC = 0.5
FRIC = -0.12
FPS = 60
FramePerSec = pygame.time.Clock()
displaysurface = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Game")
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
#self.image = pygame.image.load("character.png")
self.surf = pygame.Surface((30, 30))
self.surf.fill((255,255,0))
self.rect = self.surf.get_rect()
self.pos = vec((10, 360))
self.vel = vec(0,0)
self.acc = vec(0,0)
self.jumping = False
self.score = 0
def move(self):
self.acc = vec(0,0.5)
pressed_keys = pygame.key.get_pressed()
if pressed_keys[K_LEFT]:
self.acc.x = -ACC
if pressed_keys[K_RIGHT]:
self.acc.x = ACC
self.acc.x += self.vel.x * FRIC
self.vel += self.acc
self.pos += self.vel + 0.5 * self.acc
if self.pos.x > WIDTH:
self.pos.x = 0
if self.pos.x < 0:
self.pos.x = WIDTH
self.rect.midbottom = self.pos
def jump(self):
hits = pygame.sprite.spritecollide(self, platforms, False)
if hits and not self.jumping:
self.jumping = True
self.vel.y = -15
def cancel_jump(self):
if self.jumping:
if self.vel.y < -3:
self.vel.y = -3
def update(self):
hits = pygame.sprite.spritecollide(self ,platforms, False)
if self.vel.y > 0:
if hits:
if self.pos.y < hits[0].rect.bottom:
if hits[0].point == True:
hits[0].point = False
self.score += 1
self.pos.y = hits[0].rect.top +1
self.vel.y = 0
self.jumping = False
class platform(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.surf = pygame.Surface((random.randint(50,100), 12))
self.surf.fill((0,255,0))
self.rect = self.surf.get_rect(center = (random.randint(0,WIDTH-10),
random.randint(0, HEIGHT-30)))
self.speed = random.randint(-1, 1)
self.point = True
self.moving = True
def move(self):
if self.moving == True:
self.rect.move_ip(self.speed,0)
if self.speed > 0 and self.rect.left > WIDTH:
self.rect.right = 0
if self.speed < 0 and self.rect.right < 0:
self.rect.left = WIDTH
def check(platform, groupies):
if pygame.sprite.spritecollideany(platform,groupies):
return True
else:
for entity in groupies:
if entity == platform:
continue
if (abs(platform.rect.top - entity.rect.bottom) < 40) and (abs(platform.rect.bottom - entity.rect.top) < 40):
return True
C = False
def plat_gen():
while len(platforms) < 6:
width = random.randrange(50,100)
p = platform()
C = True
while C:
p = platform()
p.rect.center = (random.randrange(0, WIDTH - width),
random.randrange(-50, 0))
C = check(p, platforms)
platforms.add(p)
all_sprites.add(p)
PT1 = platform()
P1 = Player()
PT1.surf = pygame.Surface((WIDTH, 20))
PT1.surf.fill((255,0,0))
PT1.rect = PT1.surf.get_rect(center = (WIDTH/2, HEIGHT - 10))
all_sprites = pygame.sprite.Group()
all_sprites.add(PT1)
all_sprites.add(P1)
platforms = pygame.sprite.Group()
platforms.add(PT1)
PT1.moving = False
PT1.point = False ##
for x in range(random.randint(4,5)):
C = True
pl = platform()
while C:
pl = platform()
C = check(pl, platforms)
platforms.add(pl)
all_sprites.add(pl)
while True:
P1.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
P1.jump()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
P1.cancel_jump()
if P1.rect.top > HEIGHT:
for entity in all_sprites:
entity.kill()
time.sleep(1)
displaysurface.fill((255,0,0))
pygame.display.update()
time.sleep(1)
pygame.quit()
sys.exit()
if P1.rect.top <= HEIGHT / 3:
P1.pos.y += abs(P1.vel.y)
for plat in platforms:
plat.rect.y += abs(P1.vel.y)
if plat.rect.top >= HEIGHT:
plat.kill()
plat_gen()
displaysurface.fill((0,0,0))
f = pygame.font.SysFont("Verdana", 20)
g = f.render(str(P1.score), True, (123,255,0))
displaysurface.blit(g, (WIDTH/2, 10))
for entity in all_sprites:
displaysurface.blit(entity.surf, entity.rect)
entity.move()
pygame.display.update()
FramePerSec.tick(FPS)
結果はつぎのようになります。ちょっと短いですが、よかったら、うえのCodeをコピーして実行してみてください。
実施後の感想
ChatGPTでプログラミングをしたときに、ジャンプの扱いができなくて、ChatGPTからも重力加速度の考慮が必要だといわれ、そういうモジュールがあるのではと思い、うまくコミュニケーションが取れなかった。今回、そこは自分で行うことと分かり、一つの理解が進んだかと思う。
後半の理解が不十分だけれど、また、自分での作品つくりで、使うときに考えたいと思う。
2023年4月30日 記録
この記事が気に入ったらサポートをしてみませんか?