【初心者向け】KivyによるWindowsアプリ作成24 キータイプ時の文字消込処理の実装

今回は、前回追加したキータイプ受付処理を拡張し、タイプされたキーとゲーム画面に表示された文字が一致する場合に、画面上からその文字を消し込む処理を実装していきます。

コード全量については、GitHub上のファイルをご参照下さい。

<スポンサーリンク>

実装方針の整理

今回更新すべき範囲は多少広範に及ぶため、まずはどこをどのように更新するかを整理したいと思います。

①Targetインスタンスの保存

現状のプログラムでは、Targetインスタンスを生成することにより画面に文字を表示しています。しかしながら、このインスタンスを変数等に格納していないため、いざ、このインスタンスの消込を行うとしても、簡単にはインスタンスにアクセスすることができません

そこで、インスタンスを生成する都度、このインスタンスをリストに保存しておくようにし、そのリストを参照することでいつでもTargetインスタンスにアクセスできるようにします。

②Targetインスタンスへの行/列番号保存

画面上に表示されている文字がタイプされた際に、文字の消込を行うことに加え、その文字が表示されていたマス目に再び文字を表示できるよう、マス目毎に文字の有無を保存しているtargetExistリストの値をTrueからFalseに変更する必要があります。

このtargetExistリストの各要素へは、行番号と列番号の組み合わせでアクセスすることができます。

一方、文字毎の位置情報は、現状、Targetインスタンスに暗黙的に含まれているposという変数の中に格納されていますが、このposの値は行番号と列番号ではなく、横座標と縦座標です。そのため、targetExistリストへアクセスしようと思ったときに、わざわざposの座標データから行/列番号を再計算する必要があります。

そこで、Targetインスタンスにposだけではなく、行/列番号を持たせることにより、これを用いてtargetExistリストへ簡単にアクセスできるようにします。

③正解タイプ時の処理実装

最後に、画面に表示された文字がタイプされた際に行うべき、文字の消込等の必要な処理を実装します。

実装

①Targetインスタンスの保存

まず、GameScreenクラスの頭に、Targetインスタンスを格納するリストを定義しておきます。

class GameScreen(Screen):
    targets = [] #この行を追加

    def start(self):
#省略

さらに、GameScreenクラスのupdateメソッドの最後に、Targetインスタンス生成の都度、このリストにそれを格納するための行を追加しましょう。

def update(self, dt):
#省略
        self.add_widget(target)
        self.targetExist[y][x] = True
        self.targets.append(target) #この行を追加

リストへの要素追加は、「リスト名.append(追加する要素)」という記述で行うことができます。

これで、Targetインスタンス生成の都度、それがtargetsというリストに格納されるようになりました。

②Targetインスタンスへの行/列番号保存

次にTargetクラスを修正し、行/列番号を保持できるようにしておきます。現時点でTargetクラス内には「pass」とだけ記述されていると思いますが、これを以下のように置き換えます。

class Target(Button):
    posX = 0
    posY = 0

posXという列番号(横(x方向)から数えて何番目のマスか)を保持する変数と、posYという行番号(縦(y方向)から数えて、何番目のマスか)を保持する変数を用意し、それを初期化しています。

このままでも先に進むことはできるのですが、折角ですので、インスタンス生成時に行/列番号を引数として指定できるようにし、それをこれら変数を格納するような初期化処理を実装しましょう。

class Target(Button):
    def __init__(self, posX, posY):
        super().__init__()
        self.posX = posX
        self.posY = posY

まず、2行目で「__init__」というメソッドを定義しています。このメソッド内容の説明の前に、クラスからインスタンスを生成する際のPython内部の処理について、簡単に説明します。

あるクラスからインスタンスを生成する際、そのクラスに定義されている「__init__」という名称のメソッドが暗黙的に呼び出され、メソッド内に含まれている初期化処理が行われます

一方、これまで記事ではクラス定義の際、この名称のメソッドを全く定義していませんでした。その場合は、親クラスに定義されている「__init__」メソッドが暗黙的に呼び出され、ベースとなる初期化処理が行われます。

ここで、やりたいことは、以下の2点です。

  • Targetクラスからインスタンスを生成する際、親クラスに定義された「__init__」メソッドを実行して、ベースとなる初期化処理を行う
  • 加えて、行/列番号をインスタンス生成時の引数として指定できるようにし、追加の初期化処理として、それを用意した変数に格納するようにする

