i++

プログラム系のメモ書きなど

TypeScript : typings による Chrome Extension 用型定義のインストール

typings で型定義ファイルの管理を行うので、未インストールの場合はインストールします。

npm install -g typings

拡張機能のプロジェクトのディレクトリに移動し、typings init コマンドで初期化します(typings.json ファイルが作成されます)。 その後、install コマンドで Chrome Extension 用の 型定義ファイル(.d.ts)をインストールします。

typings install chrome --ambient --save
typings install filesystem --ambient --save
typings install filewriter --ambient --save
typings install webrtc/mediastream --ambient --save
typings install es6-shim --ambient --save

chromeChrome Extension 用の型定義の本体ですが、これをインストールするだけ使えず、chrome が依存している他の型定義もインストールする必要があります。 typings でインストールしたときに、Stripped reference というメッセージが表示された場合、それらを手動でインストールする、と覚えておけば良さそうです。

> typings install chrome --ambient --save
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/webrtc/MediaStream.d.ts" during installation from "chrome"
typings INFO reference Stripped reference "https://raw.githubusercontent.com/DefinitelyTyped/DefinitelyTyped/7de6c3dd94feaeb21f20054b9f30d5dabc5efabd/filesystem/filesystem.d.ts" during installation from "chrome"
chrome
└── (No dependencies)

--ambient って何者?など typings についてより詳しく知りたい場合は TypeScriptの型定義管理ツールTypingsについて - Qiita が参考になります。

Git : コミットメッセージに自動でブランチ名を挿入する

参考:How to add Git's branch name to the commit message?

  1. .git/hooks/ 下にある prepare-commit-msg.sample を prepare-commit-msg に変更する(.sample を外す)
  2. prepare-commit-msg に以下のようなスクリプトを追記する
branchPath=$(git symbolic-ref -q HEAD) # branchPath は refs/heads/feature/XXXX_YYYY のような文字列に
branchName=${branchPath##*/} # 最後の / 以下を取得し、branchName は XXXX_YYYY のような文字列に
issueNumber=$(echo $branchName | cut -d "_" -f 1) # "_" を delimiter として cut し、issueNumber は XXXX に
firstLine=$(head -n1 $1)

if [ -z "$firstLine"  ] ;then # 最初の行が空行かチェックして、amend でないことを確認
    sed -i "1s/^/($issueNumber) \n/" $1 # コミットメッセージの先頭に (XXXX) という文字列でブランチの情報を追加。
fi

参考先に少し修正を加え、branchName を直接使うのではなく、cut を使ってその一部を使うようにしています。 例えば feature/XXXX_YYYY というブランチ名だった場合、コミットメッセージには (XXXX) という形でブランチ名の一部が入るようになります。

これは、自分は XXXX の部分にイシューやタスクの番号を、YYYY の部分に少し説明的な文章を入れる形でブランチ名を作っているためです。

Unreal Engine : Timeline を C++ コードで作成・実行する

手順

準備
  1. Timeline で使用する Curve を「Content Browser を右クリック」→「Miscellaneous」→「Curve」(もしくは「Float Curve」)で作成する
  2. 作成した Curve を右クリックして「Copy Reference」する
  3. C++ のコード上で ConstructorHelpers::FObjectFinder を使い、先ほど作成した Curve を取得する
  4. FTimeline オブジェクトを作成する
  5. FTimeline オブジェクトに追加する FOnTimeline* (FOnTimelineVector や FOnTimelineFloat など Curve の種類による)を作成する
  6. FOnTimeline* に、Timeline が更新される毎に呼び出す関数を設定する
  7. FTimeline に、Curve と FOnTimeline* を追加する

Timeline 完了時のイベントを追加する場合のために SetTimelineFinishedFunc などもあるので、適宜使用する。

実行
  1. FTimeLine の PlayFromStart 関数を呼ぶ
    • 途中から再生する場合は Play、逆再生する場合は Reverse など再生開始方法は任意
  2. Tick で FTimeline の IsPlaying() が真であれば、TickTimeline(DeltaTime) を呼ぶ
    • 更新頻度が低くて良い場合は Tick ではなく TickTimeline を呼ぶだけの関数を設定した Timer を作成したほうが負荷が軽くなって良いかも

サンプルコード

void MyActor::MyActor()
{
    // 他の初期化処理...

    // メンバー変数として FTimeline* MyTimeline を定義している
    MyTimeline = new FTimeline();
    MyTimeline->SetTimelineLength(1.0f);

    // 作成した Timeline の取得。Copy Reference でコピーしたテキストを TEXT の中に貼り付ける。
    // <> の中身は Curve の種類によって変更する。今回は Vector。 
    const ConstructorHelpers::FObjectFinder<UCurveVector> StepCurve(TEXT("CurveVector'/Game/Timeline/TimelineCurve.TimelineCurve'"));

    // Timeline 更新時に呼ばれる関数の設定。このクラスに定義している void TimelineStep(FVector v) を呼ぶ。
    FOnTimelineVector MyTimelineStepFunction;
    MyTimelineStepFunction.BindUFunction(this, "TimelineStep");
    MyTimeline->AddInterpVector(StepCurve.Object, MyTimelineStepFunction);

    // Timeline 終了時に呼ばれる関数の設定。このクラスに定義している void TimelineFinished(FVector v) を呼ぶ。
    FOnTimelineEvent MyTimelineFinishedFunc;
    MyTimelineFinishedFunc.BindUFunction(this, "TimelineFinished");
    MyTimeline->SetTimelineFinishedFunc(MyTimelineFinishedFunc);
}

void MyActor::BeginPlay()
{
    if (MyTimeline != nullptr) {
        MyTimeline->PlayFromStart();
    }
}

void MyActor::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );

    // Timeline 再生中であれば DeltaTime 進めて実行
    if (MyTimeline != nullptr && MyTimeline->IsPlaying())
    {
        MyTimeline->TickTimeline(DeltaTime);
    }
}

