Case式を知って衝撃を受けた話

こんな記事を書きたくなった訳

最近「達人に学ぶSQL徹底指南書」のKindle版を買って読み始めているのですが、一番最初の章の一番最初の項目で早速目から鱗で電流が走りました。

これまで半年ほどPHPMySQLを使用して業務を行っていたのですが、私の先生は業務で先輩方が書いた既存のコードでした。
そろそろSQLも中級者レベルになったかなと高を括ってこんな本に手を出してみたら、全然知らないことだらけで「先生が教えてくれなかった」なんてゆとり名言も言いたくなるのですよ。
先生は業務で書かれたコードではなく本やネットであることを新しく学び、少しだけ成長した私はこの気持ちを共有したくなったのでこの記事を書くに至りました。

Case式とは

条件分岐です。
ただ、C系列のifステートメントではなく、どちらかというと条件演算子に当たるようなものです。

if (result) { isSuccess = true; }// これではなく
bool isSuccess = result ? true : false;// これ

衝撃を受けたCase式の使い方

垂直でデータを保持しているものを水平に展開することができます。
PHPでこういうデータの整形は頻繁にしてたけど、少しSQLに詳しかったらPHPでいろいろする必要なかったのかと思うと悲しくなります。 

-- テーブル定義
CREATE TABLE enemy_subskills(
    id integer, 
    skill_id integer, 
    subskill_type integer, 
    subskill_level integer);
    
-- データ挿入
INSERT INTO enemy_subskills(id, skill_id, subskill_type, subskill_level) VALUES
(1, 1, 1, 10),
(2, 1, 2, 20),
(3, 2, 1, 10),
(4, 2, 4, 20),
(5, 3, 3, 10),
(6, 3, 4, 20);

-- SQL実行
SELECT
    -- SUMで行をまとめる
    -- subskill_typeが1のとき、subskill_levelをsubskill1_nameカラムに入れる
    SUM(CASE WHEN subskill_type=1 THEN subskill_level ELSE 0 END) AS subskill1_name,
    -- subskill_typeが2のとき、subskill_levelをsubskill2_nameカラムに入れる
    SUM(CASE WHEN subskill_type=2 THEN subskill_level ELSE 0 END) AS subskill2_name,
    -- subskill_typeが3のとき、subskill_levelをsubskill3_nameカラムに入れる
    SUM(CASE WHEN subskill_type=3 THEN subskill_level ELSE 0 END) AS subskill3_name,
    -- subskill_typeが4のとき、subskill_levelをsubskill4_nameカラムに入れる
    SUM(CASE WHEN subskill_type=4 THEN subskill_level ELSE 0 END) AS subskill4_name
FROM enemy_subskills
-- 行をまとめる単位
GROUP BY skill_id;

-- 結果
-- 10   20    0    0
-- 10    0    0   20
--  0    0   10   20

まとめ

中級者だと思っていたらまだまだ初心者だったという話でした。
とりあえずこの手の本を数冊読んで「そこそこ初心者」くらいの称号を手に入れようと思います。
実務でやってても「こなしかた」は覚えていくのに技術は一向に増えていっていない気がするのは気のせいなのか...。
こなすのもスキルではあるけれども。

C++で自分が作ったポーンが使用されるように設定しようぜ!

前提

はじめに

今回C++でポーンを作成し、ゲーム再生時にそのポーンが配置されるように設定していきます。 どのPawnを生成するかについてはGameModeで設定を行い、どのGameModeを使用するかについてはWorldSettingsで設定を行います。 そのため、今回はPawn、GameMode、WorldSettingsを作成していきます。

Pawn

画面上に配置されるオブジェクトのクラスです。 通常目に見えるようなオブジェクトである場合が多いですが、今回はメッシュの設定を行っていないため、目に見えないポーンオブジェクトになっています。

GameMode

ゲームのルールの定義などを管理するクラスです。 このクラスはデフォルトで生成されているため、今回はそれを使用していきます。

WorldSettings

レベルごとに設定したいパラメータはここで保管します。 「設定」→「ワールド設定」で開く「ワールド設定」タブで表示できます。

クラスの新規作成

それでは、MyPawnクラスの作成とMyWorldSettingsクラスの作成を行います。

MyPawnクラスの作成

コンテンツブラウザでC++クラスを開き、右クリックで「新規C++クラス」を選択

f:id:u16kuma:20160515105332p:plain

MyPawnクラスの親には「ポーン」を選択

f:id:u16kuma:20160515105330p:plain

クラス名に「MyPawn」と入力して「次へ」

f:id:u16kuma:20160515105329p:plain

コンテンツブラウザにMyPawnが表示されていたら成功。 もし表示されていない場合は、UnrealEditorの「ファイル」→「Visual Studio プロジェクトを更新」を押して「再起動」してみてください。

MyWorldSettingsクラスの作成

MyPawnクラスと親クラスの選択以外同様の手順で作成します。 MyWorldSettingsクラスの親クラスにはWorldSettingsクラスを選択(全てのクラスを表示にチェックを入れることで表示される)

作成したMyWorldSettingsを読み込む

