チャプター1:クリッカーゲームを作る¶
このプロジェクトでは、クリッカーゲーム を組み合わせて、Odoo と完全に統合します。 このゲームでは、多数のクリックを蓄積し、システムを自動化することが目標です。 興味深い点は、私たちの遊び場としてOdooユーザーインターフェイスを使用することです。 例えば、ウェブクライアントのランダムな部分でボーナスを非表示にします。
始めるには、実行中の Odoo サーバーと開発環境が必要です。 練習問題に入る前に、この :ref:`tutorial <tutorials/master_odoo_web_framework/setup> `で説明されているすべてのステップに従っていることを確認してください。
目標

章の各演習の解決策は、 official Odoo tutorials repository にホストされています。
1. システムのアイテムを作成¶
開始するには、systray にカウンタを表示します。
clicker_systray_item.js
(およびxml
) ファイルを hello ワールドコンポーネントとして作成します。systrayレジストリに登録し、それが表示されていることを確認してください。
次の文字列を表示するようにアイテムの内容を更新します:
Clicks: 0
をクリックして、値を増分するボタンを追加します。

そして、出来上がり、私たちは完全に動作するクリッカーゲームを持っています!
2. 外部クリック数をカウント¶
まあ、正直言って、それはまだあまり楽しいことではありません。 そこで、新しい機能を追加しましょう。ユーザーインターフェイス内のすべてのクリックをカウントします。 ユーザーはできるだけOdooを使用するようにインセンティブを与えられます! しかし、明らかに、メインカウンター上の意図的なクリックはまだよりカウントする必要があります。
document.body
をすべてクリックするのをリッスンするには、useExternalListener
を使用します。これらのクリックごとにカウンタ値を1ずつ増やす必要があります。
カウンターをクリックするたびに値が10増加するようにコードを変更します
カウンターをクリックすると、値が11増えないことを確認してください!
また、追加の課題: 外部リスナーがイベントをキャプチャすることを確認してください。クリックを逃さないようにします。
関連項目
useExternalListener の Owl ドキュメント
3. クライアントアクションを作成¶
現在、現在のユーザーインターフェイスは非常に小さいです: それは単なるsystrayアイテムです。私たちは確かに私たちのゲームのより多くを表示するために多くのスペースを必要とします。 これを行うには、クライアントアクションを作成しましょう。クライアントアクションは、コンポーネントを表示するWebクライアントによって管理されるメインアクションです。
client_action.js
(とxml
) ファイルを作成します。hello world コンポーネントです。`awesome_clicker.client_action`という名前のアクションレジストリにクライアントアクションを登録します。
Open`という文字列を使って、sysstrayアイテムにボタンを追加します。 これをクリックすると、クライアントアクション `awesome_clicker.client_action
が開きます(アクションサービスを使用してこれを行います)。従業員のワークフローを乱すことを避けるために、フルスクリーンモードではなく、ポップオーバー内でクライアントアクションを開くことを好みます。 `doAction`コールを変更して、ポップオーバーで開きます。

4. 状態をサービスに移動¶
今のところ、私たちのクライアントアクションはただのhello worldコンポーネントです。 ゲームの状態を表示させたいのですが、その状態は現在システムのアイテムでのみ利用できます。 つまり、すべてのコンポーネントで利用できるようにするために、状態の位置を変更する必要があるということです。 これはサービスにとって完璧なユースケースです。
対応するサービスで
clicker_service.js
ファイルを作成します。このサービスはリアクティブな値(クリック数)といくつかの機能をエクスポートして更新する必要があります。
const state = reactive({ clicks: 0 }); ... return { state, increment(inc) { state.clicks += inc } };
systrayアイテムとクライアントアクションの両方の状態にアクセスします (
useState
を忘れないでください)。 systray項目を変更してローカルの状態を削除し、使用します。また、+10 clicks
ボタンを削除できます。クライアントアクションに状態を表示し、その中に
+10
クリックボタンを追加します。

5. カスタム フックを使用¶
クリッカーサービスを使用する必要があるコードのすべての部分は、 useService
と useState
をインポートする必要があります。 かなり一般的なので、カスタムフックを使用しましょう。 clicker
部分をより強調し、service
部分を強調することも便利です。
useClicker
フックをエクスポートします。クリックサービスの現在の使用状況をすべて新しいフックに更新します:
this.clicker = useClicker();
関連項目
6. 表示される値をヒューマニズム化する¶
将来的には多数を表示するので、その準備をさせていただきます。 `humanNumber`関数があり、数字をよりわかりやすく書式設定できます。例えば、`1234`は`1.2k`と書式設定できます。
カウンターを表示するために使用します(systray アイテムとクライアントアクションの両方)。
値を表示する
ClickValue
コンポーネントを作成します。注釈
Owl はテキストノードだけを含むコンポーネントを許可します。