これを実装するためには、Targetクラス内に独自に「__init__」メソッドを定義し、その中に、上記2つの処理を記述してやれば良いことになります。

では、これらを踏まえて、コードの中身を改めて見てみましょう。

まず、2行目の「__init__」メソッドの引数として、selfの他に、posX、posYという2つを指定しています。これらは、インスタンス生成時にインプットとする、それぞれ、列番号と行番号です。

続く3行目ですが、「super().親クラスのメソッド」という記述で、親クラスに定義されたメソッドを呼び出すことができます。ここでは、親クラスの「__init__」メソッドを呼び出しています。

さらに4、5行目がTargetクラス独自の初期化処理ですが、インスタンス生成時に受け取った行/列番号(posXとposY)を、インスタンス内の変数(self.posXとself.posY)に代入しています。

これで、インスタンス生成時に、Targetインスタンスに行/列番号を持たせることが可能になりました。

あとはTargetインスタンス生成時に、行/列番号を引数として指定するようにするだけです。

GameScreenクラス内のupdateメソッドを、以下のように修正しょう。

def update(self, dt):
    indexList = []
    for j in range(7):
#省略
                y, x = choice(indexList)

    target = Target(x, y) #この行を修正
    target.pos = (x * 75 + 26, y * 75 + 1)
#省略

update内の変数、xとyにはそれぞれ文字を表示するマス目の列番号と行番号が入っていますが、それをTargetへ渡すことにより、先ほどの「__init__」にメソッドによるposXとposYの初期化が行われます。

③正解タイプ時の処理実装

最後に、画面に表示されている文字と一致するキータイプが行われた際に行われるべき処理を実装しましょう。

「行われるべき処理」とは、具体的に以下の3点です。

  • 画面から文字を消す
  • targetExistの対応する要素の値をTrueからFalseにする
  • targetsリストから、対応するTargetインスタンスを消す

この3点を、前回作成したkeyboardDownメソッド内に記述してやります。前回、確認用にprint関数を4行書いていましたが、不要ですので削除してしまって下さい。

def keyboardDown(self, keyboard, keycode, text, modifiers):
    for target in self.targets:
        if target.text == text:
            self.remove_widget(target)
            self.targetExist[target.posY][target.posX] = False
            self.targets.remove(target)

2行目のfor文は、targetsリストに格納されているTargetインスタンスを、このforループ内だけで使えるtarget変数に1つずつ格納して、以降の処理を順に実施していくことを表しています。

3行目のif文では、ゲーム画面に表示されている文字であるTargetインスタンスのtext属性(target.text)と、キーボードからタイプされた文字(text)が一致していれば、以降の処理を実施することを意味しています。もし一致しない場合はforループ先頭に戻り、次のTargetインスタンスに対して同じ処理を繰り返します。

4~6行目が、正解タイプ時の処理です。

4行目では、GameScreenインスタンスの「remove_widgget」というメソッドを使って、該当するTargetインスタンスを表示対象から削除しています。

第20回で紹介した、add_widgetとは全く逆の動作ですね。第20回のadd_widgetの説明も改めてご覧頂くと、理解が深まるかと思います。

それでは今回からゲーム画面の実装に入り、ゲーム内容を作り込んでいきたいと思います。 今回はまずゲーム画面の設計を簡単に行った上で、後半...

次に5行目ではtargetExistリストの該当する要素の値を、TrueからFalseに戻しています。これで、対応するマス目に再び文字が表示可能になります。

最後の6行目では、リストの「remove」というメソッドを使って、targetsリストからTargetインスタンスを削除しています。これは②の全く逆の操作ですね。

実行

それでは、ここまでのプログラム更新が終わりましたら、実際にゲームを開始し、キーをタイプしてみましょう。

画面に表示された文字をクリックすると、その文字が消えるはずです。

また、正解タイプ後にしばらく画面を放置してみて、一度文字が表示されたマス目であっても、文字が再表示されることも、確認してみて下さい。

終わりに

今回、キータイプにより文字を消去する処理を実装することにより、少しゲームらしさが増したのではないでしょうか。

次回はよりゲームらしさをより高めるために、正解タイプ時にスコアを増加させる処理を実装していきたいと思います。

<スポンサーリンク>

シェアする

フォローする