CocosCreator2.0で廃止(Deprecated)されたもの。cc.random0To1は廃止

CocosCreator 1.xではccモジュールにrandom0To1関数などがあり、標準のMath.randomをラップした関数が複数ありましたが、CocosCreator2.0では廃止されました。

廃止されるものの確認方法ですが、ブラウザーの開発者ツール(デバッグツール)を起動して、アプリを実行すると削除した関数のエラーと、廃止予定の関数を使っていたら警告が表示されます。

CocosCreatorのコンソールには、警告表示等が表示されないので、ブラウザーからでないとこれに気づけません。

Edgeの開発者ツールで、廃止関数を確認したところ

https://github.com/cocos-creator/engine/blob/next/cocos2d/deprecated.js

TypeScriptのcreator.d.tsファイルには、すでにcc.random0To1がないため、コード入力時にエラー検知できます。

CocosCreatorの公式チュートリアルを試してわかったこと

CocosCreatorの公式チュートリアル「Quick Start:Make your first game」を1日やってみた感想です。大まかには以下のような感じでした。

  • Unityの仕組み(GameObject,Componentなど)でCocosCreatorは使える。
  • Unityユーザーはすぐにできるが、Cocos2d-xユーザーにとっては使いづらい。
  • Cocos2d-xとは別物
  • コード編集してフォーカスをCocosCreatorに戻すと、ブラウザーリロードで開発が楽(JavaScriptのlivereload)
  • ドキュメントを期待する前にまずはサンプルプロジェクトを起動

作ったゲームの簡単な説明

このゲームは、紫スライムがプレイヤーで、ADキーで左右に移動してスターを取るゲームです。スターは一定時間で消えるので、消えたらゲームオーバーです。

スターが消えるまでに取るエンドレスゲーム。消えたらゲームオーバー

Unityの仕組み(GameObject,Componentなど)でCocosCreatorは使える。

CocosCreatorはUnityの考え方を土台にして作られているのでいくつか共通な概念を確認します。

HierarchyWindowに対応するNodeTree

UnityではGameObjectに画像、音声、スクリプトなどをコンポーネントとして追加する構造です。CocosCreatorでは、Nodeという言葉を使いますが構造は同じでした。

操作もUnityと同じで、アセットからシーンウィンドウに画像をドロップしてSpriteNodeを作れます。

UnityのHierarchyWindowに対応するNodeTreeがあり、そこで右クリックすると、EmptyNodeやSpriteNodeが作れます。これはUnityでいうEmptyGameObjectやSpriteRendererコンポーネントと同じです。

InspectorWindowに対応するPropertiesウィンドウ

以下は、紫スライムのPlayerNodeのプロパティーです。これはUnityのGameObjectのInspectorWindowと同じで、「Add Component」ボタンでコライダーや、Physicsをコンポーネントとして追加できるのも全く同じです。

Unityのスクリプト変数がインスペクターに反映されるのとCocosCreatorは同じ

Unityでは変数がインスペクターに反映されます。この仕組みがあるのでC#スクリプトにパブリックフィールドを用意してUnityエディターで値を調整できます。CocosCreatorも同じで、スクリプトを作成するとひな型にpropertiesオブジェクトがあるので、ここにプロパティを書いていきます。

UnityユーザーからするとC#と記述は違いますが、やりたいことは一致しているので問題なく書いていけますが、Cocos2d-xユーザーは、この概念を新しく学ぶ必要があって面倒かもしれません。

Playerスクリプトに4つプロパティを書いたところ

Playerノードに上記Playerスクリプトを「Add Component」ボタンで追加すると以下のようにPlayerスクリプトがコンポーネントとして追加され、プロパティが表示されます。Unityと全く同じです。

Unity同様PlayerスクリプトのプロパティがGUIで編集できるようになっている

Prefabもある

Unityでは現在のシーンでオブジェクトに画像や音声、スクリプトをコンポーネントとして追加し、ProjectウィンドウにドラッグするとPrefab化できます。CocosCreatorでは、NodeTreeウィンドウからAssetsウィンドウにドラッグするとPrefab化できます。

いままで見てきたように、CocosCreatorはUnityを参考に作られているのが分かります。

Unityユーザーはすぐにできるが、Cocos2d-xユーザーにとっては使いづらい?

いくつか機能を比較してきましたがCocosCreatorは、Unityの概念を参考に作られています。そのためCocos2d-xのようなソースコード主体の開発ではなく、オーサリングツールやGUIデザイナーがある開発ツールと同様な開発手法が求められます。音声、画像など各種リソースの設定や配置は、ソースコードで書かれずにツールで設定するようになります。