// TickTimeline 毎に、進んだ Time の合計と対応した Timeline から得られる値でこの関数が呼ばれる
// .h で定義する際に UFUNCTION() を付けておくこと
void MyActor::TimelineStep(FVector value)
{
    UE_LOG(LogTemp, Warning, TEXT("TimelineStep : (%.2f, %.2f, %.2f)"), value.X, value.Y, value.Z);
}

// Timeline 完了時に呼ばれる関数
// .h で定義する際に UFUNCTION() を付けておくこと
void MyActor::TimelineFinished()
{
    UE_LOG(LogTemp, Warning, TEXT("TimelineStep Finished"));
}

参考


Blueprint も良くできていると思いますが、メインは C++ で書いたほうが楽そうです。

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

Unreal Engine 4で極めるゲーム開発:サンプルデータと動画で学ぶUE4ゲーム制作プロジェクト

WPF/XAML : DataGrid の行にコンテクストメニューを設定する

方針・ポイント

  • EventSetter を使って DataGridRow に右マウスボタンイベント(MouseRightButtonUp)を設定する
  • ContextMenu を DataGrid.Resources 内で作る
  • そのイベント内で、Resources の ContextMenu を取得、設定する

ContextMenu の方もコード上で作る、右クリック時ではなく行を追加した時に ContextMenu を設定するなど、他にも様々な方法で同じことが実現できると思いますが、今回は上記の方法で行います。

右マウスボタンのイベントの方が、右クリックによるコンテクストメニューの表示よりも先に行われるようなので、最初の右クリックでメニューは表示されます。

f:id:tkyjhr:20160127145816p:plain

サンプルコード

XAML
<DataGrid x:Name="MyDataGrid" AutoGenerateColumns="False">
    <DataGrid.Resources>
        <!-- ContextMenu の作成 -->
        <ContextMenu x:Key="DataGridContextMenu">
            <MenuItem Header="Menu 1" Click="MyDataGrid_ContextMenu1_Click"/>
            <MenuItem Header="Menu 2" Click="MyDataGrid_ContextMenu2_Click"/>
        </ContextMenu>
        <!-- DataGridRow に右マウスボタンイベントの設定 -->
        <Style TargetType="{x:Type DataGridRow}">
            <EventSetter Event="MouseRightButtonUp" Handler="MyDataGrid_Row_MouseRightButtonUp"/>
        </Style>
    </DataGrid.Resources>
    <!-- 適当なサンプルデータ表示用の列 -->
    <DataGrid.Columns>
        <DataGridTextColumn Header="苗字" Binding="{Binding FamilyName}" Width="80"/>
        <DataGridTextColumn Header="名前" Binding="{Binding FirstName}" Width="80" />
    </DataGrid.Columns>
</DataGrid>
C#
public partial class MainWindow : Window
{
    // 適当なサンプルデータ用のクラス
    public class Person
    {
        public string FirstName { get; set; }
        public string FamilyName { get; set; }

        public Person(string firstName, string familyName)
        {
            FirstName = firstName;
            FamilyName = familyName;
        }
    }

    private ObservableCollection<Person> MyDataGrid_SourceCollection;

    public MainWindow()
    {
        InitializeComponent();

        // 適当サンプルデータを追加
        MyDataGrid_SourceCollection = new ObservableCollection<Person>();
        MyDataGrid_SourceCollection.Add(new Person("太郎", "山田"));
        MyDataGrid_SourceCollection.Add(new Person("花子", "佐藤"));
        MyDataGrid.ItemsSource = MyDataGrid_SourceCollection;
    }

    // DataGridRow に対する右マウスボタンイベント
    private void MyDataGrid_Row_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
    {
        // Resources から ContextMenu を取得して設定
        (sender as DataGridRow).ContextMenu = MyDataGrid.Resources["DataGridContextMenu"] as ContextMenu;
    }