作成したMyWorldSettingsクラスは作成しただけではもちろん読み込まれることはありません。

「設定」→「プロジェクト設定」→エンジンの「基本設定」→「Default Classes」→「World Settings Class」のプルダウンメニューから作成した「MyWorldSettings」を選択。

f:id:u16kuma:20160515105337p:plain

以上で設定が完了しましたので、待ちに待ったC++をゴリゴリ書いていきましょう!

C++のコードを打ち込んでいこう!

とりあえず何も考えずに手で打ち込んでいきましょう。 手で入力していくのは非常にめんどくさいのですが、少なからず理解につながるので頑張っていきましょう。

今回作成、変更したソースコード一覧

  • MyPawn.h <新規作成>
  • MyPawn.cpp <新規作成>
  • MyWorldSettings.h <新規作成>
  • MyWorldSettings.cpp <新規作成>
  • SetupEnvGameMode.h <変更>
  • SetupEnvGameMode.cpp <変更>

MyPawn.h

  • デフォルトのコードをそのまま使用
#pragma once

#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class SETUPENV_API AMyPawn : public APawn
{
    GENERATED_BODY()

public:
    AMyPawn();
    virtual void BeginPlay() override;
    virtual void Tick( float DeltaSeconds ) override;
    virtual void SetupPlayerInputComponent(
        class UInputComponent* InputComponent) override;
};

MyPawn.cpp

  • デフォルトのコードをそのまま使用
#include "SetupEnv.h"
#include "MyPawn.h"

AMyPawn::AMyPawn()
{
    PrimaryActorTick.bCanEverTick = true;
}

void AMyPawn::BeginPlay()
{
    Super::BeginPlay();
}

void AMyPawn::Tick( float DeltaTime )
{
    Super::Tick( DeltaTime );
}

void AMyPawn::SetupPlayerInputComponent(
    class UInputComponent* InputComponent)
{
    Super::SetupPlayerInputComponent(InputComponent);
}

MyWorldSettings.h

#pragma once

#include "GameFramework/WorldSettings.h"
#include "MyWorldSettings.generated.h"

UCLASS()
class SETUPENV_API AMyWorldSettings : public AWorldSettings
{
    GENERATED_BODY()
    
    // コンストラクタの宣言を追加
public:
    AMyWorldSettings();
};

MyWorldSettings.cpp

  • GameModeのヘッダファイルのインクルード
  • DefaultGameModeの設定
#include "SetupEnv.h"
#include "MyWorldSettings.h"
#include "SetupEnvGameMode.h"

AMyWorldSettings::AMyWorldSettings()
{
    // 作成したGameModeを設定
    DefaultGameMode = ASetupEnvGameMode::StaticClass();
}

SetupEnvGameMode.h

#pragma once

#include "GameFramework/GameMode.h"
#include "SetupEnvGameMode.generated.h"

UCLASS()
class SETUPENV_API ASetupEnvGameMode : public AGameMode
{
    GENERATED_BODY()
    
    // コンストラクタの宣言を追加
public:
    ASetupEnvGameMode();
    
};

SetupEnvGameMode.cpp

  • 作成したポーンクラスのヘッダファイルを追加
  • DefaultPawnClassの設定
#include "SetupEnv.h"
#include "SetupEnvGameMode.h"

// 作成したポーンクラスのヘッダファイルをインクルード
#include "MyPawn.h"

ASetupEnvGameMode::ASetupEnvGameMode()
{
    // デフォルト値に作成したポーンクラスを設定
    DefaultPawnClass = AMyPawn::StaticClass();
}

ソースコードのポイント

以下の2点で無事作成したポーンクラスが生成されるようになっているはずです。

  • MyWorldSettings.cppのDefaultGameModeにGameModeの型情報を渡している
  • SetupEnvGameMode.cppのDefaultPawnClassにポーンの型情報を渡している

実行してアウトライナを見てみると、無事作成したMyPawnが生成されていることがわかります。

f:id:u16kuma:20160515105328p:plain

そもそもなぜUE4でC++したいのか?

はじめに

あなたはなぜUE4のC++でゲームを作りたいのですか。
Blueprintではだめですか。
Unityではいけないのですか。

UE4&C++という選択肢は非常にクールです。
しかし、Unity&C#やUE4&Blueprintなどと比べ、とっつきやすさや開発速度が劣ります。
そのため、ゲームを作り上げる楽しさの部分においては、その他の選択肢と比べ劣っているという評価を下さざるを得ません。
UE4&C++という最高にクールな世界を覗く前にUE4&C++を利用する目的を確認してみましょう。

1-1. UnityではなくUE4でなければならない理由

それではUE4でなければならない理由について考えてみましょう。

  • C++を愛しているのでUE4しか選択肢がない
  • 3Dの最先端の技術に触れたい
  • 今後のトレンドはUE4である
  • 圧倒的美麗映像!
  • デザイナーがこれ使えってうるさい
  • etc...

