Python

【Pythonista3】PythonでiOSゲーム開発#1[ゲーム開発①]

2020年3月11日

ゲーム開発では、部品として''シーン''と''ノード''の2種類を配置して作ります。

  • シーンはゲーム画面のベースとなる部品でUI部品の中のViewのことです。
  • ノードはシーンに組み込んで表示するオブジェクト部品のことです。

ゲーム部分の開発では''.pyui''ファイルは使わずに全てスクリプトに書いていきます。

ゲーム開発

オブジェクトを動かす

▼シーンにスプライトを追加してupdate関数によりスプライトの位置を変化させています。

▼スクリプトの全体です。関数の詳細は以下に記載します。

Scene継承クラス:Sceneクラスを継承したクラスのインスタンスを変数とし、run(SceneInstance())としてシーンを表示することができます。

from scene import *
class SampleScene(Scene):
    #背景色の設定
    self.background_color = '#88ffff'

run(SampleScene())

シーンにスプライトを追加する:スプライトはSpriteNodeクラスのインスタンスとして生成し、Add_childでシーンに追加することができます。

def setup(self): #スプライトの生成
    self.sprite = SpriteNode('emj:Alien_Monster') #スプライトの位置設定
    self.sprite.position = self.size / 2 #スプライトをシーンに追加する
    self.add_child(self.sprite)

スプライトを動かす:update関数では毎秒60回実行され位置を更新しています。

#移動距離の設定
dx = 10
dy = 10
 
def update(self):
    position = self.sprite.position
    position.x += self.dx
    position.y += self.dy
 
    if position.x <= 0:
        self.dx = 10
 
    if position.x >= self.size.w:
        self.dx = -10
 
    if position.y <= 0:
        self.dy = 10
 
    if position.y >= self.size.h:
        self.dy = -10
 
    self.sprite.position = position

既存のスプライトデータの使用方法

▼スクリプトの右下の+マークをタップします。

▼Image,Sound,Color,Fontの既存データを使用することができ、選択するとコピーペーストされます。

オブジェクトを変化させてタップした位置に移動させる

▼画面をタップしたところに回転・拡大縮小・透明化しながら移動させる。

▼スクリプトの全体です。関数の詳細は以下に記載します。

タッチしたときに呼び出される関数:タップの動作によって呼び出される関数は3種類あります。

touch_began

タッチしたときに1度だけ呼び出される。

touch_moved

ドラッグ中に繰り返し呼び出される。

touch_ended

タップし話したときに1度だけ呼び出される。

タッチ後のアクション関数:アクションには回転・拡大縮小・フェードイン/アウトに加えて、エフェクト(モード)を設定することができます。

  • 指定の時間で動かす

Action.move_to(x座標, y座標, 時間, モード)

Action.move_by(x座標, y座標, 時間, モード)

  • ノードの回転

Action.rotate_to(角度, 時間, モード)

Action.rotate_by(角度, 時間, モード)

  • ノードの拡大縮小

Action.scale_to(倍率, 時間, モード)

Action.scale_by(倍率, 時間, モード)

Action.scale_x_to(x軸倍率, 時間, モード)

Action.scale_y_to(y軸倍率, 時間, モード)

  • ノードのフェードイン/アウト

Action.fade_to(アルファ値, 時間, モード)

Action.fade_by(アルファ値, 時間, モード)

  • モードの種類
TIMING_LINEAR

直線的に等速で移動

TIMING_EASE_IN

開始時になめらかに加速

TIMING_EASE_OUT

終了時になめらかに減速

TIMING_EASE_IN_OUT開始時になめらかに加速し、終了時になめらかに減速
TIMING_SINODIAL

TIMING_LINEARとTIMING_EASE_IN_OUTの間(加速減速が弱い)

TIMING_EASE_BACK_IN

開始時に1度戻ってから進む
TIMING_EASE_BACK_OUT

終了時に1度越してから戻る

TIMING_EASE_BACK_IN_OUT

開始時に1度戻ってから進み、終了時に1度越してから戻る

TIMING_ELASTIC_IN

開始時に輪ゴムで打ち出されるような効果

TIMING_ELASTIC_OUT

終了時に輪ゴムで打ち出されるような効果

TIMING_ELASTIC_IN_OUT

開始/終了時時に輪ゴムで打ち出されるような効果

TIMING_BOUNCE_IN

開始時にバウンドするような効果

TIMING_BOUNCE_OUT

終了時にバウンドするような効果

TIMING_BOUNCE_IN_OUT

開始/終了時にバウンドするような効果

複数のActionを行う場合

Action.repeat(<Action>, 回数)Actionを指定の回数分だけ行う動作
Action.group(<Action>, <Action>, ...)複数のActionを1つのActionとしてグループ化する動作
Action.sequence(<Action>, <Action>, ...)複数のActionを順に実行する動作

