はじめに
本記事はかの有名なDirectX APIを簡易化したライブラリ「DXライブラリ」を使用して、現在流行のLive2Dモデルを描画し、さらにモーションを制御する簡単なやり方を紹介します。
目次
Visual Studioの準備
- Microsoft公式サイトからVisual Studio Communityをダウンロードし、インストール
https://visualstudio.microsoft.com/ja/downloads/
(IDEは何でもOKですが、今回はVisual Studioでご紹介します)
初期セットアップする時に必ず入れて欲しいのは「ユニバーサルWindowsプラットフォーム開発」
DXライブラリの導入
- DXライブラリの公式ページからSDKをダウンロード
https://dxlib.xsrv.jp/dxdload.html
Live2D Cubism 4 SDKとLive2Dモデルの導入
-
DXライブラリの公式ページも導入手順掲載してます
https://dxlib.xsrv.jp/use/dxuse_live2D_cubism4_windows.html#R1 -
DXライブラリ Windows版の Live2D 関係の関数を使うには、Live2D Cubism 4 SDK for Native の中にあるLive2DCubismCore.dll が必要なので、以下のダウンロードページから Cubism 4 SDK for Native をダウンロードしてください
https://www.live2d.com/en/sdk/about/
- サンプルデータをダウンロード
元々私が使用するモデルは当時無料配布だった「ミアラ」だが、この記事を執筆した現在は有料になりましたので、他の無料モデルを使用してください。
https://www.live2d.com/learn/sample/
- Visual Studioの設定
▼DXライブラリSDKのパス設定(すべての構成に設定)
パスは相対パス、絶対パスどちらでも構いません
▼リンカーのシステムを「Windows(/SUBSYSTEM:WINDOWS)に設定」
▼Live2D Cubism 4 SDKをプロジェクトのディレクトリ下に入れる(プロジェクトディレクトリ以外のローカル外部でも良いですが、ファイルをどこかにクローンする時に参照がずれて、また再設定しないといけない)
コーディング
- まずはLive2Dモデルを読み込む準備をします
#pragma once
#include"DxLib.h"
class Live2D
{
public:
Live2D(int modelHandle);
~Live2D();
void Initialize();
void Load(const TCHAR *filePath);
void Update(const TCHAR* motion);
void DrawBegin();
void DrawModel();
void DrawEnd();
void DeleteModel();
private:
int ModelHandle;
};
#include"Live2D.h"
Live2D::Live2D(int modelHandle)
:ModelHandle(modelHandle)
{
}
Live2D::~Live2D()
{
}
void Live2D::Initialize()
{
#ifdef _WIN64
Live2D_SetCubism4CoreDLLPath(L"../CubismSdkForNative-4-r.1/Core/dll/windows/x86_64/Live2DCubismCore.dll");
#else
Live2D_SetCubism4CoreDLLPath(L"../CubismSdkForNative-4-r.1/Core/dll/windows/x86/Live2DCubismCore.dll");
#endif
}
void Live2D::Load(const TCHAR* filePath)
{
// Live2Dモデルの読み込み
ModelHandle = Live2D_LoadModel(filePath);
}
void Live2D::Update(const TCHAR* motion)
{
// モーション再生が終了していたらアイドリングモーションをランダムで再生
if (Live2D_Model_IsMotionFinished(ModelHandle) == TRUE)
{
Live2D_Model_StartMotion(ModelHandle, motion, GetRand(8));
}
// モデルの状態を60分の1秒分進める
Live2D_Model_Update(ModelHandle, 1 / 60.0f);
}
void Live2D::DrawBegin()
{
// Live2D描画の開始
Live2D_RenderBegin();
}
void Live2D::DrawModel()
{
// モデルの描画
Live2D_Model_Draw(ModelHandle);
}
void Live2D::DrawEnd()
{
// Live2D描画の終了
Live2D_RenderEnd();
}
void Live2D::DeleteModel()
{
// Live2D モデルの削除
Live2D_DeleteModel(ModelHandle);
}
- おまけに入力系のクラスも書いておきます
#pragma once
#include"DxLib.h"
class Input
{
public:
static char currentKey[256];
static char previousKey[256];
static int mousePosX, mousePosY, mouseLeftButt, mouseRightButt, mouseMidButt;
public:
static void Mouse(int*, int*);
static int MouseLeftButton();
static int MouseRightButton();
static int MouseMiddleButton();
static int Key(int key);
static bool KeyTrigger(int key);
static void Update();
static void Draw();
};
#include"Input.h"
int Input::mousePosX = 0;
int Input::mousePosY = 0;
int Input::mouseLeftButt = 0;
int Input::mouseRightButt = 0;
int Input::mouseMidButt = 0;
char Input::currentKey[256] = { 0 };
char Input::previousKey[256] = { 0 };
void Input::Update()
{
GetMousePoint(&mousePosX, &mousePosY);
if ((GetMouseInput() & MOUSE_INPUT_LEFT) != 0) mouseLeftButt++;
else mouseLeftButt = 0;
if ((GetMouseInput() & MOUSE_INPUT_RIGHT) != 0) mouseRightButt++;
else mouseRightButt = 0;
if ((GetMouseInput() & MOUSE_INPUT_MIDDLE) != 0) mouseMidButt++;
else mouseMidButt = 0;
memcpy(previousKey, currentKey, sizeof(previousKey));
GetHitKeyStateAll(currentKey);
}
void Input::Mouse(int* x, int* y)
{
*x = mousePosX;
*y = mousePosY;
}
int Input::MouseLeftButton() { return mouseLeftButt; }
int Input::MouseRightButton() { return mouseRightButt; }
int Input::MouseMiddleButton() { return mouseMidButt; }
int Input::Key(int key) { return currentKey[key]; }
bool Input::KeyTrigger(int key) { return !previousKey[key] && currentKey[key]; }
void Input::Draw() {}
- 次にゲームの環境を整う
#pragma once
#include"DxLib.h"
class Game
{
public:
Game();
~Game();
void Initialize();
void Load();
void Update();
void Draw();
public:
int LoadTexture(TCHAR* fileName)
{
int tex = LoadGraph(fileName);
if (tex == -1)
{
MessageBox(NULL, L"画像の読み込みに失敗しました", ERROR, MB_OK);
return 0;
}
};
private:
int texture;
float texturePosX;
float texturePosY;
bool controllSwitch;
};
#include"Game.h"
#include"Input.h"
Game::Game()
{
this->Initialize();
}
Game::~Game()
{
}
void Game::Initialize()
{
texture = NULL;
texturePosX = 600;
texturePosY = 400;
controllSwitch = false;
}
void Game::Load()
{
}
void Game::Update()
{
if (!controllSwitch)
{
texturePosX = 600;
texturePosY = 400;
}
else
{
texturePosX = 800;
texturePosY = 600;
}
if (Input::Key(KEY_INPUT_SPACE) == 1)
{
controllSwitch = !controllSwitch;
}
}
void Game::Draw()
{
}
- 最後にモデルを描画し、スペースキーで動作変えましょう
#include"Game.h"
#include"Input.h"
#include"Live2D.h"
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow)
{
// ウィンドウモードに設定
ChangeWindowMode(TRUE);
SetMainWindowText(L"Live2D Test Program");
// 画面解像度を設定
SetGraphMode(1280, 720, 0);
// ウィンドウサイズを手動では変更できず、
// かつウィンドウサイズに合わせて拡大できないようにする
SetWindowSizeChangeEnableFlag(FALSE, FALSE);
bool motionChange = false;
int live2DHandle = 0;
Live2D* live2D = new Live2D(live2DHandle);
live2D->Initialize();
// DXライブラリ初期化処理
if (DxLib_Init() == -1) return -1;
Game game;
game.Initialize();
game.Load();
live2D->Load(L"../Assets/miara_pro_jp/runtime/miara_pro_t04.model3.json");
// 描画先を裏画面に変更
SetDrawScreen(DX_SCREEN_BACK);
// メインループ
while (ScreenFlip() == 0 && ProcessMessage() == 0 && ClearDrawScreen() == 0)
{
Input::Update();
game.Update();
game.Draw();
if (Input::KeyTrigger(KEY_INPUT_SPACE))
{
motionChange = !motionChange;
}
if (!motionChange)
{
live2D->Update(L"Idle");
}
else
{
live2D->Update(L"Flick");
}
live2D->DrawBegin();
live2D->DrawModel();
live2D->DrawEnd();
if (CheckHitKey(KEY_INPUT_ESCAPE) != 0) break;
}
live2D->DeleteModel();
delete live2D;
// DXライブラリ使用の終了処理
DxLib_End();
// ソフトの終了
return 0;
}
- Live2Dモデルモーションに関してですが、ご自身がダウンロードしたサンプルデータのなかの「runtime」フォルダの中にある「OOO.model3.json」のような名前のファイルから見えます。
▲私の場合IdleとFlickを切り替えて使用してます