ページ

2015年3月25日水曜日

【#TechBuzz】第11回cocos2d-x勉強会 参加レポート

3/24(火)にCocos2d-xの勉強会に参加したので、簡単にレポートします。


cocos2d-consoleでパッケージ管理(@giginet




Cocos2d-x 3.4 でcocosコンソールに追加されたパッケージマネージャのお話。

ライブラリのインストールや管理を簡単に行えるパッケージマネージャ機能はすごく便利そう!

と思いきや…、

現時点ではドキュメントもなく、パッケージもまだ3つしか登録されていない。

さらに、パッケージを登録する方法も用意されていないようです。

というわけで、今はまだ利用できそうにないですね。。。

これからに期待です。

cocos2d-xで『LWF』を利用する(@albatrus_jp



第11回 cocos2d-x勉強会 「cocos2dxでLWFを利用する」 from Naoki Yokota

Flashで作られたswfファイルをlwfという形式に変換して、HTML5やUnity、Cocos2d-xで利用できるようにしてくれるフレームワークLWFについての発表。

導入自体はそんなに難しくないが、位置調整などで苦労されたとのこと。

確かにこれを使うと表現の幅が広がりそうです。

ただ、私が個人で作るようなゲームで果たして出番があるかどうか…。

swfファイルを作るにもAdobeの有料ツールが必要になるので、ちょっと試してみるにしても、今の自分にはちょっと敷居が高いかも。

ネットワーキングタイム


やはりゲームを作っているという人が多く参加しており、自分が今実装面で困っていることについて個人的に教えて貰うことが出来た。

また、個人でCocos2d-xを使い趣味でアプリをリリースされている方ともお話出来て、なんだか自分もやれそうな気になりました。

2015年3月22日日曜日

PythonでGmailを送る

PythonでGmailを送るツールを作ろうと思い、色々調べたのでメモ。

Gmailに限らず、標準パッケージを使った基本的なメール送信手順は以下の通りです。

  1. emailパッケージを使ってMIME文書を作成
  2. smtplibを使って送信

ここで、MIMEってなんだっけ?となったので、合わせて調べてました。

MIMEとは


Multipurpose Internet Mail Extension(多目的インターネットメール拡張)の略。

当初、Eメールの文字コードは英数字といくつかの記号を表現する7bitの「US-ASCII」しか利用できず、英語以外の文章やテキスト以外のデータの送受信ができませんでした。

そこで新たなヘッダ情報を追加し、「US-ASCII」以外のデータも扱えるようにした規格がMIME。

MIMEにより追加されるヘッダは以下の通りです。

  • MIME-Version:MIMEであることを示すヘッダ。現在は1.0のみ利用される。
  • Content-Type:メッセージ中のデータタイプの指定。text、imageなど。
  • Content-Transfer-Encoding:データの符号化方法の指定。7bit、base64など。

Gmailの場合


GmailのWebクライアントで文章のみのメールを送り、ソースを見たところMIMEのヘッダは以下のように設定されていました。

MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: base64

ソースコード


上記を踏まえたコードを書いてみます。Pythonは3.4.2です。

from email.mime.text import MIMEText
from email.header import Header
from email.utils import formatdate
from smtplib import SMTP_SSL


def create_message(from_addr, to_addrs, subject, body, encoding='utf-8'):
    msg = MIMEText(body, 'plain', encoding)
    msg['Subject'] = Header(subject, encoding)
    msg['From'] = from_addr
    msg['To'] = ','.join(to_addrs)
    msg['Date'] = formatdate(localtime=True)
    return msg


def send_via_gmail(from_addr, to_addrs, password, msg):
    s = SMTP_SSL('smtp.gmail.com', 465)
    s.login(from_addr, password)
    s.sendmail(from_addr, to_addrs, msg.as_string())
    s.close()


if __name__ == '__main__':
    from_addr = 'spam@gmail.com'
    to_addrs = ['egg1@gmail.com', 'egg2@gmail.com']
    subject = 'test subject'
    body = 'test body'
    password = 'password'

    msg = create_message(from_addr, to_addrs, subject, body)
    send_via_gmail(from_addr, to_addrs, password, msg)

MIMETextでencoding='utf-8'を指定すると、Content-Transfer-Encodingもbase64に設定されます。

また、 formatdateはデフォルトではUTCで生成されてしまいます。
localtime=Trueを指定することで、現地時間(日本の場合はUTC+9)になります。

参考

2015年3月17日火曜日

Cocos2d-xにおけるメモリ管理方法


Cocos2d-xでのメモリ管理方法について、自分の理解を整理するためにメモ。

執筆時のバージョン


Cocos2d-x v3.4.2

参照カウント


Cocos2d-xではメモリ管理の方法として、参照カウント方式を採用しています。

参照カウントはガベージコレクション戦略の1つで、その概要は以下の通りです。

  • オブジェクトに対して、参照カウントと呼ばれる整数値を付加しておく。
  • オブジェクトに対する参照がどこかに保存されたら参照カウントをインクリメントし、オブジェクトに対する参照が削除されたらデクリメントする。
  • 参照カウントがゼロになったら、オブジェクトへの最後の参照が削除されたことになり、オブジェクトを破棄する。

Refクラス


これをCocos2d-xではRefクラスに実装しており、Nodeクラスなどほとんどのクラスの基底クラスになっているようです。

Refクラスのメンバは以下の通り。


Public Member Functions


void retain () 参照カウンタを+1。
void release () 参照カウンタを-1。0になったらオブジェクトは破棄される。
Ref * autorelease () オブジェクトをAutoreleasePoolに登録。自動的に破棄されるようになる。
unsigned int getReferenceCount () const 参照カウンタを取得。
virtual ~Ref () デストラクタ。


Protected Member Functions


Ref () コンストラクタ。参照カウンタを1で初期化する。


Protected Attributes


unsigned int _referenceCount 参照カウンタ。


参照カウンタ_referenceCountを、retain()とrelease()で操作します。

AutoreleasePool


私はiOSアプリの開発経験はないのですが、iOS SDKではNSAutoreleasePoolが参照カウント方式のメカニズムをラップしているらしいです。

これをCocos2d-xでもAutoreleasePoolとしてクローンしています。

代わりにstd::shared_ptrを使おうと試みたりもしたそうですが、パフォーマンスの問題で断念したとのこと。

AutoreleasePoolの仕組みはこうです。

  1. object->autorelease()を呼び出した時、このオブジェクトはAutoReleasePoolに登録される。
  2. AutoReleasePoolはこのオブジェクトのライフサイクルを現在のフレームの終了まで保持する。
  3. 現在のフレーム(スタックフレームのこと?)の終了時に、このオブジェクトが他のクラスやコンテナに保持されていなければ、自動的に破棄する。

例えば、layer->addChild(sprite)とすると、spriteはlayerの子リストに追加されます。

この場合、spriteのライフサイクルは現在のフレームの終わりではなく、layerが破棄されるまでとなります。

create関数


RefクラスのAPIを見れば分かるように、Refクラスのコンストラクタはprotectedであるため直接newすることはできません。

ではどうするのかというと、代わりにcreateおよびcreateから始まるスタティックなメンバ関数が用意されています。

この関数の処理の概要は以下の通りです。

  • 新しくインスタンスを生成する。
  • 必要な初期化を行う。
  • autorelease()を呼び出す。
  • 生成したインスタンスへのポインタを返却する。

create関数を使うことで、忘れずにautorelease()を呼び出し、AutoReleasePoolに登録するわけですね。

試しに1つ実装を見てみます。

以下は、Nodeクラスのcreat関数の実装です。

Node * Node::create()
{
    Node * ret = new (std::nothrow) Node();
    if (ret && ret->init())
    {
        ret->autorelease();
    }
    else
    {
        CC_SAFE_DELETE(ret);
    }
    return ret;
}

LayerやSpriteなど、既存のクラスを継承して独自のクラスを定義するとき、create関数にあたるものを作ることになりますが、その場合はCREATE_FUNCが用意されているので、引数が不要な場合はこれを使います。

引数が必要な場合も、既存のcreateを参考にすれば良さそうです。

まとめ

  • cocos2d-xではメモリ管理は参照カウント方式。
  • Refクラスがそのためのクラス。多くのクラスの基底クラスになっている。
  • retain()とrelease()を使ってリファレンスカウントの管理を行う。
  • release()を忘れずに行うために、AutoReleasePoolを使う。
  • AutoReleasePoolにオブジェクトを登録すると、スタックフレームの終了時に自動で解放してくれる。
  • AutoReleasePoolへの登録は、autorelease()を呼び出すことで行う。
  • autorelease()はcreate関数の中で呼び出される。
  • cocos2d-xのオブジェクトを生成するときはcreate関数を使う。

2015年3月15日日曜日

生のポインタを扱うときの注意点(C++)

最近、Cocos2d-x v3.x を触っており、主にこの本で勉強しています。

cocos2d-xではじめるスマートフォンゲーム開発 [cocos2d-x Ver.3対応] for iOS/Android
三木 康暉
技術評論社
売り上げランキング: 49,182

ただ、当然C++の知識は必要になるわけで。

C++は以前に少し使っていたことがあるのですが、期間が短かったためもはや忘却の彼方…。

Cocos2d-xにはメモリ管理の方法が用意されているようなのですが、

それについて理解するために、まずは通常のメモリ管理についておさらいしたのでメモ。

生のポインタを扱うときは、メモリの管理に気をつけないと以下の様な問題が発生します。

メモリリーク(memory leak)


プログラムが確保したメモリの一部、または全部を解放するのを忘れ、確保したままになってしまうこと。

Object *obj = new Object();
obj = nullptr;

上記の例では、実体のアドレスを参照する方法がなくなり、メモリが解放できません。

ダングリング・ポインタ(dangling pointer)


プログラムの実行中にポインタが不正なメモリ領域を指している状態。

ポインタが宙ぶらりんな状態(dangling)であることから、ダングリング・ポインタと呼ばれます。

Object *obj = new Object();
delete obj;
obj->someMethod();

上記の例では、解放した領域を参照してしまっています。

Object *obj = new Object();
delete obj;
delete obj;

上記の例では、一度解放した領域をもう一度解放しようとしています。

まとめ


これらの問題を防ぐには、以下を徹底する必要があります。

  • 確保したメモリが不要になったらdeleteする
  • 解放したメモリを参照している変数にnullptrを設定する

こういったことを忘れずに行えるように、C++11ではstd::shared_ptrなどを使うのだと思いますが、それについてはまたそのうち調べよう。

参考


2015年3月14日土曜日

閏年の計算方法について

calendar.pyのコードを読んでいて、閏年の判定について、どのように計算するのかわかっていなかったため調べました。

ところが調べ始めると、そもそも暦とはなんぞやという所から気になってしまったため、せっかくなのでそれも調べてみました。

簡単に自分の理解をメモします。

まず暦(こよみ)とは、時間の流れを年・月・週・日といった単位に当てはめて数えるよう体系付けたもののことです。

暦の作成方法には幾つかあり、大きく分けると以下の3種類があります。

  • 太陽暦
  • 太陰太陽暦
  • 太陰暦

それぞれの基準は「太陽」、「太陽と月の併用」、「月」です。

(ちなみに、日本では明治5年まで太陰太陽暦が使用されていたようです)

太陽暦の場合、「地球が太陽の周りを回る周期」を基に暦が作られており、その周期は365.24219日です。

小数点以下を切り捨てて、1年を365日としているわけですね。

1年で約0.25日分を切り捨てているため、4年たつと約1日分少なくなり、時間の経過と共にどんどん暦と季節にズレが生じてしまいます。

そこで、このズレを修正するために閏日として余分な1日を暦に追加する必要があります。

しかし、太陽暦にもいくつかの歴法があり、歴法によってこの閏年の計算方法が異なります。

ユリウス暦

  1. 西暦年が4で割り切れる年

グレゴリオ暦

  1. 西暦年が4で割り切れる年は閏年
  2. ただし、西暦年が100で割り切れる年は平年
  3. ただし、西暦年が400で割り切れる年は閏年

修正ユリウス暦

  1. 西暦年が4で割り切れる年は閏年
  2. ただし、西暦年が100で割り切れる年は平年
  3. ただし、西暦年を900で割った余りが200または600になる年は閏年

(西暦2800年にグレゴリオ暦と修正ユリウスにズレが生じます)

精度が高いのは修正ユリウス暦ですが、現行の太陽暦として世界各国で使われているのはグレゴリオ暦です。

閏年の計算にはグレゴリオ暦を採用すれば良いですね。

これで、以下のcalendar.pyにおける閏年の判定もようやく理解できました。

def isleap(year):
    """Return True for leap years, False for non-leap years."""
    return year % 4 == 0 and (year % 100 != 0 or year % 400 == 0)

ところで、閏年(うるうどし、じゅんねん、leap year)の反対は平年(へいねん、common year)って言うんですね。

これは初めて知りました。

参考リンク


2015年3月13日金曜日

highlight.jsを使ってBloggerでコードをハイライトする

Blogger上でコードを見やすくする方法について調べたのでメモ。

色々やり方はあるようですが、「highlight.js」を使ってみることにします。

使い方もシンプルで、CDNで提供されているため簡単に導入できそうです。

まず公式ページにアクセスし、「Get version」をクリックします。



2つあるCDNのうち、好きな方ほうからstylesheetとJavaScriptのタグをコピーします。


次に再びTOPページに戻り、「Usage」をクリックします。


そして、一番下のscriptタグをコピーします。


まとめると、以下のような3行になります。

<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/styles/default.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/8.4/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>

これをBloggerの管理画面のレイアウト画面にて「ガジェットを追加」で「HTML/JavaScript」を選択し、

コピーした3行を貼り付ければ準備は完了です。タイトルは任意です。


なお、stylesheetはdefault以外にも種類があり、デモ画面で確認できます。

今回スタイルは「railscasts」を選びました。

では、早速以下のPythonコードをハイライトしてみたいと思います。

@requires_authorization
def somefunc(param1='', param2=0):
    r'''A docstring'''
    if param1 > param2: # interesting
        print 'Gre\'ater'
    return (param2 - param1 + 1) or None

class SomeClass:
    pass

>>> message = '''interpreter
... prompt'''

Bloggerの投稿画面で「HTML」の編集を選択し、コードを以下のタグで囲みます。

<pre><code class="python">...</code></pre>

こんな感じです。

<pre><code class="python">@requires_authorization
def somefunc(param1='', param2=0):
    r'''A docstring'''
    if param1 > param2: # interesting
        print 'Gre\'ater'
    return (param2 - param1 + 1) or None

class SomeClass:
    pass

>>> message = '''interpreter
... prompt'''
</code></pre>

なお、先頭の改行は改行として認識されますが、後尾の改行は自動的に削られます。

そのため、先頭(<code>の直後)には改行を入れないようにします。

結果はこのようになります。

@requires_authorization
def somefunc(param1='', param2=0):
    r'''A docstring'''
    if param1 > param2: # interesting
        print 'Gre\'ater'
    return (param2 - param1 + 1) or None

class SomeClass:
    pass

>>> message = '''interpreter
... prompt'''

ハイライトされましたね!

なお、コードの種類はclass属性で指定しますが、指定しなくても自動で判別してハイライトしてくれるようです。

参考リンク

2015年3月11日水曜日

作ろうと思っていたものが標準ライブラリにあった…

去年の秋頃にPythonに入門(正確には再入門ですが…)して4、5ヶ月。

ある程度使えるようになってきた気がするので、先月くらいからそろそろPyPIにデビューしたいと考えていました。

まずはPyPIに登録してみること自体が目的なので、ちょっとしたツールでいいかなと思い、

何にしようか考えた結果、カレンダーを出力するスクリプトでも書こうかなと。

ところが、いざ作ろうと思って使えそうなモジュールを標準ライブラリの中で探してみると、

そのまんま作ろうと思っていたものがあったわけで…。

我ながらアホですね…。


しかし、こうなると自分が書こうと思っていた処理が、標準ライブラリではどのように実装されているかが気になります。


そんなに長くないので、この機会にこれを読んで勉強してみます。

そして、可能であればPython3の機能を使って書きなおしてみようかな。

2015年3月10日火曜日

ブログ、再始動

以下からこちらに引っ越してきました。


とはいっても、ほとんど投稿していなかった訳ですが…。

なぜ投稿していなかったのかを振り返ってみると、

「記事を書くからには間違いのないしっかりしたものを書かねば…!」

という意識が強かったのかなと思います。

ところが先日、こんなイベントに参加してきました。

このイベントで、ブログについて、

「その時何をやっていたかを忘れないために書く」

というお話があり、

「ブログはもっと気楽に書いていいんだな」

と感じました。

というわけで、ブログを再始動してみようかなと思います。