お知らせ
GIF
キャラクターについて書いていこうと思いますが、aidiaryさんのコードを参考にした方が早いかもしれませんね。
人工知能に関する断創録
ぼくのコードはaidiaryさんのコードをちょっと短くしただけです。
キャラクターの描画
ここをクリックしてください
まずはキャラクターの画像をダウンロードしましょう。
キャラチップ.zipを選びましょう。
ぴぽや倉庫 ここからダウンロード
FileNotFoundError
というエラーが出たら、rを"パス"の前につけましょう。。
import pygame
import sys
from pygame.locals import *
pygame.init()
screen = pygame.display.set_mode((160, 160))
pygame.display.set_caption('chara only')
# ここにキャラクター画像ののパスを貼り付ける
player = pygame.image.load(パス)
while (1):
screen.fill((0, 0, 0))
screen.blit(player,(64,64),(0,0,32,32))
pygame.display.update()
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
screen.blit(player,(64,64),(0,0,32,32))
(64,64)は画像を中央に描画するための座標です。
画面サイズ / 2 - 画像サイズ / 2
160 / 2 - 32 / 2 = 64
(0,0,32,32)
(キャラ画像の横座標、キャラ画像の縦座標、横の大きさ、縦の大きさ)
キャラクターの移動
ここをクリックしてください
import pygame
from pygame.locals import *
import sys
pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption('chara_move')
x,y = 2,2
GS = 32
#ここにキャラのパスを貼り付ける
player = pygame.image.load(パス)
while (1):
screen.fill((0,0,0))
screen.blit(player, (x*GS, y*GS), (0, 0, GS, GS))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type==KEYDOWN:
if event.key==K_DOWN:
y += 1
elif event.key==K_UP:
y -= 1
elif event.key==K_RIGHT:
x += 1
elif event.key==K_LEFT:
x -= 1
x,y = 0,0
マス単位の座標です。
ここを変えることでキャラクターの初期位置を変えることができます。
GS = 32
マスの大きさです。
screen.blit(player, (x*GS, y*GS))
マス単位の座標にマスの大きさをかけています。
x,y = 0, 0
(0*32, 0*32) つまり (0, 0)
キャラクターの描画では(64, 64)でしたね。これをここと同じように書くと
x,y = 2, 2
(2*32, 2*32) つまり (64, 64)
図で位置を表してみました。赤が(0, 0) 青が(64, 64)
if event.type==KEYDOWN:
何かキーが押された時。
elif event.key==K_DOWN:
ダウンキーが押されたとき。
y += 1
yを変更しています。
x,y = 0, 0 だと x,y = 0, 1 に変更。
screen.blit(player, (x*GS, y*GS))だから
(0*GS, 0*GS) だと (0*GS, 1*GS) に変更。
ピクセル単位の座標にすると (0, 0) が (0, 32) になります。
つまり、キャラクターが下に移動します。
キャラアニメ
ここをクリックしてください
ここからキャラクターチップをダウンロードできます。
↓画像を追加するコードです。
画像を追加
キャラが、その場足踏みしているように見えるコードです。
aidiaryさんのコードを短くしたコードです。
背景が透明な画像用に書き換えました。
import pygame
from pygame.locals import *
import sys
def split_img(img):
split_list = []
for i in range(0, 128, GS):
surface = pygame.Surface((GS, GS), pygame.SRCALPHA)
surface.blit(img, (0, 0), (i, 0, GS, GS))
split_list.append(surface)
return split_list
pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption('chara anime')
x,y = 2,2
GS = 32
#ここにキャラのパスを貼り付ける
playerImgList = split_img(pygame.image.load(パス))
# アニメーション速度
animcycle = 24
frame = 0
clock = pygame.time.Clock()
while True:
screen.fill((255,255,255))
clock.tick(60)
# 経過フレーム数に応じて表示する画像を変える
frame += 1
player = playerImgList[int(frame/animcycle%4)]
screen.blit(player, (x*GS, y*GS),(0,0,GS,GS))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
animcycle = 24
ずっと24のままです。
frame += 1
数字が一つずつ増えていきます。
player = playerImgList[frame//animcycle%4)]
キャラクター画像はリストに入っている。
計算式でインデックスを決めている。
playerImgList[0]
playerImgList[1]
playerImgList[2]
playerImgList[3]
[frame//animcycle%4]の計算(分かりやすくしてみました)
a = 0//2%2 0割る2で0 0%2余り0
b = 1//2%2 1割る2で0.5(整数除算で小数点以下が切り捨てられ0)
0%2余り0
c = 2//2%2 2割る2で1 1%2余り1
d = 3//2%2 3割る2で1.5(整数除算で小数点以下が切り捨てられ1)
1%2余り1
e = 4//2%2 4割る2で2 2%2余り0
f = 5//2%2 5割る2で2.5(整数除算で小数点以下が切り捨てられ2)
2%2余り0
split_img
関数の説明
import pygame
def split_img(img, GS):
split_list = []
for i in range(0, 128, GS):
surface = pygame.Surface((GS, GS), pygame.SRCALPHA)
surface.blit(img, (0, 0), (i, 0, GS, GS))
split_list.append(surface)
return split_list
説明
### `split_img` 関数の説明
```python
def split_img(img, GS):
img
にはロードした画像が入ります。GS
はグリッドサイズ(ピクセル単位)を指定します。
split_list = []
空のリストです。ここに分割した画像を入れていきます。
for i in range(0, 128, GS):
繰り返し処理です。0~128の範囲で GS
間隔の数字を作ります(例: GS
が32の場合、0, 32, 64, 96)。
ただし、128は含まれません。range()で作られるのは指定した数未満までです。
surface = pygame.Surface((GS, GS), pygame.SRCALPHA)
透明なサーフェイスの生成です。
(サーフェイスとは、画像やテキストのことです)
((GS,GS))
サーフェイスのサイズです。GS
は32です。
pygame.SRCALPHA
サーフェイスを透明にします。
surface.blit(img, (0, 0), (i, 0, GS, GS))
サーフェイスに分割した画像を描画します。
-
img
: キャラクター画像です。 -
(0,0)
: 描画する座標です。サーフェイスと分割した画像は同じサイズなので、ぴったり合わさります。 -
(i,0,GS,GS)
:i
は横の座標です。range
関数で生成された 0, 32, 64, 96 が順に入ります。GS
は32なので 32x32 の大きさです。
split_list.append(surface)
透明なサーフェイスに分割したキャラクター画像を貼り付けて、できた画像をリストに追加します。
return split_list
繰り返し処理が終わり、4つの画像が入っているリストを返します。
向きを変えながら歩く
ここをクリックしてください
import pygame
from pygame.locals import *
import sys
def split_image(image):
"""32x128のキャラクターイメージを32x32の4枚のイメージに分割
分割したイメージを格納したリストを返す"""
imageList = []
for i in range(0, 128, GS):
for j in range(0, 128, GS):
surface = pygame.Surface((GS,GS))
surface.blit(image, (0,0), (j, i,GS,GS))
surface.set_colorkey(surface.get_at((0,0)), RLEACCEL)
surface.convert()
imageList.append(surface)
return imageList
pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption('walking')
x,y = 2,2
GS = 32
DOWN,LEFT,RIGHT,UP = 0,1,2,3
#ここキャラのパスを貼り付ける
playerImgList = split_image(pygame.image.load(パス)) # プレイヤーx,y = 1,1
direction = DOWN
animcycle = 24 # アニメーション速度
frame = 0
clock = pygame.time.Clock()
while True:
clock.tick(60)
screen.fill((255,255,255))
# 経過フレーム数に応じて表示する画像を変える
frame += 1
player = playerImgList[int(direction*4+frame/animcycle%4)]
screen.blit(player, (x*GS, y*GS))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type==KEYDOWN:
if event.key==K_DOWN:
direction = DOWN
y += 1
elif event.key==K_UP:
direction = UP
y -= 1
elif event.key==K_RIGHT:
direction = RIGHT
x += 1
elif event.key==K_LEFT:
direction = LEFT
x -= 1
def split_image(image):の説明
概要
キャラクター画像を16個に分割してリストに入れる。
補足
キャラクター画像の大きさは128x128
GSは32
def split_image(image):
imageはキャラクター画像。
imageList = []
空のリストを作る。
for i in range(0, 128, GS):
0から128の範囲でGS(32)間隔の数字を作る。
ただし、128は含まれません。range()で作られるのは指定した数未満までです。
0 32 64 96
for j in range(0, 128, GS):
0から128の範囲でGS(32)間隔の数字を作る。
ただし、128は含まれません。range()で作られるのは指定した数未満までです。
0 32 64 96
surface = pygame.Surface((GS,GS))
サーフェイスを作る。
たとえるなら、ペイントのキャンパスのようなもの。
色はデフォルトで、黒。
((GS,GS))は大きさ。
surface.blit(image, (0,0), (j, i,GS,GS))
作ったサーフェイスに画像の一部を貼り付ける。
imageはキャラクター画像。
(0,0)はサーフェイスの座標。
j,iはキャラクター画像の座標。
GS,GSは切り取る大きさ。
surface.set_colorkey(surface.get_at((0,0)), RLEACCEL)
.set_colorkeyは指定した色を透明にする。
.get_atは指定した座標の色を取得する。
ここでは(0,0)の色は黒なので黒がすべて透明になる。
ぼくは最初背景が白の画像を使っていたので、マントが透明になってました。
RLEACCELは描画を高速化する。
surface.convert()
サーフェイスを最適化する。
imageList.append(surface)
リストに追加する。
return imageList
結果を返します。
おまけ
set_alpha: サーフェス全体の透明度を設定します。透明度は0から255までの範囲で指定し、サーフェス全体が均一に透明になります。
set_colorkey: 特定の色を透明に設定します。サーフェス上の指定した色が透明になります。
スクロール
ここをクリックしてください
キャラクターの移動処理にはスクロールというものがあるのですが、ぼくは理解してないので紹介だけしておきます。
(aidiaryさんの記事です)
タイルスクロール
変更箇所(すべて変更済みのコードです)
pygame.quit()をつけてます。
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()#ここ
sys.exit()
()をつけたり、isを==に変えたりしてます。
def load_image(filename, colorkey=None):
filename = os.path.join("data", filename)
try:
image = pygame.image.load(filename)
except (pygame.error, message):#ここ
print ("Cannot load image:"), filename#ここ
raise (SystemExit, message)#ここ
image = image.convert()
if colorkey is not None:
if colorkey == -1:#ここ
colorkey = image.get_at((0,0))
image.set_colorkey(colorkey, RLEACCEL)
return image
int()をつけてます。
def draw(self, screen, offset):
"""マップを描画する"""
offsetx, offsety = offset
# マップの描画範囲を計算
startx = int(offsetx / GS)#ここ
endx = int(startx + SCR_RECT.width/GS + 1)#ここ
starty = int(offsety / GS)#ここ
endy = int(starty + SCR_RECT.height/GS + 1)#ここ
/ を // にします。
def update(self):
# キャラクターアニメーション(frameに応じて描画イメージを切り替える)
self.frame += 1
self.image = self.images[self.direction*4+self.frame//self.animcycle%4]#ここ
(aidiaryさんの記事です)
ピクセルスクロール
変更箇所。(変更済みのコードです)
/ を // にしてます。
# プレイヤーの移動処理
if self.moving == True:
# ピクセル移動中ならマスにきっちり収まるまで移動を続ける
self.rect.move_ip(self.vx, self.vy)
if self.rect.left % GS == 0 and self.rect.top % GS == 0: # マスにおさまったら移動完了
self.moving = False
self.x = self.rect.left // GS#ここ
self.y = self.rect.top // GS#ここ
これ以外はタイルベーススクロールと同じところを変更してください。
セーブとロード
ここをクリックしてください
Sキーを押すと、座標を保存します。別の場所に移動して、Lキーを押してみてください。座標を保存した場所に戻ります。
import pygame
from pygame.locals import *
import sys
import pickle
pygame.init()
screen = pygame.display.set_mode((160,160))
pygame.display.set_caption('save load')
x,y = 2,2
GS = 32
#ここにキャラクター画像のパスを貼り付ける
player = pygame.image.load(パス)
while (1):
screen.fill((0,0,0))
screen.blit(player, (x*GS, y*GS))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type==KEYDOWN:
if event.key==K_DOWN:
y += 1
elif event.key==K_UP:
y -= 1
elif event.key==K_RIGHT:
x += 1
elif event.key==K_LEFT:
x -= 1
elif event.key==K_s:
# ゲームの状態を辞書として定義
save_data = {
"x": x,"y": y
}
# ゲームの状態をファイルに保存
with open('save_data.pickle', 'wb') as file:
pickle.dump(save_data, file)
print("セーブしました")
elif event.key==K_l:
# セーブデータを読み込む
with open('save_data.pickle', 'rb') as file:
save_data = pickle.load(file)
x = save_data["x"]
y = save_data["y"]
print("ロードしました")
pickleファイルの中身を表示
セーブやロードで、エラーが起きた時に本当に保存されてるか確かめる必要があります。
ここをクリックしてください
import pickle
# データを読み込む関数
def load_pickle_data(file_path):
with open(file_path, 'rb') as file:
data = pickle.load(file)
return data
# 読み込んだデータを表示する関数
def display_data(data):
print("読み込んだデータ:")
print(data)
# 使用例
file_path = # 保存されたpickleファイルのパス
data = load_pickle_data(file_path)
display_data(data)