PG日誌

読者です 読者をやめる 読者になる 読者になる

PG日誌

主にc#の事を書いています

Cocos2d-xでHPゲージを実装する

f:id:Takachan:20170207232430j:plain

何番煎じかわからないですが、Cocos2d-xでHPゲージを実装してみます。

仕様

今回は、ドット絵風のゲージ表現をしたいので、ProgressTimer使わずに、Spriteのみでいきたいと思います。

HPゲージの仕様ですが、

  • HPが減少すると右から左にバーが減っていく
  • HPに応じてバーの色が変わる
    • HPが50%以上の時は緑色
    • HPが25%以上の時は赤色
    • HPが10%以下は赤色

とします。

仕様リソース

リソースがくっそ小さくてすいません。

HPゲージの枠 : hp_frame.png 24x24で、周囲1ドットが枠になってます。

f:id:Takachan:20170207232937p:plain

緑色のバー : hp_bar_green.png

f:id:Takachan:20170207233054p:plain

黄色のバー : hp_bar_yellow.png

f:id:Takachan:20170207233112p:plain

赤色のバー : hp_bar_red.png

f:id:Takachan:20170207233119p:plain

実装

先に結果を載せておきます。

緑色の時

f:id:Takachan:20170207233735p:plain

黄色の時

f:id:Takachan:20170207233739p:plain

赤い時

f:id:Takachan:20170207233742p:plain

説明

枠の拡大をScale9Spriteで行う

いきなりコードを載せる前に概念的な説明です。

今回枠を拡大するのにSpriteの4隅を残してそれ以外を拡大するために、Scale9Spriteを使用しています。

Scale9SrpiteはSpriteを9等分して4隅を残してそれ以外を拡大する方式です。

こんな感じです。

f:id:Takachan:20170207235443p:plain

なんだか昔と使い方が変わってるみたいでヘッダは以下をincludeして

#include "ui\UIScale9Sprite.h"

インスタンス化する時は以下のように使います。

auto frame = Scale9Sprite::create("画像の名前", $Spriteの全体サイズ, $内側の矩形サイズ);

$全体サイズと$内側の矩形サイズの関係性ですが図にするとこんな感じです。

また、サイズの指定は、setContentSizeで行います。setScaleは使いません。一緒に指定するととんでもないサイズになるのでご注意を。

クラス構成

  • HpBar.h
  • HpBar.cpp
    • HPゲージの実態
      • 枠と3色のゲージのSpriteを包含している
      • setCurrentでゲージの表示を更新
  • BarState.h
    • HPゲージの表示状態(色)を表します。

f:id:Takachan:20170208000120p:plain

createで作って、getBarSprite()を好きなところへaddChildして、setCurrent(100)などするとバーが増減します。

コード

肝心のコードは以下の通りです。

大したことしていないのに尋常じゃなく長いので醜ければ最下段からGistで参照してください。

gist.github.com

List<T>の使い方

f:id:Takachan:20170115150341j:plain

C#で動的に要素を追加したり、削除したりしたいときに使う動的なリストの使い方のメモになります。

基本的な使い方

使う前に以下を宣言する。

using System.Collections.Generic;

単純な宣言

// int型を格納するリストを宣言、intの部分は任意の型が指定できる
var list = new List<int>();

宣言時に内容を指定して初期化

var list = new List<int>()
{
    1, 2, 3, 4 // listには最初から1,2,3,4の4つの要素が含まれている
};

要素の追加/挿入

list.add(5); // 末尾に5を追加
list.Insert(0, 100); // 先頭(0番目)に100を追加

要素の削除

list.Remove(5); // 最初に見つかった5を削除
list.RemoveAt(2); // 2番目の要素を削除
list.RemoveAll(p => p == 2); // 条件(この場合2)に一致するものを全部削除
list.Clear(); // 全部削除

Clearはキャパシティが増えたままなので、長期間使用するなどの場合、必要があればTrimExcess()メソッドをたまに呼び出したほうがメモリに優しいです。

アクセス方法

int item = list[2]; // 2番目の要素にアクセス

 foreach(int num in list) // 先頭から最後まで順番に表示
{
    Console.WriteLine(num);
}

foreach(int num in list.Reverse()) // 最後から先頭へ逆順に表示
{
    Console.WriteLine(num); 
}

ソート

var list = new List<int>() { 5, 2, 6, 3 };
list.Sort(); // 辞書順にソート
 // → 2, 3, 5, 6

list.Sort((a, b) => b - a); // カスタムソートはラムダを書く(逆順にする場合)
// → 6, 5, 3, 2

存在確認

if(list.Exists(p => p == 3)) // 3に一致するものがあるかどうか確認する
{
    // 存在する
}

使用上の注意

Listクラスは、IEnumerableとか、ICollection, IListを継承しているのでなるべくインターフェースで受け渡した方が拡張性が上がります。SortedListとかLinkedList(T)に変更した場合でもシグネチャ変更が発生しません。

