UdemyでPythonを勉強した結果を残すブログ。

40歳でプログラミング始めて転職までいけるのかを実録してみます。

DAY23 Turtleモジュールをもっと応用して障害物よけゲームを作る

今回はTurtleモジュールを使ってもう1個ゲームを作る講座。

今回は障害物よけゲームです。

Udemyの講座では長方形が動くようにしていますが、

自分のは復習と応用も兼ねてshapeをタートルにしてクリアするたびに難易度があがる設定を追加しています。

クラッチから書けたので、コーディング自体は荒削りだと思います。

 

クラッチからってなんだよって始めたとき思ってたけど

「最初から」ということなんですね。

フルスクラッチでというのはネットからのコピペもなしでということ…すごいわ

 

こんな感じのゲームイメージ

白い亀がタートルから通り過ぎるタートルを避けて上まで通り抜けるというゲーム。

f:id:GO-py:20220409093531p:plain

 

流れとしてはこんな感じ

  • プレイヤーのタートルを作り、下からスタートする。
    上のみ動ける仕様にする。
  • 敵のクラスを作る。色はランダムにし、動くスピードもランダムにする。
    右端でy軸はランダムに設置していく。
  • 上に行ったらゴール・次のレベルを表示し、下に戻る。

 

それでは始めます。

 

プレイヤーのクラスを作る

tim.py 

これは今までの流れからすると難しいことはしていないので

全部のコードを。

 

from turtle import Turtle
import random
START_POSITION = (0, -280)

class Tim(Turtle):

def __init__(self):
super(Tim, self).__init__()
self.shape("turtle")
self.color("white")
self.penup()
self.setheading(90)
self.start()
self.goto(START_POSITION)

def start(self):
self.goto(random.randint(-200, 200), -280)

def move(self):
new_y = self.ycor() + 20
self.goto(self.xcor(), new_y)

udemyの講座だと常にx軸は真ん中からのスタートにしたけど

今回はゴールするたびにx軸も-200から200の間の何処かからのスタートに。

 

 

次に、横切るタートルのクラスを作成

enemies.py

main.pyでたくさんのタートルを作るため、このクラスの初期値では

作るたびにタートルの色とはじまる位置を変更する機能をいれます。

右から左にいくので、頭の位置は左向きに。

 

from turtle import Turtle
import random


class Enemies(Turtle):
def __init__(self):
super(Enemies, self).__init__()
self.shape("turtle")
self.penup()
col_r = random.randint(100, 255)
col_g = random.randint(100, 255)
col_b = random.randint(100, 255)
random_y = random.randint(-250, 250)
self.color(col_r, col_g, col_b)
self.setheading(180)
self.goto(300, random_y)

 

ランダムなスピードで歩く機能を追加します。

スピードは毎回違うように設定します。

 


def move(self):
new_x = self.xcor() - random.randint(4, 20)
self.goto(new_x, self.ycor())

 

これで横切るタートルの設定はおしまい。

 

 

メッセージ表示部分のクラスを作成

msg.py

  • 左上に現在のレベル表示
  • 上に着いたらゴール!次のレベルを表示
  • 敵に当たったらゲームオーバー

の3つを表示する機能を作ります。

 

from turtle import Turtle
import time

class Msg(Turtle):
def __init__(self):
super(Msg, self).__init__()
self.color("white")
self.penup()
self.ht()
self.level_num = 1
self.display_level()

初期値はこんな感じ。

display_levelは左上にgoto()して、writeでlevel_numの変数を呼び出して表示します。

 


def display_level(self):
self.clear()
self.goto(-280, 260)
self.write(f"Level {self.level_num}", font=("Futura", 20, "bold"), align="left")

 

ゴールしたときの表示はこんな感じ

レベル表示で書く位置が左上に行ってるので、最初にgoto(0, 0)にしてから書く。

ここでimportしたtimeを使います。Goal!と2秒表示、その後次のレベルを2秒表示。

 


def goal(self):
self.goto(0, 0)
self.clear()
self.write("Goal!!", font=("Futura", 40, "bold"), align="center")
time.sleep(2)
self.clear()
self.level_num += 1
self.write(f"Level {self.level_num}", font=("Futura", 40, "bold"), align="center")
time.sleep(2)
self.clear()

 

負けたらゲームオーバーのテキストを真ん中に表示します。


def game_over(self):
self.goto(0, 0)
self.write("Game Over.", font=("Futura", 20, "bold"), align="center")

 

これでクラスファイルの作成は終わり。

 

 

main.pyでオブジェクトをまとめてゲームにしていく

仕上げていきます。

今まで作ったものは全てインポートして、こちらもscreen, timeなどもインポートしていきます。

 

from turtle import Screen
from tim import Tim
from msg import Msg
from enemies import Enemies
import random
import time

tim = Tim()
msg = Msg()
screen = Screen()
screen.colormode(255)
screen.setup(600, 600)
screen.bgcolor("black")
screen.tracer(0)

enemies_list = []

screen.listen()
screen.onkey(tim.move, "Up")

 

enemies_list のリストは、スネークゲームの時と同じように

敵のタートルを1つずつリストに格納していってそれぞれが独立したランダムな動きをするために設定しています。

 

screen.listen()とonkey()のセットで、上のキーを押すたびに上にあがる機能に。

 


difficulty = [0,1,0]

game_on = True
while game_on:
screen.update()
    time.sleep(0.1)
for i in range(random.choice(difficulty)):
enemies = Enemies()
enemies_list.append(enemies)

for enemie in enemies_list:
enemie.move()
if enemie.xcor() <= -330:
enemies_list.remove(enemie)

if tim.distance(enemie) <= 20:
msg.game_over()
game_on = False

difficultyのリストは敵のタートルを出現するときに何人追加するかをランダムで決めるためのリストです。

whileで動かすたびに敵を作ってたら大渋滞になるので(試しにこのリストを1,1とかにしてみてください)

作らない時もあるようにしています。

 

で作ったらenemies_listに格納していって、次のforでそれぞれを動かしていきます。

xcor() <= -330の部分のifは、敵のタートルが左端にいってもそのままにしとくと

オブジェクトはずっとたまっていくので、リストがどんどん増えていきます。

超上級者がいた場合もしかしたら動きがもっさりする可能性もあるので、

敵のタートルが左端へ消えたらリストから削除するようにremoveを入れています。

 

また最後に敵タートルにぶつかったときに

ゲームオーバーの文字を表示すると同時にgame_on = Falseにして動きをストップしています。

 

time.sleepはゲームスピードを調整しています。

ここをいじることで難易度がより調整できます。

 


if tim.ycor() >= 300:
msg.goal()
for enemie in enemies_list:
enemie.goto(-320, enemie.ycor())
if len(difficulty) <= 8:
difficulty.append(1)
else:
difficulty.append(random.randint(1,2))
tim.start()
msg.display_level()

screen.exitonclick()

 

仕上げに、プレイヤーが上に行ったときの表示を設定していきます。

難易度の調整もゴールに行ったときにしていて、

difficultyのリスト数が8以下ならリストに1を追加していって敵タートルの出現確率を上げるようにしています。

さらにLEVEL 6以降は出現数を2にしたりもして難易度を上げるようにしています。

 

最後にscreen.exitonclick()で締め。

 

 

今回は復習ということでとりあえず自分で作れるなら作ってみよう、

どうせ作れなさそうだしあとで動かないところお手本ソースコピーして勉強しよう

くらいに思ってたら全部作れたので嬉しい。笑

 

 

今回の全てのコードはGitに上げています。

実務だとGitもいるだろうし今回からはGitでアップロードするようにします。

 

github.com