Arcadeは、Pythonを使って絵を描いたり、キャラクターを動かしたりして、 2Dゲームやアニメーションを作るためのライブラリです。Scratchで学んだ考え方をそのまま活かせるので、 Pythonを楽しく学び始めるのにぴったりです。
Scratchでは、ブロックパレットからブロック(プログラムの命令)を選び、 スクリプトエリアに並べます。ブロックを組み合わせることで、 スプライト(キャラクター)の動きやゲームの動作を作ることができます。
一方、Pythonでは、ブロックの代わりに文字や記号を使って命令を書きます。 このように、プログラムを書くための文字や記号の並びを「コード」と呼びます。 Scratchでブロックをつなげていくように、Pythonでは命令を表すコードを上から順番に書き並べて、 コンピューターにしてほしいことを伝えます。たとえば、キャラクターを動かしたいときは、「右に進む」 「10歩動く」といった動きを、Pythonの命令を使ってコードにします。
なを、このページは、Arcade Academy - Learn Python の「18. Using the Window Class」参照し、 実際にコードを動かして試しながら書いています。
Arcadeで2Dの絵を描くプログラムはPython Arcade「絵を描く方法」にも書きました。 次のコードでWindowを開いて絵を描きました。このプログラムでは幅640、高さ480のWindowを開いています。
import arcade arcade.open_window(640, 480, "描画サンプル") # Width x Height arcade.run()
これで、640×480ピクセルのゲーム画面を作ることができます。でも、画面ができただけでは、まだゲームにはなっていません。 ゲームを作るには、
など、たくさんの仕組みが必要です。 そこで、ArcadeのWindowをそのまま使うのではなく、ゲームに必要な機能を追加した、自分専用のWindowを作ります。 そのために使うのが、
class MyGame(arcade.Window):
という書き方です。 これは、Arcadeが用意したWindowを土台にして、自分のゲーム用のMyGameを作るという意味です。 このクラスは、「キャラクターを画面に表示する」などゲームを作る上で必要な機能を持っています。
__init__(self, width, height, title)は、 このクラスを作成した時に、一番最初に実行される関数です。 この中で、super().__init__(width, height, title)は親である arcade.Window の初期設定を実行しています。
import arcade
# MyGame クラスの定義 ---
class MyGame(arcade.Window):
def __init__(self, width, height, title):
# 親クラスの初期化関数をコールする
super().__init__(width, height, title)
# --- クラスの定義終わり
# MyGame を作成
mywindow = MyGame(640, 480, "MyGame Example")
arcade.run()
on_draw(self)は1秒間に約60回、定期的に呼ばれる関数です。 この関数で再描画してアニメーションを作成します。 この中でself.clear()で背景以外を全部消して、その上で draw_lrbt_rectangle_filledで Windowの下の4分の1を緑色に塗り、さらにボールを draw_circle_filledで描き加えています。この場合は ボールが毎回、同じ位置に描画されるので、描画が更新されても静止画になります。

import arcade
# MyGame クラスの定義 ---
class MyGame(arcade.Window):
def __init__(self, width, height, title):
# 親クラスの初期化関数をコールする
super().__init__(width, height, title)
# 背景色
arcade.set_background_color(arcade.color.SKY_BLUE)
# 1秒間に60回、この関数が呼び出され再描画します。
def on_draw(self):
self.clear() #全部消す
arcade.draw_lrbt_rectangle_filled(0, 640, 0, 240, arcade.csscolor.GREEN)
arcade.draw_circle_filled(50, 300, 15, arcade.color.AUBURN)
# --- クラスの定義終わり
# MyGame を作成
mywindow = MyGame(640, 480, "MyGame Example")
arcade.run()
ボールのX座標を self.ball_x = 0 と定義します。 on_update(self, delta_time) は1秒間に約60回、定期的に呼ばれる関数です。この暗数の中でこのX座標をアップデートします。 右端に到達したら、左端に戻すようにしています。
import arcade
# MyGame クラスの定義 ---
class MyGame(arcade.Window):
def __init__(self, width, height, title):
# 親クラスの初期化関数をコールする
super().__init__(width, height, title)
# 背景色
arcade.set_background_color(arcade.color.SKY_BLUE)
self.ball_x = 0
# 1秒間に60回、この関数が呼び出され再描画します。
def on_draw(self):
self.clear()
arcade.draw_lrbt_rectangle_filled(0, 640, 0, 120, arcade.csscolor.GREEN)
arcade.draw_circle_filled(50, 160, 15, arcade.color.AUBURN)
# 1秒間に60回、この関数が呼び出されます。
def on_update(self, delta_time):
self.ball_x += 2
if(self.ball_x>=640):
self.ball_x=0
# --- クラスの定義終わり
# MyGame を作成
mywindow = MyGame(640, 480, "MyGame Example")
arcade.run()Scratchのプログラムでは以下のようなプログラムです。 MyGameの場合は、ぶつかった壁が左右なのか、上下なのかで跳ね返った後の動きを変更しています。 左右の場合はX方向の動きを反転し、上下の場合はY方向の動きを反転しています。