    // ContextMenu の MenuItem のイベントその1
    private void MyDataGrid_ContextMenu1_Click(object sender, EventArgs e)
    {
        if (MyDataGrid.SelectedItem != null)
        {
            MessageBox.Show("Menu 1 : FirstName = " +(MyDataGrid.SelectedItem as Person).FirstName);
        }
    }

    // ContextMenu の MenuItem のイベントその2
    private void MyDataGrid_ContextMenu2_Click(object sender, EventArgs e)
    {
        if (MyDataGrid.SelectedItem != null)
        {
            MessageBox.Show("Menu 2 : FamilyName = " + (MyDataGrid.SelectedItem as Person).FamilyName);
        }
    }
}

Markdown : タイトル末尾に # 記号を使う

Markdown で # を使った形式でタイトルを書く時、

### C#

と書くと結果は

C

となり、末尾の #(ハッシュ記号?シャープ記号?)が表示されません。
以下のように、後ろに # をつけることできちんと表示されるようになります。

### C# #

C#

Unreal Engine : C++ クラスを削除する

  1. Visual Studio 上で削除対象のクラスの .h と .cpp を削除します
    • Visual Stdio 2015 の Remove ではプロジェクトから削除するだけのようなので、エクスプローラーを開きファイルの実体も削除しておきます
  2. Visual Studio 上でソリューションをビルドします
    • このタイミングでの Unreal Engine のエディタからのコンパイルは、先ほど削除したファイルが見つからない、というエラーで失敗しました
  3. Unreal Engine を一旦終了し、再度開きます
  4. Content Browser でクラスが消えていることを確認します

Content Browser からは削除やリネームができないんですね。

使っていないクラスを消すくらいならば大した問題はなさそうですが、クラスを継承した Blueprint が存在したりする場合や、削除ではなくクラス名の変更をする場合などはいろいろとややこしくなりそうです。

参考

Unreal Engine : C/C++ コードからのログ出力

コンソール(Output Log)へのログ出力と、ゲーム画面上へのログ出力の2通りの方法でログを確認できます。

Console ログ出力

UE_LOG(カテゴリ名, ログレベル, テキストフォーマット, テキスト引数) を使用します。

カテゴリなし
// LogTemp は定義なしで使用可能なカテゴリです
UE_LOG(LogTemp, Warning, TEXT("%s: Hello!"), __FUNCTIONW__);
単一ファイル用カテゴリ
// このカテゴリを使う .cpp 内で定義します
// カテゴリ名を "(ダブルクオーテーション)で囲んで文字列として定義する必要はありません
DEFINE_LOG_CATEGORY_STATIC(LogCategoryName, Warning, All);

UE_LOG(LogCategoryName, Warning, TEXT("%s: Hello!"), __FUNCTIONW__);
複数ファイル用カテゴリ
// (プロジェクト名).h に書きます
DECLARE_LOG_CATEGORY_EXTERN(LogCategoryName, Warning, All);

// (プロジェクト名).cpp に書きます
DEFINE_LOG_CATEGORY(LogCategoryName);

// ログを出すところで
UE_LOG(LogCategoryName, Warning, TEXT("%s: Hello!"), __FUNCTIONW__);
ログレベルの種類
レベル 備考
Fatal コンソールにログを出力すると同時にゲームをクラッシュさせます
(試しにコンストラクタに書いてみたらエディタの方がクラッシュしました…)
Error ログテキストは赤色
Warning ログテキストは黄
Display ログテキストは灰色
Log Log 以下のレベルのメッセージはコンソールには出力されず、ログファイルにのみ記録されます
(とドキュメントからは読み取れますが、自分の環境では Log までは Output Log に出力され、Verbose 以下から表示が消えました)
Verbose
VeryVerbose
All 実態は VeryVerbose です(All = VeryVerbose と定義されています)

画面ログ出力

GEngine->AddOnScreenDebugMessage(id, 表示時間, テキスト色, 表示するテキスト) を使用します。
GEngine は利用できない可能性があるので、AddOnScreenDebugMessage を呼び出す前にその有無をチェックする必要があります。マクロを書いておくと楽です。

#include "EngineGlobals.h"
#include "Runtime/Engine/Classes/Engine/Engine.h"

// 第1引数に -1 以外の数値を渡すと、前にその数値を使って出力したログを上書きします。-1 の場合は常に上書きせずログが追加されます。
// 第2引数は表示する時間(秒)
#define DISPLAY_LOG(fmt, ...) if (GEngine) GEngine->AddOnScreenDebugMessage(-1, 5.f, FColor::Red, FString::Printf(TEXT(fmt), __VA_ARGS__));

DISPLAY_LOG("%s: Hello at line %d", __FUNCTIONW__, __LINE__);

参考