import sys
import random
import pygame
class Snake(): #スネークのクラス
def __init__(self): #ゲームを初期状態にする関数・機能
self.length = 1 #スネークの長さを1(先頭のみ)に設定する
self.positions = [((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2))] #スネークの位置を画面の真ん中にする
self.direction = random.choice([up, down, left, right]) #スネークの進行方向をランダムに設定する
self.color = (17, 24, 47) #スネークの色を設定する
self.score = 0 #スコアを0にする
def get_head_position(self): #スネークの現在の先頭マスを呼んだコードに教える関数・機能
return self.positions[0]
def turn(self, point): #スネークの進行方向を変更する関数
if self.length > 1 and (point[0] * -1, point[1] * -1) == self.direction: #self.length > 1 ...スネークの長さ(length)が1より大きい and...かつ
#(point[0] * -1, point[1] * -1) == self.direction...進行方向が前後であれば、前後ろキーは無効、左右も同様に左右のキーが無効になる
return #何もしないで呼んだコードに戻る
else: #上の条件に満たしていない場合に以下のコードが使用される
self.direction = point
def move(self): #スネークを1マス進める関数・機能
cur = self.get_head_position() #現在のスネークの先頭マスを関数に聞く
x, y = self.direction #現在のスネークの進行方向を取得する
new = (((cur[0] + (x * GRIDSIZE)) % SCREEN_WIDTH), (cur[1] + (y * GRIDSIZE)) % SCREEN_HEIGHT) #次に移動するマスを計算する
if len(self.positions) > 2 and new in self.positions[2:]: #スネークの先頭とスネーク自身の体が重なった場合
self.reset() #スネークのマスや長さ、スコアをリセットする
elif cur[0] <= 0 or cur[0] >= SCREEN_HEIGHT - GRIDSIZE or cur[1] <= 0 or cur[1] >= SCREEN_WIDTH - GRIDSIZE: #スネークの先頭が壁にぶつかった場合
self.reset() #スネークのマスや長さ、スコアをリセットする
else: #↑2つの条件を満たさないとき
self.positions.insert(0, new) #マスの位置を新しく計算したマスを先頭のマスに設定する
if len(self.positions) > self.length: #現在のスネークの長さとポジションの数を比較して、スネークの長さが小さい場合 ※ポジションの数は、スネークの長さ+次に移動するマス
self.positions.pop() #一番後ろの体を消滅させる
def reset(self): #スネークの長さ、マス、進行方向、スコアを最初からにする関数・機能
self.length = 1 #スネークの長さを1マス(先頭だけ)にする
self.positions = [((SCREEN_WIDTH / 2), (SCREEN_HEIGHT / 2))] #スネークのマスを真ん中のマスに設定する
self.direction = random.choice([up, down, left, right]) #スネークの進行方向をランダムに設定する
self.score = 0 #スコアを0に設定する
def draw(self, surface): #画面にスネークを表示させる関数・機能
for p in self.positions: #スネークの長さ分繰り返す
r = pygame.Rect((p[0], p[1]), (GRIDSIZE, GRIDSIZE)) #スネークを表示させるマスを設定する
pygame.draw.rect(surface, self.color, r) #画面にスネークを表示させる
pygame.draw.rect(surface, (93, 216, 218), r, 1) #画面のスネークに隙間を表示させる
def handle_keys(self): #押されているキーを見て、キーによって使用するコードを変える関数・機能
for event in pygame.event.get(): #何が起きているか(イベント)見る
if event.type == pygame.QUIT: #画面が閉じられている場合
pygame.quit() #ゲームを終了する
sys.exit() #プログラムを終了する
elif event.type == pygame.KEYDOWN: #キーボードのキーが押された場合
if event.key == pygame.K_UP: #↑キーが押された場合
self.turn(up) #進行方向を↑に設定する
elif event.key == pygame.K_DOWN: #↓キーが押された場合
self.turn(down) #進行方向を↓に設定する
elif event.key == pygame.K_LEFT: #←キーが押された場合
self.turn(left) #進行方向を←に設定する
elif event.key == pygame.K_RIGHT: #→キーが押された場合
self.turn(right) #進行方向を→に設定する
class Food(): #食べ物のクラス
def __init__(self): #ゲームを初期状態にする関数・機能
self.position = (0, 0) #食べ物を配置するマスを左上に設定する変数
self.color = (223, 163, 49) #食べ物の色を設定する変数
self.randomize_position() #食べ物をランダムなマスに配置する関数を呼ぶ
def randomize_position(self): #食べ物をランダムなマスに配置する関数・機能
X = random.randint(1, GRID_WIDTH - 2) * GRIDSIZE
Y = random.randint(1, GRID_HEIGHT - 2) * GRIDSIZE
self.position = (X,Y) #↑で計算したマスを食べ物を配置するマスとして設定する
def draw(self, surface): #画面に食べ物を表示させる関数・機能
r = pygame.Rect(self.position, (GRIDSIZE, GRIDSIZE)) #食べ物を表示させるマスを設定する
pygame.draw.rect(surface, self.color, r) #食べ物を表示させる
pygame.draw.rect(surface, (93, 216, 228), r, 1) #食べ物の周りに隙間を表示させる
def drawGrid(surface): #画面の背景を表示させる関数・機能
for y in range(0, int(GRID_HEIGHT)): #画面の縦幅分繰り返す
for x in range(0, int(GRID_WIDTH)): #画面の横幅分繰り返す
if (x + y) % 2 == 0: #縦の位置+横位置から2で割った際に、割り切れるマスの場合
r = pygame.Rect((x * GRIDSIZE, y * GRIDSIZE), (GRIDSIZE, GRIDSIZE)) #マスの場所を設定
pygame.draw.rect(surface, (93, 216, 228), r) #マスを表示させる
else: #縦の位置+横位置から2で割った際に、割り切れないマスの場合
rr = pygame.Rect((x * GRIDSIZE, y * GRIDSIZE), (GRIDSIZE, GRIDSIZE)) #マスの場所を設定
pygame.draw.rect(surface, (84, 194, 205), rr) #マスを表示させる
SCREEN_WIDTH = 480 #画面の横幅
SCREEN_HEIGHT = 480 #画面の縦幅
GRIDSIZE = 20 #1マスのサイズ
GRID_WIDTH = SCREEN_HEIGHT / GRIDSIZE #1画面に存在する横のマスの数
GRID_HEIGHT = SCREEN_WIDTH / GRIDSIZE #1画面に存在する縦のマスの数
up = (0, -1) #上マスに移動するための数字 0 ...右に0マス移動 -1...下に-1マス移動(つまり上方向に移動)
down = (0, 1) #下マスに移動するための数字 0 ...右に0マス移動 1 ...下に1マス移動
left = (-1, 0) #左マスに移動するための数字 -1 ...右に-1マス移動(左方向に移動)0...下に0マス移動
right = (1, 0) #下マスに移動するための数字 1 ...右に1マス移動 0 ...下に0マス移動
def main():
try:
#ゲームを使用できるようにする(初期化)
pygame.init() #ゲームを初期状態にする
clock = pygame.time.Clock() #ゲームで使うタイマーの間隔
screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), 0, 32) #画面のサイズを決めたうえで画面を作成する
#表示するための画面を作る
surface = pygame.Surface(screen.get_size()) #まっさらな画面の作成 ※screen と surfaceは別の画面であることに注意
surface = surface.convert() #↑で作成した画面のコピーを取る
drawGrid(surface) #作成したまっさらな画面にゲームの背景部分を表示する
#スネークと食べ物を使用できるようにする
snake = Snake() #スネークの機能を使えるようにする(スネークの初期化)
food = Food() #食べ物の機能を使えるようにする(食べ物の初期化)
#文字の表示について設定する
myfont = pygame.font.SysFont("monospace", 16) #スコアの表示を設定する
while (True):
clock.tick(10) #1秒に10回実行(移動)する
snake.handle_keys() #キーボードでどのキーが押されているかチェックして、上下左右のキーが押されていたら方向を変える
drawGrid(surface) #画面にゲームの背景部分を表示する
snake.move() #現在の進行方向に1マス進め、その後、ゲームオーバーの条件を満たしているかチェックする。満たしている場合はゲームをリセットする
if snake.get_head_position() == food.position: #スネークの先頭(頭の部分)のマスと食べ物があるマスを比較して、場所が同じ場合に以下3行のコードを使用する
snake.length += 1 #スネークの長さを1マス増やす
snake.score += 1 #スコアをプラス1する
food.randomize_position() #食べ物の場所をランダムに設定する
snake.draw(surface) #画面にスネークを表示する
food.draw(surface)#画面に食べ物を表示する
screen.blit(surface, (0, 0)) #screenの画面の左上(0,0)にsurface(スネークと食べ物)の画面を描く
text = myfont.render("Score {0}".format(snake.score), 1, (0, 0, 0)) #スコアの絵を作る
screen.blit(text, (5, 10)) #screenの画面の左上(5,10)にtext(スコア)の絵を描く
pygame.display.update() #画面を更新する
except Exception as err:
raise Exception("Error") from err
main() #プログラムを開始する関数を呼ぶ