関連項目
humanNumber 関数 の定義
7. `ClickValue`コンポーネントにツールチップを追加¶
`humanNumber`関数を使うと、インターフェースで正確さが失われました。ツールチップとして実数を表示しましょう。
Tooltipにはhtml要素が必要です。`<span/>`要素で値をラップするには、`ClickValue`を変更してください。
正確な値を表示するために動的な`data-tooltip`属性を追加します。

関連項目
8. ClickBotを購入¶
私たちのゲームをさらに面白くしましょう。プレイヤーが初めて1000クリックになったら。 ゲームは新しい機能を解放する必要があります:プレイヤーは1000クリックでロボットを購入することができます。 これらのロボットは、10秒ごとに10クリックを生成します。
状態に「レベル」の数字を追加します。いくつかのマイルストーンで増加し、新機能を開く数字です。
「clickBots」番号を追加してください。購入したロボットの数を表します。
クライアントアクションをクリックボットの数を表示するように変更します(
level >= 1`の場合のみ) `クリック>= 1000
の場合に有効になるBuy
ボタンを使用します。Buy
ボタンはクリックボットの数を 1 ずつ増やします。10秒間隔を設定して、クリック数を
10*clickBots
増分します。プレーヤーが十分なクリックを持っていない場合は、購入ボタンが無効になっていることを確認してください。

9. クラスモデルにリファクタリングする¶
現在のコードは、やや関数型スタイルで書かれています。 しかし、そのためには、state とそのすべての更新機能をクリッカーオブジェクトにエクスポートする必要があります。 このプロジェクトが成長するにつれて、これはますます複雑になるかもしれません。 簡単にするために、私たちのビジネスロジックをサービスから分割し、クラスにしましょう。
リアクティブなクラスをエクスポートする
clicker_model
ファイルを作成します。すべての状態を移動し、サービスの関数をモデルに更新します。ちなみに
@web/core/utils/reactive
のReactive
クラスで ClickerModel を拡張できます。Reactive
クラスはモデルをリアクティブなプロキシにラップします。クリッカーサービスを書き換えて、クリッカーモデルクラスをインスタンス化してエクスポートします。
10. マイルストーンに達したときに通知する¶
1kクリックに達したときに何かが変わったというフィードバックはあまりありません。その情報を明確に伝えるために、effect
サービスを使ってみましょう。 問題は、クリックモデルがサービスにアクセスできないことです。 また、できるだけUIの関心をモデルから外しておきたいと考えています。 そこで、私たちはコミュニケーションのための新しい戦略を探求することができます:イベントバス。
クリッカーモデルを更新して、バスをインスタンス化し、初めて1000クリックに達したときに
MILESTNE_1k
イベントをトリガーします。クリッカーサービスをモデルバスで同じイベントをリッスンするように変更します。
それが起こったら、`エフェクト`サービスを使って虹色の男を表示します。
ユーザーがクリックボットを購入できるようになったことを説明するテキストを追加します。

11. BigBotを追加¶
明らかに、プレイヤーにもっと多くの選択肢を提供する方法が必要です。 新しい種類のクリックボットを追加しましょう: BigBots
10秒ごとに100回クリックしますが5000回クリックするだけです
5kになったときに`レベル`を増やします(2)
bigbotsを追跡するために状態を更新します
bigbotsは`レベル > =2`で利用できます。
クライアントアクションで対応する情報を表示します
ちなみに
JavaScriptの式としてテンプレート内で`<または
>`を使用する必要がある場合は、xmlパーサでクラス化する可能性があるので注意してください。 これを解決するには、gt, gte, lt
または lte
のいずれかの特殊エイリアスを使用できます。 テンプレート式 <https://github.com/odoo/owl/blob/master/doc/reference/templates.md#expression-evaluation>`_ の `Owl ドキュメントページを参照してください。

12. 新しいタイプのリソースを追加: 電力¶
次に、別のスケーリングポイントを追加するために、新しいタイプのリソースを追加しましょう。パワー乗数です。 これは、`level >= 3`で増やすことができる数値で、Botの動作を乗算します。 クリックを1回ではなく、クリックボットが「multilier」クリックを提供してくれるようになりました。
100kになると`レベル`を増やします(3にする必要があります)。
電力を追跡するために状態を更新します(初期値は1です)。
乗数として使うボットを変更します。
ユーザーインターフェイスを更新して、ユーザーが新しいパワーレベルを購入できるようにします(コスト:50k)。

13.ランダム報酬を定義する¶
私たちは、ユーザーが時々ボーナスを取得し、Odooを使用して報酬を得ることを望んでいます。
click_rewards.js`で報酬のリストを定義します。報酬は次のオブジェクトです: `description`文字列。 - ゲームの状態を引数に取り、変更できる `apply
関数です。 - ボーナスが利用可能なロック解除レベルを示す「minLevel」番号(任意)。 - ボーナスが利用できなくなったロック解除レベルを記述するmaxLevel
番号 (任意)例:
export const rewards = [ { description: "Get 1 click bot", apply(clicker) { clicker.increment(1); }, maxLevel: 3, }, { description: "Get 10 click bot", apply(clicker) { clicker.increment(10); }, minLevel: 3, maxLevel: 4, }, { description: "Increase bot power!", apply(clicker) { clicker.multipler += 1; }, minLevel: 3, }, ];
そのリストに何でも追加できます!
関数`getReward`を定義すると、現在のロック解除レベルに一致する報酬のリストからランダムな報酬を選択できます。
`choose`関数の中で、別の`utils.js`ファイルに移動することができる配列からランダムに選択するコードを抽出します。
14. フォームビューを開くときに報酬を提供する¶
フォームコントローラにパッチを適用します。フォームコントローラが作成されるたびに、報酬が与えられるかどうかをランダムに決定します(1%の確率)。
答えが「はい」の場合は、モデルのメソッド「getReward」を呼び出します。
その方法は報酬を選択し、通知を送信する必要があります。 報酬が適用されるボタン
Collect
を使用すると、最後にclicker
クライアントアクションが開きます。

15. コマンドパレットにコマンドを追加¶
コマンドパレットに`Clicker Gameを開く`コマンドを追加します。
`Buy 1 click bot`というコマンドを追加します。

16. さらに別のリソースを追加: 木¶
今、完全に新しい種類のリソースを紹介する時間です. ここではあまりにも論争されるべきではないものです: 木. これで、ユーザーは果物の木を植える(収集する?)ことができます。 木は100万クリックの費用がかかりますが、果物(梨またはチェリーのいずれか)が提供されます。
さまざまな種類の木:梨/チェリーとその果物を追跡するために状態を更新します。
木と果物の合計数を計算する関数を追加します。
新しいロック解除レベルを
clicks >= 1000 000
で定義します。クライアントのユーザー インターフェイスを更新して、木や果物の数を表示し、木を購入することもできます。
30秒ごとに果実番号を1ずつ増やします。

18. ノートブックコンポーネントを使用する¶
私たちは今、より多くの情報を追跡します。 Notebook
コンポーネントを使用して、さまざまなタブの情報と機能を整理することで、クライアントインターフェースを改善しましょう。
Notebook
コンポーネントを使用します。すべての
click
コンテンツは 1 つのタブに表示されます。すべての
tree/fruits
コンテンツは別のタブに表示されます。

19. ゲームの状態を保持¶
あなたは確かに私たちのゲームで大きな欠陥に気づいた:それは一時的です。 ユーザーがブラウザのタブを閉じるたびにゲームの状態が失われます。 それを修正しましょう。ローカルストレージを使用して状態を保持します。
browser
を@web/core/browser/browser
からインポートしてローカルストレージにアクセスします。10秒ごとに状態をシリアル化し、ローカルストレージに保存します。
clicker
サービスが開始されると、ローカルストレージから状態をロードするか、そうでなければ自分自身を初期化する必要があります。
20.状態移行システムを導入する¶
どこかで状態を保持すると、新しい問題が発生します:コードを更新すると何が起こるか。 状態の形状が変化しユーザーがブラウザを開いて 古いバージョンで作られた状態で? 移行問題の世界へようこそ!
その問題に早期に取り組むのは賢明だろう。 ここでは、バージョン番号を州に追加します。 最新でない場合は自動的に州を更新するシステムを導入します。
状態にバージョン番号を追加します。
マイグレーションのリストを定義します。マイグレーションは、
fromVersion
番号、toVersion
番号、およびapply
関数を持つオブジェクトです。コードがローカルストレージから状態をロードするたびに、バージョン番号を確認する必要があります。 状態が最新でない場合は、必要な移行をすべて適用する必要があります。
21.別の種類の木を追加¶
移行システムをテストするために、新しいタイプの木を追加しましょう: 桃。
`桃`の木を追加します。
状態のバージョン番号を増分します。
移行を定義します