Scratch での動き
MyGameでの動き
import arcade
import numpy as np
Angle = 45.*np.pi/180
# MyGame クラスの定義 ---
class MyGame(arcade.Window):
def __init__(self, width, height, title):
# 親クラスの初期化関数をコールする
super().__init__(width, height, title)
# 背景色
arcade.set_background_color(arcade.color.SKY_BLUE)
self.xinc = 4*np.cos(Angle)
self.yinc = 4*np.sin(Angle)
self.ball_x = 50
self.ball_y = 160
# 1秒間に60回、この関数が呼び出され再描画します。
def on_draw(self):
self.clear()
arcade.draw_lrbt_rectangle_filled(0, 640, 0, 120, arcade.csscolor.GREEN)
arcade.draw_circle_filled(self.ball_x, self.ball_y , 15, arcade.color.AUBURN)
# 1秒間に60回、この関数が呼び出されます。
def on_update(self, delta_time):
self.ball_x += self.xinc
self.ball_y += self.yinc
if(self.ball_x>=640): # 右の壁にぶつかった
self.xinc=-self.xinc
if(self.ball_x<=0): # 左の壁にぶつかった
self.xinc=-self.xinc
if(self.ball_y>=480): # 上の壁にぶつかった
self.yinc=-self.yinc
if(self.ball_y<=0): # 下の壁にぶつかった
self.yinc=-self.yinc
# --- クラスの定義終わり
# MyGame を作成
mywindow = MyGame(640, 480, "MyGame Example")
arcade.run()ボールをいくつも作って動かすために、ボールの設計図となる「ボールクラス」を作ります。 ボールクラスには、それぞれのボールが持っている情報として、位置、色、大きさ、X方向の移動量、Y方向の移動量などを用意します。 また、ボールの位置を計算する処理と、ボールを画面に描くための描画処理も用意します。 ゲームが進むとon_update()からupdate()が呼び出され、 ボールの位置を計算し直します。そして、画面を描くときにはon_draw()から描画処理draw()が呼び出されます。 このように、ボールに必要な「情報」と「動作」をひとまとめにしておくことで、同じボールをいくつでも作ることができます。
import arcade
import numpy as np
# ボールのクラスの定義 ---
class Ball(arcade.Window):
def __init__(self, xposs, yposs, bsize, bangle, bspeed, bcolor):
self.ball_x = xposs
self.ball_y = yposs
self.ball_size = bsize
self.xinc = bspeed*np.cos(bangle*np.pi/180)
self.yinc = bspeed*np.sin(bangle*np.pi/180)
self.color = bcolor
def updata(self,delta_time):
self.ball_x += self.xinc
self.ball_y += self.yinc
if(self.ball_x>=640): # 右の壁にぶつかった
self.xinc=-self.xinc
if(self.ball_x<=0): # 左の壁にぶつかった
self.xinc=-self.xinc
if(self.ball_y>=480): # 上の壁にぶつかった
self.yinc=-self.yinc
if(self.ball_y<=0): # 下の壁にぶつかった
self.yinc=-self.yinc
def draw(self):
arcade.draw_circle_filled(self.ball_x, self.ball_y , self.ball_size, self.color)
# --- クラスの定義終わり
# MyGame クラスの定義 ---
class MyGame(arcade.Window):
def __init__(self, width, height, title):
# 親クラスの初期化関数をコールする
super().__init__(width, height, title)
# 背景色
arcade.set_background_color(arcade.color.SKY_BLUE)
# ボールを創る
self.ballr = Ball(50, 150, 10, 43, 12, arcade.color.RED)
self.ballg = Ball(350, 360, 15, -42, 9, arcade.color.YELLOW)
self.ballb = Ball(250, 250, 20, 64, 6, arcade.color.BLUE)
# 1秒間に60回、この関数が呼び出され再描画します。
def on_draw(self):
self.clear()
arcade.draw_lrbt_rectangle_filled(0, 640, 0, 120, arcade.csscolor.GREEN)
self.ballr.draw()
self.ballg.draw()
self.ballb.draw()
# 1秒間に60回、この関数が呼び出されます。
def on_update(self, delta_time):
self.ballr.updata(delta_time)
self.ballg.updata(delta_time)
self.ballb.updata(delta_time)
# --- クラスの定義終わり
# MyGame を作成
mywindow = MyGame(640, 480, "MyGame Example")
arcade.run()