Akatsuki Hackers Lab | 株式会社アカツキ(Akatsuki Inc.)

Akatsuki Hackers Labは株式会社アカツキゲームスが運営しています。

動画を集めて、描いて、話す。チーム向け動画レビューツール VideoReview

この記事は、Akatsuki Games Advent Calendar 2025 25日目の記事です

初めまして、アカツキゲームスの有田です
アドベントカレンダーの最終日を枠を頂けましたので、
社内で開発してきた動画レビューツール「VideoReview」をOSSとして公開したので紹介をしたいと思います

動画レビューを行うとき、次のような困りごとを感じたことはないでしょうか?

  • 大量の動画がクラウドに置かれているだけで整理できない 
  • コメントと動画(時間・フレーム)が紐付かない
  • 修正のやり取りや履歴が追えなくなる

VideoReviewは、動画を集約しコメントやお絵描きでやり取りできる、チーム向けの動画レビューツールですSNS のような感覚で、「このカットどう?」「ここ直したい」といったレビューをテンポよく回せる環境を目指して作りました

「探す・把握する・確認する」をひとつの流れに

探したい動画に、すぐ辿り着ける高速検索

レビュー対象の動画が増えても、キーワード検索で瞬時に絞り込みができます
ボス名・チャプター名・用途など、あいまいな記憶でも目的の動画にすぐアクセスでき、「探す時間」をほぼゼロにできます

レビュー対象をツリー構造で一元管理

動画はチャプターや用途ごとにツリー構造で整理され、全体の構成を俯瞰しながらレビュー対象を選べます
どの動画がどの文脈に属しているのかが直感的に分かり、レビューの抜け漏れを防ぎます

新着コメントが一目で分かる、迷わないレビュー導線

新しいコメントが付いた動画には「New」アイコンが表示され、次に確認すべき動画がひと目で分かります
コメント → 動画確認 → 次の動画、という流れが自然につながり、レビュー作業を止めずに進められます

 

レビューの流れを止めない、外部ツールとのシームレスな連携

コメントをSlackへ同時共有し、レビューの拾い忘れ防止

動画へのコメントを、そのままSlackへ同時に共有できます
コメント内容に加えて、該当時刻・スクリーンショット・動画への共有URLを送信することで、Slack上でもレビューを始められます

  

コメントからタスクチケットを作成し、確実にトラッキング

コメントを起点にAtlassian社のJiraチケットを作成でき、指摘事項や修正タスクをそのままワークフローに乗せられます
チケットには動画へのリンクが含まれるため、「どのシーンの話か」を迷わず確認でき、レビューとタスク管理が自然につながります

動画に直接描き込み、伝えたいポイントを明確に

動画のフレーム上に直接描き込むことで、言葉だけでは伝えにくい位置・形・動きのニュアンスを、そのまま共有できます
コメントに視覚的な情報を加えることで、レビューの意図がより正確に、素早く相手に伝わります

自動化フローに組み込みやすい動画アップロードAPI

VideoReviewでは、動画アップロードをREST APIとして公開しています
CI・バッチ処理・ツール連携などから直接動画を登録でき、レビュー工程を既存の制作フローに容易に組み込むことが可能になっています

オンプレを前提に、必要に応じてクラウドを選べる構成

VideoReviewはオンプレミス環境での運用を前提に設計しています
社内ネットワーク内で動画を完結させることで、機密性の高い映像素材を外部に出さずにレビューを行えます

一方で、運用やチーム構成に応じて、AWS S3 をストレージとして選択することも可能です
オンプレ・クラウドを用途に応じて使い分けることで、セキュリティ・導入コスト・運用負荷のバランスを柔軟に取れます

試して見たい!という方

ローカルで簡単に起動できるDocker環境も用意しています!
手順:

  1. リポジトリをクローン:git clone https://github.com/KirisameMarisa/video-review.git
  2. ディレクトリへ移動:cd video-review
  3. 依存パッケージのインストール:npm install
  4. Dockerコンテナの起動:docker compose -d --build
  5. ブラウザでアクセス:http://localhost:3438

今後の展望

描画機能の強化:

現状の手書き注釈に加え、矩形・矢印・文字追加などの図形ツールを実装して、指示を分かりやすくします

動画検索強化:

コメント投稿の範囲から、投稿者から、タグからなど様々な角度から動画の検索性をあげ更新情報を見逃さないように改善します

最後に

VideoReviewは、 実際の制作チーム内で日常的に使われながら改善を続けているツールです

たとえば、
自動テストで撮影したスキットシーンの動画をアップロードし、レビューや過去動画のバックアップ用途として利用されていますまた、多言語チェックにおける動画の集約先としても使われています