public ICollection<int> GetList() { // インターフェースで受け渡す

使い方によってどんなインターフェースを使えばいいかはざっくりとこんな感じです。

interface 状況
IEnumerable(T) 読み取り専用。foreachとかで使ってほしい。無限の長さの場合もこれ
ICollection(T) 追加、削除あり。インデクサでアクセスしない
IList(T) 追加、削除あり。インデクサでアクセスする。配列みたいに使う

(T)が付いていないIList, ICollection, IEnumerableは基本使いません。

プロパティの場合、setterはprivateにしておいた方が安全です。ReadOnlyCollection(T)などに外から変更されて、クラス内で操作して例外が出るなどは想定外かと思います。

public ICollection<int> List { get; private set; } // setはprivateにしておく

やらないほうがいい事

var list = new List<List<int>>(); // <T>の中にジェネリックを宣言しない。

何個でも入れ子にできるのですが外部公開すると理解できない、アクセスを制御できないとコントロール不能なケースが多いのでこういう実装はしない方がいいです。アクセス用のクラスを作りましょう。

あと、Listを直接継承するのではなくIList(T)やICollection(T)を継承したほうが拡張性に優れます。ただ、ライブラリを作成するのでない限り、インターフェースが多機能すぎるので全部自前で実装するより、List(T)を所有するクラスかがアクセス方法を提供するほうが簡単なケースが多いと思います。

2016年にリアルで聞いた意識の高すぎる言葉大賞

もう1月終わっちゃいそうなんですが、去年1年間IT産業に従事して、意味が分からなかったというか、本当に意味わかってんのかというか、発言者の人柄というか、効いた頻度というか、とっても違和感を感じた言葉をまとめてみました。いちおう1回以上リアルで聞いた覚えがあるものを上げています。

ちなみに順位が高いほど言葉に言霊が宿ってるのか記憶障害が発生して意味の把握が微妙です。

6位 コア・コンピタンス

企業の強み

この言葉の凄いところは、日本語に完璧に言い換えが可能なところだと思ってます。

用例

  • 「わが社のコア・コンピタンスは(ry」
  • 「わが社の強みは(ry」

「なんでわざわざ英語で言った?」

コア・コンピタンス(wikipediaより)

コア・コンピタンス (Core competence)とは、ある企業の活動分野において「競合他社を圧倒的に上まわるレベルの能力」「競合他社に真似できない核となる能力」の事を指す。ゲイリー・ハメル(英語版)とプラハラード(英語版)がハーバード・ビジネス・レビュー Vol.68(1990年)へ共同で寄稿した「The Core Competence of the Corporation[1]」の中で登場し、その後広められた概念である。「顧客に特定の利益をもたらす技術、スキル、ノウハウの集合である」と説明されている。 両氏の定義によると、コア・コンピタンスは次の3つの条件を満たす自社能力のことである[2]。

5位 コンセンサス

合意

これ、明らかに総理大臣が使ってるから、ニュースで知って使い始めたという人が散見されました。

コンセンサス(三省堂辞書サイトより)

「複数の人による合意」のことです。

用例

  • 顧客とコンセンサスをとってくる
  • 顧客と合意してくる

「コンセンサスを『とってくる』」って何ですかね?ルー語かなにかですかね?

4位 アジェンダ

議題の一覧

もうここら辺から早くも意味がよくわからなくなってきますね。会議の進行予定とかだと思います。

用例

  • 今日の会議のアジェンダです
  • 今日の会議の議事一覧です

アジェンダ(wikipediaより)

会議における検討課題、議題、議事日程。(公的機関の)スケジュール、行動計画、日程表。ラテン語の「agenda」(「行動する」という意味の動詞「agere」の動形容詞「agendus」の中性複数形)に由来する。

3位 アグリー

合意?肯定的な反応

  • その意見にアグリー
  • Y田さんに100ポイント

アグリーバードなんつって。いきなりアグリーと言われて反応できるやつは敵だと思う。

アグリー(マイナビ)

アグリーは「同意する」「賛成する」という意味

2位 ダイバーシティ

多様性

あー、、あのお台場にあるやるね。そうそう。知ってるしってるー。ダイバーシティでしょ?

用例とか思いつかんわ。南の島で酸素ボンベしょって思う存分やってこい。

ダイバーシティ(Weblioより)

「多様性」などの意味を持つ英語

1位 インフルエンサー

イラァ、、、

意味不明、有名人のステマからの商品購入行動?

言葉の響きに言霊が宿ってるのかってくらい何だか、心中穏がざわつきますね。

リアルで言ってるのを聞いたときは逆に感動してしまいましたが。

あ、40度くらいの高熱が出るやつ。一応言っておこうかなと。

インフルエンサー(MarkeZine)https://markezine.jp/word/detail/%E3%82%A4%E3%83%B3%E3%83%95%E3%83%AB%E3%82%A8%E3%83%B3%E3%82%B5%E3%83%BC

有名人やスポーツ選手、有名ブロガーのような、自身のブログやSNS、メディアへの露出などで商品やサービスを紹介することで、大多数の消費者に大きな影響力を発揮するキーパーソン。

番外編

番外編は、特に今年に限ったことじゃありませんが、自分で使いながら2016中何だか変な言葉だなと思った言葉とか、リアルでは見なかったけどネットで見かけた言葉とかです。

シリアル化

オブジェクトからXMLやJsonなどへデータ形式を変換すること。逆シリアル化、デシリアライズはその逆

ハンドル

ファイルハンドル、ウインドウハンドル、スレッドハンドルなどなど。ドザー系プログラマーがOSから借りてくる資源。返さないと交通事故(リーク)が起きる、握らずにはいられない中毒性のあるハンドル。

オウンドメディア

卵産む鶏の事だよ。オンドリー。

さいごに

すいません、書いてて多少イライラしてしまったので内容がちょっと荒れました。

こうやって振り返るとマーケティングというか広告業界発の言葉は破壊力が高いのが多いみたいですね。

割とよく言われていますが、カタカナ語で言っても意味が伝わらない、本質がぼやける、ぼく個人がイラつくなどいろいろ効果があるので日本語に言い換えられるならそうしたほうがいいと思います。

Disposeパターンを実装する

f:id:Takachan:20170112223259j:plain:h200

Disposeパターンについて調べたので結果をまとめてみようと思います。

Disposeパターン

Disposeパターンですが、c#で基底クラスが

  • アンマネージリソースを使用する
  • 派生クラスで継承される予定がある

場合、クラスにIDisposeメソッドを付けてリソース解放を明示的に行いたい場合に使います。特に、基底クラスのDispose呼び出しによって派生クラスの資源解放を確実に行いたい場合これを適用します。

MSDNにはDiposeパターンの解説があるのですが日本語の方は機械翻訳で読むのが大変です。(もし日本語版を読むなら2010とか古いバージョンの方が良さそうです。)

コード例

早速コード例ですが、

基底クラスの実装

public class Base : IDisposable
{
    // Disposeされたかどうかを表すフラグ
    //   true : Dispose済み
    //   false : Disposeまだ
    private bool disposed;

    // IDisposableの実装
    public Dispose()
    {
        this.Dispose(true);

        // デストラクタを呼ばない指示
        //  → 2重解放しないようにする
        GC.SuppressFinalize(this);
    }

    // Disposeパターン用のメソッド
    //
    // disposing
    //   true : Disposeメソッドからの呼び出し
    //   false : デストラクタからの呼び出し
    protected virtual void Dispose(bool disposing)
    {
        if(this.disposed)
        {
            return; // 解放済みなので処理しない
        }

        if(disposing)
        {
            // managed resource の解放処理を記述
        }

        // unmanaged resource の解放処理を記述

        // Dispose済みを記録
        this.disposed = true;
    }
}

派生クラスの実装

public class Derived : Base
{
    // Disposeされたかどうかを表すフラグ
    // (派生クラスにも実装する)
    //   true : Dispose済み
    //   false : Disposeまだ
    private bool disposed = false;

    // Baseクラスのメソッドをoverrideしている
    protected override void Dispose(bool disposing)
    {
        // 基底クラスのつくりと同じ ---->

        if(this.disposed)
        {
            return; // 解放済みなので処理しない
        }

        if(disposing)
        {
            // managed resource の解放処理を記述
        }

        // unmanaged resource の解放処理を記述

        // Dispose済みを記録
        this.disposed = true;

        // <---- 基底クラスのつくりと同じ

        // 基底クラスのDisposeを呼び出す(超重要!!)
        base.Dispose(disposing);
    }
}

利用側のコード

public class AppMain
{
    public void Main(string[] args)
    {
        // ☆使用例1☆
        Base base_1 = new Derived();
        base_1.Dispose();
        // Derived.Dsipose(bool) → Base.Dispose(bool) の順に呼ばれる

        // ☆使用例2☆
        using(Base base_2 = new Derived())
        {
            // (省略)
        }
        // この時点で base_1 の Dipose と同じ動きになる

        // ☆使用例3☆
        Derived derived = new Derived();
        ((Base)derived).Dipose();
        // これも Derived.Dsipose(bool) → Base.Dispose(bool) の順に呼ばれる

        // ☆使用例4☆
        using(Derived  base_2 = new Derived())
        {
            // (省略)
        }
        // これも同じ
    }
}

もしこのコードを他人に配るような場合公開メソッドには以下のようにDipose済みだったら処理を行わない実装をした方が幸せになれます。

public void Foo()
{
    if(this.disposed)
    {
        throw new InvaliedOperationException("Object is disposed.");
    }
}

注意点

だいたいコメントの通りですが、Dipose(bool disposing)を各クラスが持つ日調があり、これは手で書く必要があります。(面倒なので世の中テンプレートを配布されている方も居るのでそれらを使った方が確実です)

また、派生クラスの注意点は

  • IDisposableを継承しない
  • デストラクタ(Finaliza)を実装しない
  • base.Disposeメソッドの呼び出しを忘れない
  • Dispose(bool)は protected virtual を忘れない

となります。全ての派生クラスでDisposeを継承せずに基底クラスのIDisposableを有効に使用することを意図しています。

参考資料

このことが書いてある書籍ってほとんどないのですが知っている中で唯一この本にだけDisposeについて言及があります。よかったら読んでみてください。

Effective C# 4.0

Effective C# 4.0