1-2. BlueprintではなくC++でなければならない理由

  • 今までC++の開発に従事していた場合、今までのスキルを活かすことができる
  • Blueprintで主に開発しているが、どうしても速度が必要な場所がある
  • Blueprintでは使用できない機能を使いたい
  • ロジックはコードベースで管理したい
  • なにか問題があったときのチューニングがしやすい
  • 中~大規模開発でUE4を使用する
  • スマートフォンなどの端末の制約で使わざるを得ない
  • C++で書いたほうが楽しいイケメンプログラマである
  • C++で書いたほうが楽しい気持ち悪いただのオタクであるwwww
  • 難易度の高い方にロマンを感じる
  • C++俺の嫁
  • etc...

2. UE4ゲーム開発でC++が担う役割

UE4でロジックを組んでいく場合、BlueprintとC++を使うことができるためいくつか選択肢があります。

  • すべてBlueprintで実装する
  • Blueprintで使えない機能をBlueprintで使えるようにするプラグインだけC++で書く
  • Blueprintで実装すると速度的にボトルネックになってしまう部分をC++で書く
  • プログラマがロジックをC++で書き、ゲームデザイナーがBlueprintで実装する
  • 重要なゲームロジックはC++で書き、細かい部分についてはBlueprintで実装する
  • すべてのロジックはC++で書き、Blueprintをデータのコンテナとして活用する
  • すべてC++で書く

3. まとめ

ここまで読んでいる方はもちろん「今後のトレンドはUE4である」と思い「C++で書いたほうが楽しい気持ち悪いただのオタク」な方だと思います。
しかし、UE4を使う以上、C++を使っていったほうが良い場面や、Blueprintを使っていったほうが良い場面というのは必ずあります。
そのため、C++だけではなくBlueprintも毛嫌いせず学んでいけるとよいですね(自己暗示)

C++プロジェクトを作成してUEの世界を堪能しようぜ!

対象

C++初級者以上である人 UE4の読み方が「うえよん」ではないことを知っている人

環境

Windows10 Unreal Engine 4.11.2 Visual Studio 2015 Community

C++プロジェクトを作成しよう!

EPIC GAMES LAUNCHERを起動する。

f:id:u16kuma:20160513230344j:plain

開いたウィンドウの左上に「起動」ボタンがあるので押してUnrealEngineを立ち上げる。

f:id:u16kuma:20160513230416p:plain

プロジェクトブラウザが表示される

f:id:u16kuma:20160513230440p:plain

新規プロジェクトタブを選択し、「C++」を選択する
※ここでC++を設定しなくてもC++を書いていくことは可能だが、ここで設定しておくと楽なので推奨

f:id:u16kuma:20160513230501p:plain

ウィンドウ下部分の設定はお好みで設定して「プロジェクトを作成」ボタンを押すことでプロジェクトを作成することができる

f:id:u16kuma:20160513230542p:plain

こんな感じのウィンドウが開けば無事プロジェクトの作成ができている

f:id:u16kuma:20160513230654p:plain

作成されたプロジェクトに自動的に追加されたクラスを確認する
ウィンドウの下部分に表示されているコンテンツブラウザタブのフィルタの左に表示されているボタンを押すことで、ツリー表示されるようになりC++クラス階層も表示される

f:id:u16kuma:20160513230714p:plain

C++プロジェクトを作成したデフォルトの状態では「プロジェクト名GameMode」(プロジェクト名はここではMyProject)というクラスが作成されていることが確認できる

f:id:u16kuma:20160513230736p:plain

できる!...からってするなよ!PHPの連想配列乱用!

※以下ジョークを含んでおり、間違った覚え方をしても一切責任を負いません。

僕は今半年ほどPHPでゲームのサーバーのプログラムを書いていますが、まだまだ新米なのでプロジェクトのコードという達人のプログラムを読みながら日々勉強している身です。

達人のコードを見て学んだテクニックを共有したいと思います。 連想配列をあたかもクラスであるかのように使う高等テクによって、定義情報をもデータとして扱うことに成功しているコードに出会いました。

これが↓

class User_table
{
    private $user_id = 0;
    private $user_name = '';
    
    public function __construct($user_id, $user_name)
    {
        $this->user_id = $user_id;
        $this->user_name = $user_name;
    }
}

$user = new User_table(76213846, 'まさる');

こうなる↓

$user = [
    'user_id' => 76213846,
    'user_name' => 'まさる'
];

脅威の行数ですよね!

これのメリットとしては、

  • 12行で書いていたものが一時的にたった4行で書けるようになる
  • 定義情報をデータと一緒に生成するので使いまわすときにコピペコーディングが可能になり、雪だるま式にコード量を増やすことができる
  • すべての要素がPublicになるため、コードが複雑になったときにいろいろなことを考えながらコーディングすることができる
  • 超マニアックな条件の時なら誰にも気づかれずunsetして要素を消したり追加したりでき、後々楽しいデバッグ作業ができる
  • 実行時の条件によって要素を付け替えることができ、誰にも全体像を悟られることがない
  • IDEの入力補完が一切機能しなくなり、どんな要素があるのかを調べるために無駄に検索能力が向上する

実務で使うと文字通り脅威になると思いますのでぜひ!