タップ時の動作:スプライトに動作を加えるときには、sprite.run_action(<Action>)とする。

def touch_began(self, touch):
    p = touch.location #直線移動 
    act1 = Action.move_to(p.x, p.y, 3.0, TIMING_LINEAR) #回転  
    act2 = Action.rotate_by(4 * pi, 3.0, TIMING_LINEAR) #フェードイン/アウト 
    act3 = Action.fade_to(0.5, 0.5, TIMING_LINEAR) 
    act4 = Action.fade_to(1.0, 0.5, TIMING_LINEAR) #拡大縮小  
    act5 = Action.scale_to(2, 0.5, TIMING_LINEAR)
    act6 = Action.scale_to(1, 0.5, TIMING_LINEAR) #フェードイン/アウトを順に実行する
    act_s = Action.sequence(act3, act4) #拡大縮小を順に実行する 
    act_s2 = Action.sequence(act5, act6) #act_sを3回繰り返す 
    act_rp = Action.repeat(act_s, 3) #act_s2を3回繰り返す  
    act_rp2 = Action.repeat(act_s2, 3) #act1,act2,act_rp,act_rp2をグループ化する  
    act_g = Action.group(act1, act2, act_rp, act_rp2)
    self.sp.run_action(act_g) 

タップしたオブジェクトを生成・削除する

▼何もないところをタップするとスプライトが生成され、スプライトをタップするとスプライトが削除される。

▼スクリプトの全体です。関数の詳細は以下に記載します。

▼複数のスプライトを生成させるのでスプライトのクラスを作っておきます。スプライトはタッチされると削除という動作があるのでタッチされたかどうかを真偽する関数を作っておきます。タッチされた位置とスプライトの位置の差が13(スプライトの大きさ)である場合に真を返します。

class SampleSprite(SpriteNode):
    def __init__(self, img):
        super().__init__(img)
        self.d = Point(0, 0)

    def is_touched(self, pt):
        p = self.point_from_scene(pt)
        return -13 < p.x < 13 and -13 < p.y < 13

▼タッチされた際にスプライトを生成する関数です。各スプライトには初めにランダムで変数dとして速度ベクトルを設定しておきます。

def create_sprite(self, p):
    sp = SampleSprite('emj:Alien_Monster')
    sp.position = p 
    d = Point(random.randint(-3, 3), random.randint(-3, 3))
    sp.d = d 
    fo = Action.fade_to(0.0, 0.0)
    sp.run_action(fo) 
    fi = Action.fade_to(1.0, 1.0, TIMING_LINEAR)
    act = Action.sequence(fo, fi)
    sp.run_action(act)
    self.add_child(sp)

▼複数のスプライトをランダムに移動させています。シーンにあるスプライトはchildrenという変数に格納されているので、そこからスプライトを取り出します。各スプライトに対して現在位置に速度ベクトル分を加えて更新します。

def update(self):
    for sp in self.children:
      sp.position += sp.d
      if sp.position.x <= 0 or sp.position.x >= self.size.width:
         sp.d.x *= -1
      if sp.position.y <= 0 or sp.position.y >= self.size.height:
         sp.d.y *= -1

▼画面をタッチした際に動作する関数です。各スプライトに対して、タッチされた場合にはスプライトの削除関数(remove_from_parent)を呼び出します。一つもなかった場合にはスプライトが生成されます

def touch_began(self, touch):
    for sp in self.children:
        if sp.is_touched(touch.location):
            fo = Action.fade_to(0.0, 1.0, TIMING_LINEAR)
            rm = Action.call(sp.remove_from_parent)
            act = Action.sequence(fo, rm)
            sp.run_action(act)
            return 
    self.create_sprite(touch.location)

まとめ

今回はゲーム開発というよりスプライトの動かし方を書いただけになってしまいました。

次回はゲームのようなプログラムを作っていこうと思います。

合わせて読みたい

よく読まれている記事

1

DeepFaceLab 2.0とは DeepFaceLab 2.0は機械学習を利用して動画の顔を入れ替えるツールです。 以前にDeepFaceLab 1.0を記事としてアップしていましたが、2.0は以 ...

2

自作PCで、多くのパーツをCorsair製品で揃えたので、iCUEでライティング制御していきました。 私のPCでは、表示されている4つのパーツが制御されています。ここで、HX750i電源ユニットは、L ...

3

コンピュータは有限桁の数値しか扱う事はできないので、桁数の多い場合や無限小数の場合は四捨五入され切り捨てられます。なので実際の数値とは多少の誤差が生じますが、これを丸め誤差といいます。 なので、コンピ ...

-Python