FIT2-2024b 第07回 ミニプロサンプル解説 + 実習
アナウンス再掲
中間発表・最終発表あります
12/18(水)、01/22(水)の2日
どうしても参加できない方はお申し出ください
今週からはひたすら最終成果物の開発
講師、SAを捕まえて進めるのが吉
今日のゴール
ミニプロに向けて、「クラス」を最低1つ完成させる
画面に登場する主要な要素 (プレイヤー、ボール等) を Classに定義する
update, draw関数を実装し、実際に画面上で動作するようにする
企画書の分布
ブロック崩し 4 → ボールキャッチゲームの延長で実現可能
横スクロールアクション 3
縦スクロールアクション 3
シューティングゲーム 2
対戦ゲーム 1
固定画面アクション (キーボード操作) 6
固定画面アクション (マウス操作) 1
パズルゲーム 3
共通項として以下を解説します
主キャラクターをキーボード/マウス操作で動かす
サンプルコードは開示しますが、「開示したサンプルコードからの差分」のみ採点対象のためコンセプトに留めます
基本の骨組み
code:python
import pyxel
pyxel.init(200, 200)
def update():
pass
def draw():
pyxel.cls(7)
pyxel.run(update, draw)
応用編は以下
code:python
import pyxel
class App:
def __init__(self):
pyxel.init(200, 200)
pyxel.run(self.update, self.draw)
def update(self):
pass
def draw():
pyxel.cls(7)
App()
クラスの考え方が大事
1. 登場するモノを考え、名前をつける => class Player:
2. 登場するものが持つべき値を考える => def __init__(self): self.x self.y 等
3. Playerに関わる「動詞」を考える => 動く def move() 描画される def draw() 攻撃する def attack()
3で定義した「動詞」を def update(): 内で組み合わせていく
def draw(): は全変数を描画するだけでいい
俯瞰:プレイヤーを上下左右キーで動かす
code:python
import pyxel
class Player:
def __init__(self):
self.x = 100
self.y = 100
self.width = 10
self.height = 10
def move(self):
if pyxel.btn(pyxel.KEY_UP):
self.y = self.y - 10
if pyxel.btn(pyxel.KEY_DOWN):
self.y = self.y + 10
if pyxel.btn(pyxel.KEY_LEFT):
self.x = self.x - 10
if pyxel.btn(pyxel.KEY_RIGHT):
self.x = self.x + 10
def draw(self):
pyxel.rect(self.x - self.width / 2, self.y - self.height / 2, self.width, self.height, 0)
pyxel.init(200, 200)
player = Player()
def update():
global player
player.move()
def draw():
global player
pyxel.cls(7)
player.draw()
pyxel.run(update, draw)
step2. : プレイヤーが攻撃する
code:python
import pyxel
class Player:
def __init__(self):
self.x = 100
self.y = 100
self.width = 10
self.height = 10
def move(self):
if pyxel.btn(pyxel.KEY_UP):
self.y = self.y - 10
if pyxel.btn(pyxel.KEY_DOWN):
self.y = self.y + 10
if pyxel.btn(pyxel.KEY_LEFT):
self.x = self.x - 10
if pyxel.btn(pyxel.KEY_RIGHT):
self.x = self.x + 10
def draw(self):
pyxel.rect(self.x - self.width / 2, self.y - self.height / 2, self.width, self.height, 0)
def attack(self):
return FireBall(self.x, self.y)
class FireBall:
def __init__(self, x, y):
self.x = x
self.y = y
def move(self):
pass
def draw(self):
pyxel.circ(self.x, self.y, 5, 3)
pyxel.init(200, 200)
player = Player()
fireballs = []
def update():
global player
player.move()
if pyxel.btnp(pyxel.KEY_SPACE):
fireballs.append(player.attack())
for fireball in fireballs:
fireball.move()
def draw():
global player
pyxel.cls(7)
player.draw()
for fireball in fireballs:
fireball.draw()
pyxel.run(update, draw)
横スクロールアクション:jump_gameの解説
code:python
import random
import pyxel
class Player:
def __init__(self):
self.x = 72
self.y = -16
self.vy = 0
self.isAlive = True
def update(self):
if pyxel.btn(pyxel.KEY_LEFT):
# max = 与えられた値のうち大きい方の値を採用する
self.x = max(self.x - 2, 0)
if pyxel.btn(pyxel.KEY_RIGHT):
# min = 与えられた値のうち小さい方の値を採用する
self.x = min(self.x + 2, pyxel.width - 5)
self.y += self.vy
# min = 与えられた値のうち小さい方の値を採用する
self.vy = min(self.vy + 1, 8)
if self.y > pyxel.height:
if self.isAlive:
self.isAlive = False
if self.y > 600:
self.x = 72
self.y = -16
self.vy = 0
self.isAlive = True
return False # playerが死亡してゲームをリセットする際にのみFalseを返す
return True
def draw(self):
pyxel.rect(self.x, self.y, 5, 15, 0)
class Floor:
def __init__(self, x):
self.x = x
self.y = random.randint(8, 104)
self.isActive = True
def update(self, player):
addScore = 0
if self.isActive:
if (
player.x + 16 >= self.x
and player.x <= self.x + 40
and player.y + 16 >= self.y
and player.y <= self.y + 8
and player.vy > 0
):
self.isActive = False
player.vy = -12
addScore = 10
else:
self.y += 6
self.x -= 4
if self.x < -40:
self.x += 240
self.y = random.randint(8, 104)
self.isActive = True
return addScore
def draw(self):
pyxel.rect(self.x, self.y, 40, 5, 4)
class Fruit:
def __init__(self, x):
self.x = x
self.y = random.randint(0, 104)
self.kind = random.randint(0, 2)
self.isActive = True
def update(self, player):
addScore = 0
# abs = 絶対値、-12ならば12になる
if self.isActive and abs(self.x - player.x) < 12 and abs(self.y - player.y) < 12:
self.isActive = False
# min = 与えられた値のうち小さい方の値を採用する
player.vy = min(player.vy, -8)
addScore = (self.kind + 1) * 100
self.x -= 2
if self.x < -40:
self.x += 240
self.y = random.randint(0, 104)
self.kind = random.randint(0, 2)
self.isActive = True
return addScore
def draw(self):
if self.isActive:
if self.kind == 0:
pyxel.circ(self.x, self.y, 3, 8)
elif self.kind == 1:
pyxel.circ(self.x, self.y, 3, 10)
elif self.kind == 2:
pyxel.circ(self.x, self.y, 3, 11)
pyxel.init(160, 120)
score = 0
player = Player()
floors = []
fruits = []
for i in range(4):
floors.append(Floor(i * 60))
fruits.append(Fruit(i * 60))
def update():
global score, player, floors, fruits
if pyxel.btnp(pyxel.KEY_Q):
pyxel.quit()
if not player.update():
# ゲームをリセットする
score = 0
for floor in floors:
score += floor.update(player)
for fruit in fruits:
score += fruit.update(player)
def draw():
global score, player, floors, fruits
pyxel.cls(12)
for floor in floors:
floor.draw()
# draw fruits
for fruit in fruits:
fruit.draw()
player.draw()
# draw score
pyxel.text(5, 4, str(score), 1)
pyxel.text(4, 4, str(score), 7)
pyxel.run(update, draw)