タイルのコスチュームを入れ替える

korakurider2006-03-17

Tweakのアップデートをかけたら(Tweak-Tiles-bf.102.mcz)、代入文のタイル上の語順が変更されていました。

  • 変更前:"set オブジェクト プロパティ to 値"
  • 変更後:"オブジェクト set プロパティ to 値"

オブジェクトにメッセージを送信するという言語形式へより統一されたという言い方はできます。

しかし、タイル表現を翻訳することを考えると、語順をどうするかは重要な設計判断です。日本語の環境で言えば、ドリトルみたいにメッセージ送信を強調する方針もあると思いますし、言霊みたいな自然な日本語表現を重視する方針も考えられます。いずれにせよ今のタイル実装のまま日本語化するのは難しいです。また、http://d.hatena.ne.jp/korakurider/20060211/p2 みたいな問題の回避も必要です。

Tweakのコードを読むと、いろんな要素を実行時に自由に入れ替えられることを目標に設計されていることがわかります。タイルについても、Player/Costumeの仕組みを使って、ビジュアルを完全に入れ替えられるようになっています。そこで、実際に入れ替えの実験をしてみます。日本語化の方法を考察することが目的なので、このシリーズのエントリ(連載?)では、Tweaklandイメージ http://d.hatena.ne.jp/propella/20060211/p1 を使います。

タイルのコスチュームを決定する仕組み

  • CTileLibraryのクラス変数に、目的別のcostumeクラスを返す「タイルライブラリ」が格納されています。デフォルトでは CTileLibraryがタイルライブラリとして使われます。
  • さらに、いくつかのオブジェクトから構成されているタイルでは、costumeクラスのinitializeメソッドで、内部に含まれるcostumeをクラス指定で作成している場合があります。

例:CMessageTileCosutme>>initialize

initialize
	super initialize.
	self define: #fireButton as: CTileButton new.
	self define: #receiverTile as: CReceiverTileCostume new.
	self define: #argumentsTile as: CMessageAndArgsCostume new.
	self define: #expandArrow as: CTileButton new.

従って、costumeクラスの別セットとそれを指定するタイルライブラリクラスを作成し、タイルライブラリとして登録すればよさそうです。

最初の一歩:やりたいこと

  • http://d.hatena.ne.jp/korakurider/20060211/p2 の問題が解決できるまでの回避策として、フレーズの翻訳をしないタイルに入れ替える。
  • プロパティの表現が「オブジェクト's プロパティ」という英語表現になっているので、「オブジェクトのプロパティ」という表現のタイルに入れ替える。

※タイルライブラリの入れ替えのコード例は省略します。

プロパティ表現の入れ替え

(1) 他のタイルは全部#detaultCostumeでタイルライブラリにcostumeを聞いているのに、mなぜか、CPropertyTile>>defaultCostumeは、costumeクラスがハードコードされていて入れ替えできなくなっていました。そこでこれを直します。

CTileLibrary>>propertyTileCostume
	^CPropertyTileCostume

CPropertyTile>>defaultCostume
	^CTileLibrary default propertyTileCostume

(2) プロパティの表現は、CPropertyTileCostume→CReceiverTileCosutme という内部構造になっています。これらをコピーして CxPropertyTileCostume, CxReceiverTileCostumeを作成します。コピー後の修正点:

CxPropertyTileCostume>>initialize
	super initialize.
	self define: #fireButton as: CTileButton new.
	self define: #receiverTile as: CxReceiverTileCostume new.
	self define: #argumentsTile as: CxMessageAndArgsCostume new.
	self define: #expandArrow as: CTileButton new.

CxReceiverTileCostume
onNameChanged
	<on: nameChanged in: value>
	reflexive 
		ifTrue:[self text: value name,'の']
		ifFalse:[self text: value name].

一時的にフレーズの翻訳をとめる

(1) フレーズの表現は、CMessageTileCostume→CMessageAndArgsCostumeという内部構造になっています。これらをコピーして、CxMessageTileCostume, CxMessageAndArgsCostumeを作成します。コピー後の修正点:

CxMessageTileCostume>>initialize
	super initialize.
	self define: #fireButton as: CTileButton new.
	self define: #receiverTile as: CxReceiverTileCostume new.
	self define: #argumentsTile as: CxMessageAndArgsCostume new.
	self define: #expandArrow as: CTileButton new

CxMessageAndArgsCostume>>initialize
	この表現"displayName := player displayName ifNil:[selector]."を
	こちらの表現に直す displayName := selector.

感想・考察

タイルの入れ替え自体は思ったより簡単でした。
今回はさぼりましたが、引数つきメッセージの翻訳については、もっと動的な構築方法をとれば日本語向け実装自体はできますが、従来やっていたように単に翻訳データを用意するだけは済まず、多言語対応のフレームワークを考え直す必要があるように思います。
その場合、言霊で行われているような語順調整も含めて問題を一般化できそうです。

あとはプロジェクトの保存・復元との関係を検証する必要がありますね。ODFとのつなぎは日を改めて実験してみます。