今までのCocos2d-xと同じだろうと思ってやってみると名前だけが同じなので、全然別物のためUnityユーザーが始めるよりもCocos2d-xユーザーの方が大変かもしれません。

コード編集してフォーカスをCocosCreatorに戻すと、ブラウザーリロードでするので開発が楽(JavaScriptのlivereload)

HTML+JavaScript+CSSでWebアプリを開発している感覚で、オートリロードでゲームを再確認できます。かなり軽いためこれは非常に良かったです。

またブラウザーゲームの場合そのままブラウザーの機能を使えるので、例えば音声認識APIなどと連動する場合は、相性が良いと思います。

ドキュメントを期待する前にまずはサンプルプロジェクトを起動

Unityのような感覚でドキュメントや参考となるプロジェクトを見つけることはできません。また日本語のドキュメントを探すのも難しいです。ですが、DashboardにExample Collectionがあり、これはいろんな機能をシーンで分けて一覧化したプロジェクトです。なのでまずは起動してみるとよいです。簡単なゲームを作る際に必要な情報は手に入ります。

少々強引なJavaScript

JavaScriptはC#やJavaと異なり、動的型付けなので、以下のような記述はできません。

ソースコード上のプロパティとGUIのインスペクターを連動するために、以下のようにJavaScriptのオブジェクトにtypeプロパティでcc.Prefabのように型を設定して対応しています。

またTypeScriptでプログラミングする場合は、注釈があるため2行ですっきり書けます。class構造もすっきりして入力補完も完全対応なので慣れるとこちらのほうが開発しやすそうです。

まとめ

CocosCreatorとUnityの似ているところをUIやソースコードで確認してみました。

CocosCreatorは動作が軽く、Phaserなどコードベースのライブラリーと比較するとシーン管理、画像やテキストの配置や音声ファイルの設定などがドラッグアンドドロップでできるため、ソースコードが少なくなります。

またJavaScriptのためブラウザー機能と連携する場合は、ブラウザーの機能(音声認識APIなど)を単純に呼び出すだけでよいのでこれも相性が良いです。

ブラウザーゲームとして公開する場合は、瞬時にCanvas起動するのでこれはUnityより良いです。

此処までいくつかメリットを書きましたが、まとめるとWebブラウザーベースのちょっとしたゲームを素早く作りたい。UnityのWebGLのロードが待てない。リソース管理をコードベースで書きたくない。などの理由がある場合はよいツールと感じました。

Unityは、とにかく入門情報が、英語でも日本語でも動画でもgithubのソースコードでも豊富です。初心者向けの入門書もたくさんあり問題が発生しても誰かが解決策をブログで書いていたりします。良いツールですが、広く使ってもらうのは難しいのかもしれません。

Windows10でCocos2d-xのsetup

Cocos2d-xはPython2.7系のセットアップツールがあるので、setup.pyを実行すると環境変数を設定してくれます。

 

 

プロジェクト作成、カレントディレクトリーにMyGameディレクトリーが作成される。

 

MyGame\proj.win32\MyGame.sln が用意されるのでこれで開発できます。Cocos2d-xはソースコードとして含まれるので、初回ビルド時は、Cocos2d-Xをビルドするので数分かかります。VisualStudio2017問題なくビルドできました。

カレントディレクトリーの複数ターゲットに対応したNASMのMakefile

.asmファイルが増えるたびにMakefileに、helloworld: helloworld.oなどのように書いていたので書きかたを調べてみました。

  • wildcard *.asmをすべての.asmファイルを取得
  • 変数展開で*.asmファイルを*.oファイルに変換しOBJECTS変数に保持
  • ターゲットファイル名を同様に変数展開でTARGETSに保持

あとは、11行目と13行目を用意することで、複数のターゲットに対応してasmファイルをビルドできるようになりました。

NASMで簡単なコードを書く場合、C言語の逆アセンブリーでサンプルを用意する

NASMを始めたばかりだと、すこしのコードを書くのにも時間が掛かります。sum関数やfactorial関数など、ちょっとした関数やいくつか複合した条件分岐などを作る場合は、まずC言語で実装してそれを逆アセンブルして、コードを入手するのもよい案かもしれません。

gccで逆アセンブル

-fverbose-asmを追加すると、引数や戻り値のヒントがコメントとして表示されます。もっとコードと比較しながら確認したい場合は、gdbを使ったほうがよいです。

objdumpで逆アセンブル

factorial.sの抜粋

以下がgccで逆アセンブルした結果です。コメントで<retval>と引数nが確認できます。またn * factorial(n-1)の部分をimul命令(imul eax, ebx)で行っています。ここまでくればあとは、このコードを解析していけば、自分でNASMのfactorialを作る子tができます。

 

 

 

 

 