現場で使う中で出てきた課題や要望を取り込みながら、
レビュー作業を少しずつ楽にすることを目指して育てています

まだ生まれたばかりではあるものの、沢山のフィードバックをいただいて成長させていきたいと思っているので、Issue や PR などのフィードバックはいつでも歓迎です

強化学習ライブラリGymnasiumを使ってみた

こんにちは! アカツキゲームス クライアントエンジニアのSuです。
この記事は Akatsuki Advent Calendar 2025 24日目の記事です。メリークリスマス!

はじめに

学生時代に強化学習の研究を少したので、久しぶりに強化学習をやりたいな〜の気持ちで本記事を書きました。今回はGymnasiumというPythonライブラリを使用した経験を紹介したいと思います!

強化学習とは?

強化学習(Reinforcement Learning)は簡単にいうと、エージェントが環境の中でアクションと実行し、その結果から学習し、エージェントがよりいい結果を出力できるようにアクションを選択する方法を最適化することです。

エージェントがアクションを行い、環境の変化を見て学習する
(Gymnasium-Basic Usageより)

例えば、レーシングゲームで自動運転のエージェントを作るとしたら:

  • Action: 加速、減速、方向を変わる
  • Observation: ゴールまでの距離、壁の方向と距離、経過時間...
  • Reward: 走行した距離、壁にぶつかる回数...

エージェントがアクションを決めるアルゴリズムは強化学習分野の重要トピックです。Q-Learning、PPO、SAC、最近でたDAPOなど、アルゴリズムの進化速度はとても早いです。この記事は深掘りしませんが、興味がありましたらぜひ調べてみてください!

Gymnasiumとは?

2021年にOpenAI Gym library の開発チームが Gymnasium に移転しました。
強化学習環境開発・訓練に特化した Python ライブラリです。

