Pythonista3 Advent Calendar 2022 の7日目の記事を書き始めるワイ
ワイ「まずは書き出しのテンプレからやな、、、」カタカタ、、、
この記事は、Pythonista3 Advent Calendar 2022 の07日目の記事です。
一方的な偏った目線で、Pythonista3 を紹介していきます。
ほぼ毎日iPhone(Pythonista3)で、コーディングをしている者です。よろしくお願いします。
以下、私の2022年12月時点の環境です。
--- SYSTEM INFORMATION ---
* Pythonista 3.3 (330025), Default interpreter 3.6.1
* iOS 16.0.2, model iPhone12,1, resolution (portrait) 828.0 x 1792.0 @ 2.0
他の環境(iPad や端末の種類、iOS のバージョン違い)では、意図としない挙動(エラーになる)なる場合もあります。ご了承ください。
ちなみに、model iPhone12,1
は、iPhone11 です。
ワイ「これでええな!」ッターン
ワイ「さてと、、、」
ワイ「scene
モジュールを紹介すると言っても、何をどう紹介したらええんやろか、、、」
ワイ「どうしたの?ネタ切れなのかな?」
ワイ「ネネネ、ネタ切れちゃうわ!!」
ワイ「書きたいことはたくさんあるけど、書く速度と時間が全く釣り合ってないんや!」
ワイ「じゃあ、大好きなShader をやればいいんだよ?」
ワイ「それば、次回の予定や!そもそも前回も、ui
モジュールでニッチにdraw
メソッドでクリエイティブコーディングをメインお届けしてしまったんや!」
ワイ「少ないPythonista3 読者層の中で隙間産業すなよ!」
ワイ「Shader はあくまで、scene
モジュールの副産物みたいなもんやろ」
ワイ「そうですわねぇ、SpriteKit Framework がベースですものねぇ」
SpriteKit | Apple Developer Documentation
ワイ「不要な情報を増やすなや、、、」
ワイ「そういったことは、objc_util
のときにまとめて説明しようと思ってたんや、、、」
ワイ「ワンチャン、Pythonista3 をはじめようと読んでくれてた人が、混乱するやろ、、、」
ワイ「ごめんなさいだよ?(たぶんAPI の説明を前にしてたんだよ?)」
ワイ「紹介する順番をそれなりに考慮して進めてるんやから水差さんようにお願いしますやで」
充実のチュートリアル
ワイ「とにかく、scene
モジュールは、Pythonista3 の中でもコードサンプルが多いんや」
ワイ「しかも、細かくパート分けされてたり、順を追って機能追加をしていったりと手厚くサポートされているなと思うで」
Game Tutorial
ワイ「サンプルコードがたくさん入っているExamples
にも、Examples/Game Tutorial
にpart7 まで用意されてるんや!」
ワイ「Tutorial Part 1.py
なんて、実装コードよりもコメント解説の方が多いんやで」
ワイ「フォントがUbuntu Mono
で、Size はPythonista3 最小の8
でやっと全体像がギリギリ見えるくらいや」
ワイ「すごいね!壮観なのだね?」
ワイ「ゲームで使えるイラストなんかもPythonista3 に準備されてるんやで」
ワイ「キーボードの右上にある(+)
をタップするとアイコンや画像、サウンドを簡単に選べるんや」
ワイ「ゲームつくる前に、材集めのためのサイト巡りが不要になるで!!」
ワイ「いたせりつくせりなんだね?」
ワイ「英語に抵抗あるなら、前に紹介した翻訳スクリプトを使えば少し楽になるやで」
Pythonista3 内だけで、英語を日本語に機械翻訳 | Pythonista3 のeditor module を使い、Pythonista3 のコーディングを楽にする - Qiita
scene
モジュールのDocumentation
ワイ「Documentation の充実っぷりも最高やで、特にintroduction は、適宜かいつまんでサンプルが用意されているんや」
introduction | scene — 2D Games and Animations — Python 3.6.1 documentation
ワイ「[Open in Editor]
でサンプルをひとつづつ挙動を確認すれば、scene
モジュールの雰囲気が掴めるで」
ワイ「サンプルから、自分が思い描く改造チャレンジをしてみるのもええと思うで」
それにしても
ワイ「コードの内容にも触れずに、ただただPythonista3 にある事実を伝えているだけやんけ。。。」
ワイ「ui
モジュールだと、add_subview
がadd_child
になっていたり、混同しないように気をつけるんやでー!しか伝えることがなさそうやで。。。」
ワイ「。。。」
ワイ「過去の完成してない、リポジトリの紹介しか道はないのかもしれんな。。。。」
ワイ「改めてコードをみてみると、意味不明なところやペンディングなところもあるから、いろいろ修正したいンゴ」
ワイ「だけど、そんなことしたら、時間が全然足りない。。。」
ワイ「納期という確定完成が存在しない、趣味プログラミングの悲しき性かもしれんな」
ワイ「そもそも、ゲームも下手だし。ゲーム作りたい。ってモチベーションもさほど持ってない系男子なんや、、、」
ワイ「もう前置きの言い訳は、いいからはやく紹介をするんだよ?」
ワイ「わかりましたやで、、、」
エアーホッケーゲーム
ワイ「昔のiPhone から引っ張り出してきたやで、、、」
ワイ「2人プレイのエアーホッケーゲームやな」
ワイ「2019年の4月頃にぽちぽち作ってたみたいやで」
テストプレイ
ワイ「点数が入ると自エリアがピカピカする」
ワイ「パドルは自エリアしか移動できひんようになってるな」
ワイ「ボールがガクガクしとるのは、衝突判定がガバってる証拠やな」
ワイ「まあ必殺技みたいでカッコええからヨシ!やで」
ワイ「ヨシ!じゃないんだよ?しっかり修正をしてほしいんだよ?」
実装
ワイ「これは、コードを見返して気がついたんじゃなく、記憶が蘇ってきただけなんやが」
ワイ「パドルやゴールを個別に判断させたくて、ゴニョゴニョしてたのを思い出したわ」
ワイ「super
で呼んでるところかな?継承の概念はないのかな?」
class Oval_obj(scene.ShapeNode):
def __init__(self, _x, _y, wh, player, color, parent=None):
p_path = ui.Path.oval(0, 0, wh, wh)
super(Oval_obj, self).__init__(
p_path, position=(_x, _y), fill_color=str(color), parent=parent)
self.touch = None
self.player = player
class Field(scene.Node):
def __init__(self, parent=None):
super(Field, self).__init__(parent=parent)
def setup(self):
r_path = ui.Path.rect(0, 0, x, y_cent)
self.play1 = scene.ShapeNode(r_path, 'pink')
self.play1.position = (x_cent, y_cent / 2)
self.play2 = scene.ShapeNode(r_path, 'cyan')
self.play2.position = (x_cent, y_cent + y_cent / 2)
ワイ「参考にしたコードがこんな感じだったのかも知れんな、もうその辺は覚えてないわ」
ワイ「2つのものを捜査させて無駄感が半端ないねん」
def update(self):
self.ball.update()
if self.ball.position[1] > y - self.ball.size[0] / 2:
if self.goal1.position[0] - goal_var / 2 <= self.ball.position[0] < self.goal1.position[0] + goal_var / 2:
#print('赤に加点')
self.p1_points += 1
self.field.p1_action()
self.scr_p1.text = str(self.p1_points)
if self.ball.position[1] < self.ball.size[0] / 2:
if self.goal2.position[0] - goal_var / 2 <= self.ball.position[0] < self.goal1.position[0] + goal_var / 2:
#print('青に加点')
self.p2_points += 1
self.field.p2_action()
self.scr_p2.text = str(self.p2_points)
ワイ「class 名や、変数名も適当すぎるんだよ?」
ワイ「命名関係と、2プレイヤーとしての処理を書き換える。衝突判定をしっかり書く。とかの書き直しが必要そうなコードやな」
ワイ「実装時の記憶じゃなくて、コードから意図を読み取れる書き方を目指したいやで」
テトリス目コピ
ワイ「これは、Pythonista3 で実装するネタ探しの時に『なんかネタくださいな』と相談したときに『テトリスでも作れば?』と言われたんや」
ワイ「色々な言語で実装されてそうだったから、そんな情報を一切遮断したるでーと、Wikipedia と当時公式で出てたアプリを見るだけで作ってみたやつやね」
pome-ta/tetrisPysta: Pythonista3 (ios app) use scene module
テストプレイ
ワイ「ブロックが着地する。もしくは、壁にぶつかると、画面が揺れるエフェクトをつけてる」
ワイ「当時、触覚フィードバックを知らんかったから、視認てきなフィードバックを実装したんやね」
ワイ「テトリスが下手すぎてキャプチャ撮るのに時間かかってしもうたわ」
実装面
ワイ「今回の記事用に、試しにプレイしてみたんやけど、低確率でエラー出てしまうんよ」
ワイ「コードがスパゲッティ過ぎて、深追いできず諦めましたや」
ワイ「あと、下ボタン長押し処理を実装せずに終えてるみたいやな」
ワイ「ぽちぽち、下ボタン連打するんがホンマめんどくさいわ」
ワイ「いまは、なんとなくどう処理すればいいかイメージはつくな」
ワイ「ボタン周りだと、ボタン一つ一つをMainScene
に個別で配置しとるから、ガバッとレイアウトの移動調節できへんのが面倒やな」
# --- btn start
path = ui.Path.oval(0, 0, 72, 72)
self.d_btn = scene.ShapeNode(path=path, parent=self, fill_color='white')
self.d_btn.position = self.size * .5
self.d_btn.position -= (0, self.size[1] / 2 - self.d_btn.size[1] / 2)
self.l_btn = scene.ShapeNode(path=path, parent=self, fill_color='red')
self.l_btn.position = self.size * .5
self.l_btn.position -= (+(self.l_btn.size[0]),
self.size[1] / 2 - self.l_btn.size[1])
self.r_btn = scene.ShapeNode(path=path, parent=self, fill_color='blue')
self.r_btn.position = self.size * .5
self.r_btn.position -= (-(self.r_btn.size[0] * 1),
self.size[1] / 2 - self.r_btn.size[1])
self.e_btn = scene.ShapeNode(path=path, parent=self, fill_color='yellow')
self.e_btn.position = self.size * .5
self.e_btn.position -= (0, self.size[1] / 2 - self.e_btn.size[1] * 1.5)
self.s_btn = scene.ShapeNode(parent=self, fill_color='pink')
self.s_btn.path = ui.Path.oval(0, 0, 32, 32)
self.s_btn.position = self.size * .5
self.s_btn.position -= (self.s_btn.size[0] - self.size[0] / 2,
self.size[1] / 3)
# --- btn end
ワイ「地獄かな?」
ワイ「当時は、iPhone6 plus だったから良かったかもしらんが、画面レイアウトの柔軟性に欠けとる」
ワイ「ブロックの回転は、もっとスマートならないのかな?」
class SetUpMinos:
def __init__(self):
i_rotate = ([[-1, 0], [0, 0], [1, 0], [2, 0]], [[1, -2], [1, -1], [1, 0],
[1, 1]],
[[-1, -1], [0, -1], [1, -1], [2, -1]], [[0, -2], [0, -1],
[0, 0], [0, 1]])
mino_i = {'name': 'i', 'color': 'cyan', 'rotate': i_rotate}
o_rotate = ([[0, 0], [0, 1], [1, 0], [1, 1]])
mino_o = {'name': 'o', 'color': 'yellow', 'rotate': o_rotate}
s_rotate = ([[-1, 0], [0, 0], [0, 1], [1, 1]], [[0, 1], [0, 0], [1, 0],
[1, -1]],
[[-1, -1], [0, -1], [0, 0], [1, 0]], [[-1, 1], [-1, 0], [0, 0],
[0, -1]])
mino_s = {'name': 's', 'color': 'green', 'rotate': s_rotate}
z_rotate = ([[0, 1], [1, 1], [1, 0], [2, 0]], [[1, 0], [1, 1], [2, 2],
[2, 1]],
[[0, 2], [1, 2], [1, 1], [2, 1]], [[0, 0], [0, 1], [1, 2],
[1, 1]])
mino_z = {'name': 'z', 'color': 'red', 'rotate': z_rotate}
j_rotate = ([[0, 0], [1, 0], [2, 0], [0, 1]], [[1, 1], [1, 0], [2, 1],
[1, -1]],
[[0, 0], [1, 0], [2, -1], [2, 0]], [[1, 1], [1, 0], [0, -1],
[1, -1]])
mino_j = {'name': 'j', 'color': 'blue', 'rotate': j_rotate}
l_rotate = ([[0, 0], [1, 0], [2, 0], [2, 1]], [[1, 1], [1, 0], [2, -1],
[1, -1]],
[[0, 0], [1, 0], [0, -1], [2, 0]], [[1, 1], [1, 0], [1, -1],
[0, 1]])
mino_l = {'name': 'l', 'color': 'orange', 'rotate': l_rotate}
t_rotate = ([[0, 0], [1, 0], [2, 0], [1, 1]], [[1, -1], [1, 0], [2, 0],
[1, 1]],
[[1, -1], [1, 0], [2, 0], [0, 0]], [[1, -1], [1, 0], [1, 1],
[0, 0]])
mino_t = {'name': 't', 'color': 'purple', 'rotate': t_rotate}
self.mino_list = [mino_i, mino_o, mino_s, mino_z, mino_j, mino_l, mino_t]
ワイ「せやな、結局答え合わせ的に、他のテトリスのコードと見合わせてないねん」
ワイ「独自実装過ぎて、他のコードを読むの諦めた記憶があるわ」
ワイ「壁付近のブロック回転は、公式テトリスから動きをキャプチャして、その通りに動くように調整した記憶も出てきたわ」
ワイ「写真アルバムのテトリスキャプチャ汚染すごそうなんだよ?」
過去のコード
ワイ「なかなか、ガバガバでヘビーやったな、、、」
ワイ「一つのファイルで完結させるのをやめたらいいんだよ?」
ワイ「それは、モジュール設計が下手くそというのが本音。表向きは、試してみたい人が1ファイルの方がハードル低く参入できる意図があるんやで」
ワイ「本音と建前の説明順番が逆なんだよ?」
ワイ「frame_interval
に依存して、ゲーム速度が変化してしまうのもよくないんだよ?」
ワイ「最近だと120Hz の端末もあるんよね。ゲーム内時間を管理するのを入れんとあかんなぁ」
ワイ「ちょいちょい、過去のを引っ張り出してリファクタリングするのも、勉強になるかもなぁ」
ワイ「とりあえず酷くてもいいから、GitHub にあげてさらし首にすれば、意識してコード書くようになるかもな」
ワイ「つまりGitHub にあるコードは、意識してコード書いてるんだよ?」
ワイ「もうええわ、やめさせてもらうわ」
結局scene
モジュールの紹介はどうすんねや?
ワイ「っは!?」
ワイ「夢ならよかったのに、、、」omz
ワイ「はやくscene
モジュールでのShader 遊びをしたいやで、、、」
ワイ、俺「皆さんここまで、読んでいただきありがとうございました!」
ワイ「って、なんで俺くんが!?
改めまして、ありがとうございました!」
本当の本当に終わり
せんでん
Discord
Pythonista3 の日本語コミュニティーがあります。みなさん優しくて、わからないところも親身に教えてくれるのでこの機会に覗いてみてください。
書籍
iPhone/iPad でプログラミングする最強の本。
その他
- サンプルコード
Pythonista3 Advent Calendar 2022 でのコードをまとめているリポジトリがあります。
コードのエラーや変なところや改善点など。ご指摘やPR お待ちしておりますー
なんしかガチャガチャしていますが、お気兼ねなくお声がけくださいませー
やれるか、やれないか。ではなく、やるんだけども、紹介説明することは尽きないと思うけど、締め切り守れるか?って話よ!(クズ)
— pome-ta (@pome_ta93) November 4, 2022
Pythonista3 Advent Calendar 2022 https://t.co/JKUxA525Pt #Qiita
- GitHub
基本的にGitHub にコードをあげているので、何にハマって何を実装しているのか観測できると思います。