スタックフレームの確認

簡単なC言語を逆アセンブルするとx64の場合、push rbpから始まります。これはスタックフレームを理解すれば、この意味が分かります。

「スタックセグメントを確認してみる」が初心者にわかりやすいx64版のgdbを使ったスタックフレームの確認方法です。

NASMを見ると関数呼び出しで、必ずpush rbp, mov rbp, rspと書かれているがこれはスタックフレームを新しく用意して、引数やローカル変数をこの後に保持します。また最後にleave命令で、mov esp, ebp; pop ebpとして、呼び出し元関数のスタックフレームを復元します。

 

 

leave命令の意味

スタックフレームを戻す2つのmov,popを1回で行う命令

lea命令

アドレス計算して転送する命令(Load Effective Address)

nasm x64でprintfを呼び出す

PIC対応でNASM x64でprintfを呼び出す

-no-pieオプションでPIC対応にしない場合

call printfでよい。

gccのオプション-no-pieを付ける

 

 

 

 

nasm x64のWRT ..plt

nasmのチュートリアル(http://cs.lmu.edu/~ray/notes/nasmtutorial/ )で、C言語のputs関数を呼び出す簡単なプログラムを作りましたが、gccでオブジェクトファイルから実行ファイルを作るときに以下エラーが発生しました。

https://www.nasm.us/xdoc/2.10rc8/html/nasmdoc9.html#section-9.2.5

NASMから外部関数を呼び出す場合は、PLT(procedure linkage table)を使わなければいけないようです。以下のようにWRT ..pltを付けて解決しました。

これでオブジェクトファイルを作成しgccでリンケージして実行できました。

 

Python初心者講座 60行でタイピングゲームを作ろう!

はじめに

Pygameで60行ぐらいでタイピングゲームを作ります。以下が完成したときのソースコードです。このぐらいの量なら初心者でも行けると思います。この記事は、各見出しごとに、機能を追加し、解説、ソースコードと実行結果を載せています。機能を追加した時点のちゃんと動くソースコードを載せているので、もし自分で書いて動かない場合は比較して参考にしてください。

それでははじめていきましょう。

 

※Pygameはpipでインストールしておいてください

タイピングゲームの基本動作を確認

  1. 単語帳からランダムに単語を選ぶ
  2. キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除
  3. 単語が空かチェックして、空なら1に戻る

上に書いたように、タイピングゲームの基本動作は単純です。まずは赤文字の部分を作ってしまいます。

単語帳からランダムに単語を選ぶ

select_wordを追加したソースコード

解説

単語(word)、選ぶ(select)で、select_word関数を作ります。

単語帳(word_list)を配列で作ります。

len()関数は、配列の中身の数が分かるので、len(word_list)で、個数を求めます。上記の例では5個です。

random.randintでランダムな数を求めます。random.randint(0, 5)なら、0,1,2,3,4,5のどれかが取得できます。word_listは、中身が5個あって、配列は以下のように0から4で取得できます。word_list[5]とするとエラーになってしまうので、random.randint(0, num_of_elements – 1)のように-1します。

最後に、0から4のどれかがiに保持できたので、return word_list[i]で、呼び出し元に、選んだ単語を返します。

実行

スクリプトの最後に3つテストを書いているので実行したら、実行毎にランダムな単語が3つ表示されます。

単語の先頭文字を削除

解説

Pythonはスライス機能があるので、文字列[開始インデックス:終了インデックス] で文字列から一部分を取得できます。開始インデックス、終了インデックスは省略もできます。例えば”abcde”[1:]と書いたら、1番目の文字以降の文字列”bcde”を取得できます。配列のインデックスと同じで、ゼロ始まりなので、aは0番目の文字、bは1番目の文字です。

cust_head_charを追加したソースコード

実行

テスト2でpple, anana,herryのように、先頭文字を削除できているのがわかります。

単語が空かチェック

Pythonではnot演算子で、空””かどうかチェックできます。not演算子は、文字列が”abcde”のようにある場合は、Falseを返します。空””の場合はTrueを返します。

is_empty_wordを追加したソースコード

実行

テスト3の最後のテストが、Trueになっているのが分かります。

ここまでの作業のまとめ

  1. 単語帳からランダムに単語を選ぶ
  2. キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除
  3. 単語が空かチェックして、空なら1に戻る

ここまでで3つの関数を作りました。残りは画面に単語を表示して、キー入力に対応するだけです。残り20行ぐらい。

画面を用意して塗る(fill,フィル)

いきなりいろんな作業をすると、分からなくなるので、まずは720×480の画面を作って背景を塗りつぶします。うまくいってから、文字列表示やキー入力を実装していきます。

解説

run_game関数を作ってそれを実行することで、ゲーム画面を表示します。

pygame.init()でゲームライブラリーを初期化します。

pygame.display.set_mode((720, 480))で、720×480の画面用意しscreen変数に保持します。今後はここに単語を表示させます。

screen.fill((200, 200, 200))で、淡いグレーでscreenを塗ります。

pygame.display.update()で、実際に画面が更新されます。

イベントについて

「閉じるボタンを押した」「キー入力」「マウスクリック」「マウス移動」「ウィンドウ最大化」などはすべてイベントとして扱います。何か発生するたびに、pygame.event.get()でイベントを取得して処理できるようにします。ちょうどfor文のとこです。

まずはpygame.QUITイベントに対応します。「閉じるボタンを押した」ときにこのpygame.QUITイベントが発生します。発生したときはsys.exit()でアプリを終了します。これを書かないとアプリが終了できなくなるので必ず必要です。

また、今回pygameとsysパッケージを使ったのでimport文も追加します。

ここまでのソースコード

実行

画面を灰色で塗る

単語を表示

ペイントソフトをイメージすると分かりやすいです。ペイントソフトで文字列を書く場合、フォントを用意して、文字列を書いて、それをpngなど画像ファイルとして書き出します。pygameの場合以下のようになります。

  1. フォントを用意 pygame.font.SysFont
  2. 文字列を書く font.render
  3. 書き出し screen.blit

解説

文字列を表示するためには、まずフォントを用意します。今回はNoneを指定し初期フォントを使います。

word = select_word()で、ランダムに選んだ単語を1つ用意して、それをrenderで書きます。

screen.blitで画面に書きだします。

ここまでのソースコード

実行

単語が表示できた!

キー入力と単語の先頭文字が同じなら、単語の先頭文字を削除

解説

キーが押されたら、pygame.KEYDOWNイベントが発生します。この時の入力されたキーはevent.keyで取れます。これはアスキーコードという数値なのでchr(event.key)で文字にします。そして、chr(event.eky) == word[0]で、単語の先頭文字と比較します。

もし同じなら、最初に作ったcut_head_char関数で、単語の先頭文字を削除します。

ここまでのソースコード

これで、キー入力して単語の先頭文字が同じ場合には削除されます。

単語が空かチェックして、空なら新たな単語を用意する

解説

単語が空かチェックするis_empty_word関数をあらかじめ用意していたので、空なら、word = select_word()で新たな単語を用意します。

解説:文字のセンタリング

文字列の左上頂点を求める

スクリーンサイズの半分から、文字列の幅の半分を引くとセンタリングするための文字列の左上頂点が求められます。図で理解するとよいです。

ここまでのソースコード

今回、以前書いたテストのprint文も削除しました。

実行

センタリングして、タイピングできるようになった

まとめ

60行ぐらいでタイピングソフトができました。これをどんどん改造していこう!フォントサイズ変更、色変更をした後に、スコア表示などができると思います。需要があれば、改造のしかたも書こうと思います。

カウントダウンタイマーはちょっと面倒でget_ticksを使います。以下は60秒のタイマーです。60行後、start_ticks = pygame.time.get_ticks()を呼び出してリセットする必要があります。

 

 

Python3+Tkinterでタイピングゲームを作ってみました。

 

https://github.com/dev001hajipro/typing-game-py

JavaScriptでタイピングソフトの基本部分を作ったので、Python+Tkinterに移植してみました。130行ぐらいで、タイマー、スコア表示、タイピングが実装できました。まだゲーム終了とリトライ機能、音声はありませんが、初心者には参考になると思います。またPython+Tkinter課題がいくつか見えてきました。

TkinterはUI更新はメインスレッドで行う

最初、タイマー機能を実現するために、ワーカースレッドを用意して、そのスレッドでUI更新をしようとしましたが、例外が発生しました。ワーカースレッドでは、データ更新を行い、Tk.after関数で定期的にUIリフレッシュをする機能を別途設けて対応しました。

Tkinterに音声再生はない

Pythonで音声再生をする場合は、PyAudioなどを使う方法がありますが面倒そうです。

Pythonではglobalに状態変数を持ち、それを関数で呼び出す場合コードが汚くなっていく。

Pythonはグローバル変数を関数のスコープで使う場合、globalキーワードを使います。とりあえずグローバル変数を使うと、コードが汚くなるのが分かりました。状態保持用のクラスを作成するなどをしたほうがよさそうです。

ゲームライブラリーを使ったほうが良い

ゲームエンジン、ライブラリーは、入力支援、音声再生、スプライト表示などが簡単に書けるので、PyGame、PySDL2、Godot3 Engineを検討したほうがよいと感じました。