宇宙船を着陸させるタスクを学習させる環境は簡単に作れる
(https://gymnasium.farama.org/ より)

今回は公式ドキュメントにある例のマップを改造して、そのマップ上にプレイヤー、ゴール、トラップがあります。プレイヤーを動かして、トラップをできるだけ踏まないように、終点まで移動するタスクをAIに学習させ、その学習結果を評価したい思います。

環境の作成

まず、Gymnasium環境クラス gymnasium.Env 3パートで構成されます:初期化、更新、描画です。それと下記の情報はコンストラクタで定義します:

初期化

処理は reset() に入れます。環境を初期状態にする処理です。最初の Observation を返します。処理は 1 episode(タスク開始〜終了)ごとに実行されます。今回はプレイヤー、ゴール、トラップの位置をランダムに生成する処理を書きました。Observation はプレイヤー、ゴール、トラップの位置にします。

更新

実行するActionを step() 関数に渡して、環境はどう変化するかとこの行動はいいかどうかを返す。今回の Action は移動方向で、関数内にはプレイヤーの位置を更新、ゴールについたら点数を与える、トラップを踏んだら減点にしました。

描画

render() 関数に定義されます。今回は青い丸がプレイヤー、赤い丸がゴール、黒い丸がトラップ、それとマスを PyGame ライブラリで描画しました。

パッケージ

環境できたら、利用しやすくためパッケージ化します。パッケージ化すると、便利な Wrapper が使えます。Observation を他の形式に変更する(例えば、プレイヤーとゴールの位置ではなく、その相対位置に変更)にはよく使いします。

エージェント

Observation を見て、どういう Action を取るかを決めるルールです。Q-Learning、PPO、SAC というアルゴリズムの部分です。自分で実装するのもいいし、公式おすすめのライブラリ Stable-Baselines3 を使うと便利です。パッケージされた Gym 環境があれば下記のように簡単にモデル作れます。複数環境で並行学習もできます。

学習

環境から返した点数で今回選んだActionを評価して、次同じObservationが来た時に同じActionを選ぶかどうか、アルゴリズムを修正します。Stable-Baselines3のドキュメントを参考すれば各パラメターの意味が書かれていますので、ここは割愛します。

ログ

Stable-Baselines3 は TensorBoard 出力できます。TensorBoard を使用してログを出力できます。学習の過程を図で表示できます。学習足りているかどうかの確認やパラメター調整する際にかなり参考になりました。

tensorBoard

訓練結果を評価

Stable-Baselines3で学習したモデルを保存できます。その保存したモデルをロードすれば、与えた Observation に対して Action を出力します。

<gist>

よし!最強のAIを作ったので、早速モデルを試すぞ!
あれ、なんか動かないだけど......

移動しない

最初の問題は、壁にぶつけたら移動しなくなった問題です。これを解決するために、「前回と同じ位置なら減点」するRewardを追加してみましたが...

ずっと隣のマスに行ったりきったり

「同じ場所じゃなければいい」とエージェントもその抜け道を見つけて、ずっと同じマスに行ったりきったりしていました...

AIちゃんをちゃんと動かせるため、「すでに経過した場所に移動すると減点する!」ように Reward 修正しました。

色々調整した結果、それっぽい動きになった!
時々トラップに踏むですが、避けるように頑張ってるを感じてます。

より広いマップ

15x15のマップで改めて学習させました!10x10より学習時間2倍かかったが、成果は悪くないと思います。

Github Repo

今回使用したコードをGitHubにアップロードしたので、興味がある方はぜひ触ってみてください!

github.com

最後に

調整してAIをどんどん成長させるのも楽しいですが、適切なRewardを設定するのが難しいと実感しました。それと、個人的な感想ですが、Actionが連続スペースなタスクの方が得意なイメージがあります。となるとActionの設計も重要になってきますね。もっと複雑なタスクをやらせて欲しくなった!

AIだけではなく、強化学習の概念とアルゴリズムはゲーム開発中にも活用できると思います。勉強になりました!

明日は25日!クリスマス当日に軍曹が素敵な記事を公開する予定です。みなさんぜひ読んでみてください〜!

「一番メモリを消費するキャラクターは誰?」に即答したい。Unity アセットの静的解析と自動通知で実現したアセット肥大化を未然に防ぐ仕組み

この記事は Akatsuki Games Advent Calendar 2025 22日目の記事です。

はじめに

クライアントエンジニアの渡邊です。ゲームの新規機能開発やプロジェクト内部向けツールの製作を行なっています。

概要

運用型ゲームではキャラクターが増え続けますが、キャラクターのアセットが端末のメモリをどれくらい使用するかは常に気になる問題です。

「今、最もメモリを消費しているキャラクターは誰なのか?」

「複数キャラクターを同時に読み込んだ時、ゲームアプリがクラッシュしてしまうことはないだろうか?」

こうした問いに答えるために、私は、キャラクターのモデル、アイコンやサムネイルといった画像、VFX、サウンドデータなど複数の要素から構成されるキャラクターのアセットのメモリ上のサイズを推定して集計するツールと、メモリサイズ推定値が大きいキャラクターをランキング化して Slack に通知する仕組みを開発しました。

完成したツールの Editor Window
Slack へのランキング通知

本記事では、Unity エディタ上での集計ロジックの簡単な解説から、自動通知の仕組みまでを解説します。このツールは単なる計測に留まらず、アセット肥大化を早期に検知することができたり、アーティストさんへアセット最適化を促進したりと、当初の単なる「キャラクターのメモリ使用量測定」の枠を超えた変化を生み出すことができました。

続きを読む

Redashで見栄えを良くしよう

この記事は Akatsuki Games Advent Calendar 2025 16日目の記事です。

はじめに

サーバエンジニアの井出です。今年新卒で入社して、主に新規機能開発を行っています。また自分自身のサブタスクとして、チームのデータ分析も行っています。本日は自分がデータ分析のタスクの中で、「これ良いTipsだな」って思ったことを書かせていただきます!

注意書き

本記事では、実際にタスクを進める中で学んだ事を記事にしています。そのため、一部内容を変更している箇所があります。伝えたい内容に影響はないのでご了承ください...。

概要

データ分析のタスクは、年間の売上分析、使用キャラランキングから、お問い合わせ対応時の調査まで、多岐にわたります。これらの多様なデータ分析タスクに対応するため、エンジニアやプランナーなど職種を問わず誰でもデータにアクセスし、クエリを叩いて調査できるようにする環境を整えられるよう、BIツールとしてRedashを導入しています。

Redashとは

Redashとは、ブラウザ上でSQLなどのクエリを実行し、結果をグラフや表として可視化できるオープンソースのBI(ビジネスインテリジェンス)ツールです。

ある日...

分析タスクとして「あるプレイヤーの戦闘ログから、どのキャラクターがどのスキルを使用したかを調べてほしい」という依頼が来ました。

そのため、BigQueryで以下のようなクエリを作成して調査を始めました(内容は少し省略しています)。

SELECT
  player_id,
  skills,
  timestamp
FROM
  <戦闘ログのテーブル>
WHERE
  player_id = <player_id>
ORDER BY
  timestamp DESC

実際に上記クエリを実行すると、以下のような実行結果を得られました。

上記の結果から、「最近の戦闘で、キャラクターIDが2351のキャラクターは200331000のスキルを発動した/キャラクターIDが7128のキャラクターは200469000,200183000のスキルを発動した...」などのことがわかります。

Redash上でクエリ作成して実行した結果

上記のクエリをRedashで作成し、実行すると以下のようになってしまいます。

skillsカラムのフィールド情報が崩れてしまっています。 これでは「skillsカラムが何を表しているのか」がぱっと見で分からない状態です。

原因調査

なぜ崩れてしまったか調べていると、公式ドキュメントの[Table Visualization Options] → [Formatting Columns]で以下のように説明がありました。

Redash is sensitive to the data types that are common to most databases: text, numbers, dates and booleans. But it also has special support for non-standard column types like JSON documents, images, and links.

上記の文章から、Redashは、データベースから返ってくる型情報をそのまま表示させるが、型が不明確なRECORD型は「とりあえずテキスト」として扱われてしまいそうな事が分かりました。

そのため、skillsカラムのフィールド情報を綺麗に表示するには、RECORD型をそのまま出力するSQLを書くのではなく、SQL内でRECORD型の中身を展開する必要があります。

「なんかうまく表示できるような展開方法ないかなぁ〜」ってRedash設定を色々見ていたら、カラムの出力設定に以下のような記述があり、カラム毎にHTMLコンテキストを埋め込めそうな雰囲気があります。

HTML埋め込んでみる

この機能をskillsカラムに応用して、見やすい形式にしたクエリが以下です。

SELECT
  player_id,
  '<ul>' || (
    SELECT
      ARRAY_TO_STRING(
        ARRAY(
          SELECT 
            '<li>Character ID: ' || CAST(s.character_id AS STRING) || 
            ' / Skills: ' || 
            (SELECT ARRAY_TO_STRING(ARRAY(SELECT CAST(id AS STRING) FROM UNNEST(s.ability_ids) AS id), ', ')) || 
            '</li>'
          FROM UNNEST(skills) AS s
        ), 
        ''
      )
  ) || '</ul>' AS skills,
  timestamp
FROM
  <戦闘ログのテーブル>
WHERE
  player_id = <player_id>
ORDER BY
  timestamp DESC

Redashで上記を実行すると、以下のように出力されます。

無事HTMLを埋め込む事ができました! 最初の出力結果と見比べると、断然見やすく、分かりやすくなっていると思います!

最後に

今回はRedashで出力カラムを見やすくする方法を解説しました。
普段Redashでは「誰が見ても分かりやすい状態を作る/誰でも触れるような状態を作る」という事を心掛けてクエリを作成しています。

こういった、誰かを思いやるような「気づき」の精神は会社全体の様々な場所で見受けられます。
例えば、過去に作成された莫大な量の仕様書を、AI活用して誰でもすぐ見つけられるようにする、データ入稿を一部自動化して工数を削減する、データ入稿に間違いがないか差分を正確にチェックするツールを作るなど、様々な工夫がなされています。

このような精神をこれからも大事にして仕事をしていければと思っています!

免責事項

掲載している情報の正確性には細心の注意を払っておりますが、執筆時点(2025年)の情報であり、今後のツール(Redash/BigQuery等)のアップデートにより仕様が変更される可能性があります 。

Unity を用いた開発で発見しづらい場所に溜まっていた不要データの大掃除

この記事は Akatsuki Games Advent Calendar 2025 - Adventar 17日目の記事です。

  • はじめに
  • 概要
  • 事例紹介
    • 事例1: YAML に忍びこむ合計600万文字のテキストを除去!🧹
      • 問題発見
      • 原因
      • 対処
      • 結果
    • 事例2: ゲームに影響を与えずにVFXのデータを2000万行削減!✨
      • 問題発見
      • 原因
      • 対処
      • 結果
  • おわりに

はじめに

クライアントエンジニアの渡邊です。新卒で入社して4年目で、主にゲームの新規機能開発と運用向けの内部ツール等を開発しています!

概要

ゲームの見た目、面白さ、演出、UI などさまざまな用途で用いられるアセットですが、開発中、様々な要因で不要なデータが知らず知らずのうちに蓄積していきます。例えば、ゲームの要件・仕様変更に伴って使わなくなったデータをエンジニアが削除し忘れる、アセットを作成してくださるアーティストさんそれぞれの経験値・制作手順の微妙な違いで不要なデータが生じてしまうといった人的要因などが挙げられます。

今回は、私が所属する開発現場で生じた不要データの事例を二つ紹介します。

続きを読む