なれはて日記

ざんぞうです

Unityゲームジャム「そろえる」に参加しました

おひさ

お久しぶりの投稿です。

メーーーーちゃんです。

 

最近ゲーム作りから離れて30周年のロボット大戦とかエルデの王を目指したりしてましたがunity1weekの開催を見つけちまったので久しぶりに参加を決めました。

この記事を投稿するのはu1wの評価期間を終え、共有会を終えたタイミングです。(書くのが遅い)

meetup.unity3d.jp

 

今回作成、投降した作品はこちら

https://github.com/yamadamael/GameJam_20220502_src/blob/main/Icon.png?raw=true

はばたけ野菜少女 | フリーゲーム投稿サイト unityroom

 

ソースコード公開しようの流れがあったので私も公開してみました。

github.com

 

野菜少女とは

えっ野菜少女ってなんですか?

いや、知りません。

 

今回のお題が「そろえる」でした。

なんかないかなーと考えたところコンプガチャを思い出しました。

https://image.itmedia.co.jp/nl/articles/1205/09/ike_120509mogemas02.jpg

ありましたよね。

それなりに排出率低いのを何体か引くとさらにもう1体もらえます!

みたいなの。怖いですね。

 

今は「特定のカード複数枚で効果が得られる」ということ自体が違法のようで、

2体集めると合体攻撃だーってのもNGで各社頑張って回避してたようです。

2012年の話だったんですね。

ja.wikipedia.org

 

今は廃絶されたコンプガチャですが、unity1weekでこの邪悪な違法システム作ってもいいんだ!?やったーのテンションです。

私自身クライアント者なのでガチャ排出システムを作ったこともなく、作りたいと思っていたのも背中を押しました。

そして背景としては野菜。野菜がこの世界の食物連鎖の頂点にあります。野菜>動物(人類以外)>人類の構図です。野菜こそが世界の覇者!

そうして生まれたのがはばたけ!野菜少女です。

 

制作について

目標とかスタンスとか

  • ガチャシステムを作ってみる
  • ガチャ演出を作ってみる
  • ゲーム要素はなくていい、評価1でもOK

ガチャシステムを作ってみる

要件はこれ

  • レアリティごとの抽選率がある SSRは3%でSRは10%、Rは87%
  • キャラ単位で抽選率を変えられる。いわゆるピックアップ
  • データはjsonファイルからロードする。
  • 特定の複数キャラを集めたら特別なキャラが付与される
  • 抽選漏れが発生しない。少数誤差が存在しないようにする

普通のコンプガチャですね。

注意したのは最後の抽選漏れで、例えば抽選対象が3体いると各抽選率は33.333333~%になり抽選率の合計が100%になりません。そうなると極まれに抽選されないことが起きるため生の抽選率合計で計算するのは避けました。

実際に書いたコードでは各キャラに抽選倍率を持たせて、その合計値から乱数を生成し抽選ごとに足していくようにしました。

イメージ的にはこんな感じ

  倍率
キャラ1 2
キャラ2 1
キャラ3 1
合計 4

 

乱数(0~4未満) 抽選したキャラ
0 キャラ1
1 キャラ1
2 キャラ2
3 キャラ3

 

問題点

動作的には問題ありませんでした。

ただキャラごとに全体から見た2倍、3倍などの倍率で指定できますが、

「このキャラは5%で抽選させたい!」と言われると総数から計算した細かい指定が必要になります。

確率的な正しさを求めてやってみましたが、そもそも端数が出たら低レア当たったことにしとけばいいのでは説を唱えられると「それもいいよね」と思います。

 

また、jsonというフォーマットのデータからガチャ情報を読み込んでいます。jsonの読み込みに慣れておくとデータ系の実装が楽になるのでいいかもしれません。

私はExceljsonの変換マクロを作っていてjsonの作成自体はとても楽な環境です。あとで変換マクロは公開するかもしれません。

 

ガチャ演出を作ってみる

はい、苦手分野です。

でも、「いいもの作らなきゃ!!評価が!!うわああああ」的な怖いメーーーちゃんは今回いなかったので笑いながら作ってました。

演出の流れ

  • 畑から引いた数だけ光が生まれる
  • 光がSR以上なら確定演出、すべてSR未満なら飛ばす。
  • 光は空へとはばたきます
  • 宇宙空間まで羽ばたいた光はなんと野菜でした!

一大スペクタクル~!感動的ですよね。泣いちゃいます。

演出のほとんどはDOTweenで動作しています。性質上10連をひたすら連打することになり(拷問になる)演出スキップを付けてみましたが、DOTweenの理解が浅くスキップしてるのにSE鳴ってたりします。。あと1連で連打してると光が10個生まれることがありますね。大豊作!3分調べて分からなかったので放置しました。

 

また、コンプ演出も後になってから必要に感じ作ることにしました。ここまで苦行に耐えてくれたユーザーのためにもここはがんばらねば...の精神です。あれがご褒美になったのかはわかりません。

そもそもコンプガチャって世界観的になんなのか?と考えたところ素体たちが悪魔合体してあらたな生命が誕生するってことなんですよね。この真実を元にコンプ演出が生まれました。あれも気合いDOTweenベースでやってた気がします。

ゲーム要素はなくていい、評価1でもOK

今回のコンセプトはガチャを作ろうということだけです。でもガチャはゲームじゃない!どうしよう!じゃあゲーム要素なしでオッケ~。目的があってそれ以外を無限に許し続ける。それは自分なりの「自分を苦しませない駆動開発」なのだろうと昨日の共有会で思いました。めっちゃいい言葉です。akamiさん言語化してくれてありがとうございます。

 

www.youtube.com

 

やりたいことやろう。練習、実験、検証、ランキング狙い、チーム開発、わからんけど参加してみる、実績作り、、、参加条件満たして悪させずプラスになればいいんじゃい!

 

ソースコード公開してみた

共有会情報ですが#u1w_scriptsのタグでGithubソースコード公開しているようです。さいさん情報ありがとうございます。

 

www.youtube.com

 

ということで私も借り物はすべて削除したうえで公開しました。(リンク2度目)

github.com

 

見どころはこのへん、と定義します。

  • ガチャシステム
  • ガチャ演出(DOTween処理は怪しい)
  • App以下のなんか管理してるアレ

ガチャシステムは前述したとおりです。まともなものを作ろうとしていましたが、すごいものが作れたわけではないです。

ガチャ演出はDOTween処理終わったら次のステート、終わったら次のステート、、、を繰り返してる感じです。もっときれいに書きたいですね。

App以下は毎回地味に成長しているテンプレート的な部分です。シーン遷移とか音鳴らしたりとか。テンプレートにするならちゃんとgithubでテンプレートとして管理してほしいですね。いつやるんですか?早くしてください。

 

表立って公開するのは初めてですが、メリットはあるんですかーと言うとあると思っています。

  • 公開している人が1人増える→じゃあワイもって人がでてくるかも
  • バグやこうしたらいいかもみたいなことを教えてくれるかも
  • 何らかのノウハウ、技術を与えられるかも
  • 公開することで得られる謎の爽快感(?)

「かも」ばかりですが#u1w_scriptsの公開リポジトリを拝見させていただいたところ、「えっこんな記法あるんだ?」「これが噂のユニアールエックス...」などどれも発見があり感謝しかないです。

 

おしまい

前ーーに参加を試みて無理だと感じてトンズラしてから数年たってからの参加でしたが終始気持ちよく居られました。

  • やりたいことやれてたのしい
  • 完成してさらに嬉しい
  • 遊んでもらって嬉しい
  • 評価/コメント貰ってさらに嬉しい
  • 他の投稿作品遊んで楽しい&学び&気づき
  • 共有会で学びまくれて楽しい
  • 公開リポジトリみて完全に理解できて楽しい

えっこんなに楽し嬉しでいいんですか!?

いいんです。

やったー!

 

u1w終わってから年始に作っていたゲームの開発を再開できるようになりました。時期的に都合がよかったのとu1wの参加で燃えたのが今でも維持できてるからです🔥。難しい所にぶつかるとくたばる癖があるのでなんかいい感じに「自分を苦しめない駆動開発」を意識しながら続けられたらいいですね。

また半年くらいしたらu1w開催して私はこじらせてる頃だと思うので参加したいですね。共有会で聞いたことを実践したりやりたいことが無限にあるんだ!

UE4/C++ キーが押されたか、離されたかを取得する

前回の続きです。
InputKey関数くんが押された離されたを取ってくれると思っていましたが、調べてみると入力をプログラム側から設定(入力の偽装)をするもののようです。

目的の処理はどうするのじゃーと調べていたらこちらの記事を発見。
user-ooame.hatenablog.jp
IsInputKeyDown()でポジティブエッジ、ネガティブエッジが取れるのを記録、比較して押された、離されたとしていました。
エンジン機能は最小限でシンプルでいいですね!

写経させてもらいつつ改造して2秒分の入力を保存できるようにしてみました。
アクションゲームだと入力履歴や入力時間が欲しくなったりするので保存できるとよさそうです。

良い記事の救われ入力はいい感じになりました。
次回はUMGあたりを攻めたいと思います。

UE4/C++ Tickでアクションの入力を監視する

前回でキーボードからの入力が受け取れるようになりました。
meeeeee1021.hatenablog.com
今回はUE4で設定したアクションでバインドしたキーの入力を監視したいです。

アクションのバインド

アクションのバインドはプロジェクト設定のインプットから設定します。
「K」か「左クリック」でAttackが発火するようにしました。
(日本語設定なのがばれてしまった!あまりメリットがないので英語に戻したいです。)

f:id:meeeeee1021:20220122022717p:plain
UE4 Input

MyPlayerController.h

前回と同じなのではしょります。

MyPlayerController.cpp

PlayerInput->GetKeysForAction(FName)からバインドされたキー配列を取得し、
一つずつ入力を確認します。

#include "MyPlayerController.h"
#include "GameFramework/PlayerInput.h"

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

    // Actorなどで監視する場合はPlayerControllerを取得する必要がある
    // APlayerController* pc = UGameplayStatics::GetPlayerController(this, 0);

    // アクションの監視
    char* actionName = "Attack";
    TArray<FInputActionKeyMapping> keyMapping = PlayerInput->GetKeysForAction(actionName);
    for (auto keyMap : keyMapping)
    {
        if (IsInputKeyDown(keyMap.Key))
        {
            float time = GetInputKeyTimeDown(keyMap.Key);
            UE_LOG(LogTemp, Log, TEXT("press %s: %f"), *keyMap.ActionName.ToString(), time);
            break;
        }
    }
}

「K」か「左クリック」でログが出るようになりました。やったー!
しかし、押したら毎フレーム実行されると気まずいです。
InputKey関数さんが押した離したのを見てくれるようなので明日また調べてみます。

UE4/C++ Tickでキーボード入力やゲームパッド入力を監視する

日記を書くのはとてもお久しぶりです。
UE4を始めたので気力があれば残していきたい。

PlayerControllerが入力系握っているようなのでPlayerControllerに監視してもらいます。
ちゃんとやるなら結果も保持してアクターから参照される形ででしょうか。
UE4的な作法が全然わかっていませんのでどなたかヘルプ!

MyPlayerController.h

PlayerControllerを継承したクラスを作成します。
UE4Editorから作成するとTick関数がなかったためActorから拝借。

// MyPlayerController.h
#pragma once

#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "MyPlayerController.generated.h"

UCLASS()
class PROGQUICKSTART_API AMyPlayerController : public APlayerController
{
	GENERATED_BODY()
	
public:
	// Called every frame
	virtual void Tick(float DeltaTime) override;
};

MyPlayerController.cpp

EKeys構造体にキーボードのキーとゲームパッドのキーが定義されているので利用します。VRなデバイスにも対応しています。
IsInputKeyDown(EKey)はキーが押されている間Trueを返します。
GetInputKeyTimeDown(EKey)で押下時間が取れます。

// MyPlayerController.cpp
#include "MyPlayerController.h"
#include "GameFramework/PlayerInput.h"

void AMyPlayerController::Tick(float DeltaTime)
{
	// Actorなどで監視する場合はPlayerControllerを取得する必要がある
	// APlayerController* pc = UGameplayStatics::GetPlayerController(this, 0);

	// キーボード入力の監視
	FKey key = EKeys::P;
	if (IsInputKeyDown(key))
	{
		float time = GetInputKeyTimeDown(key);
		// *FStringで内部のchar*が取れる
		UE_LOG(LogTemp, Log, TEXT("press %s: %f"), *key.ToString(), time);
	}
}

【VBA】 可変長引数なformat関数

エクセルの関数にText()がありますが引数1つしか与えられないのが辛い。
悲しみに暮れたのでよくある可変長な整形関数を作成しました。
xlamファイルの基本モジュールに記載してアドオン登録して使います。

f:id:meeeeee1021:20200905122619p:plain
使い方


stringformat.vba

Unityゲームジャム「密」に参加しました

 

UnityRoomにておこなわれたゲームジャム「密」に参加したので開発記録を残しておきます。前半ポエムで後半は日記です。

https://unityroom.com/unity1weeks/16

 

完成したブツはこちらになります。

密蹴 | フリーゲーム投稿サイト unityroom

 

はじめに

過去2回のゲームジャムに参加し今回で3回目になります。(「跳ねる」は勝手に自主開催)

メーーーーー | フリーゲーム投稿サイト unityroom

 

コロナの影響であまり外出できなかったので何か作りたい気分になってたところゲームジャム開催と聞き迷わず参加を決めました。

僅かにでも使った道具は以下

 

作り終えて

時間関連

費やした時間は今までで最長かと。平日3、休日4でリモートワークで通勤もなくより時間を掛けられました。

自分との戦いを盛り上げるため(?)事前準備などはせず、タイトル発表から全てはじめました。

引きこもるのは得意ですが企画に詰まるとツイッター見がち。

 

企画関連

こなれてきたのか調子に乗り企画はざっくりで見切り発車。途中テンション下がってしまったがちゃんと着地できました。

最終的に目指したのは「多くの敵を同時に攻撃し、締めの一発で全員倒して気持ちい~」となれるゲームでした。多くの敵ってのが密な要素になります。

着想としては"スパロボのマップ兵器"や"TOD2の同時撃破で高グレード"みたいなところです。バカゲーっぽいテキストはバカゲーが好きなので目指してみました。"とんでもクライシス"が好きだ...

以前より時間取れるぜ!ということで仕様は多めで右往左往しながら進めましたが時間ありきで何とかなりました。プロジェクトとしては酷かったと思います。軸をしっかり持たないと手が止まったり道を間違え時間を浪費する。共同開発だったらめっちゃ迷惑だと思う。(良い方向への軌道修正であるならいいが)

  

開発関連

開発系アセット?(PlayMakerみたいなの)は特に使っておらず、コードべた書きです。コーギーエンジンとかプレイメーカーとかよくわかんないけどそういうのも使えた方がいいんだろうなぁと思い始めました。エンジニアとしては全てプログラムで表現することに喜びを見出しますが、一時的な速度を求めたり、ユーザが楽しめるものを作るという観点では使える道具は何使ったっていいのでは?と考えを改める。

木曜日時点で(アクション回りの実装のみでは)ゲームが楽しくなさ過ぎて絶望していましたが、ポイント制度を入れただけでゲームらしくなり気力も取り戻せました。

ポイント計算は↓。とにかく1発のビームでたくさん倒せばおk。

1ヒットで倒した敵のポイント合計x今回のビーム中に倒した敵の数x1ヒットで倒した敵の数

 

成果物

  • 満足度:★★★★☆
  • 完成度:★★☆☆☆

まずは完成おめでとう私。

満足度4/5は開発期間の気持ち。今の自分は概ね出し切ったかな。楽しかったし。

完成度2/5は成果物を見ての気持ち。表現ちからの無さに絶望しマイナス3点。ゲームにはなった。

 

うまくいったところ

  • HPがゴリゴリ削れてくのが見えるのは良かったと思う。
  • 敵キャラの差別化(ステータス、テキスト(?))
  • タイトル
  • gifアイコン

 

反省

ゲームの遊びとしては高得点をとるには削りフェーズと撃破フェーズに分けられます。この削りフェーズは非常事態宣言を使ってHPを20以下に減らすのですが、まじめにやるとすごい時間がかかるし短調で辛い。簡単にクリアされたら悔しいじゃないですか

 爽快感を得るための仕込みが苦行が過ぎてるのがよくない。ある程度の仕込み時間はあるべきと考えるがそのバランスが取れなかった。

政治的要素を入れたくないと思いつつも後半ハイになってしまい非常事態宣言追加、密です追加。ぶれぶれ。

 

評価とコメントを受けて

多くの閲覧、評価(良し悪し関係なく)、コメントを頂けてとても嬉しかった。

敵キャラに名前を付けたことでその名前で呼ばれることに快感を得る。

「HPが削れていくのが楽しい」と頂けて当初の目的は果たせたことを確認した。

 

評価期間(周りを見て)

わかってたけどレベル高杉内??ツイッター見て笑ってる場合じゃなかったなと反省。

開発中も気づいてはいたけどデザイン周りのセンスもスキルもからっきしだ。プログラムだけ出来ていればいいやと思っていたが1人でゲーム作るとなるとやっぱ限界は近い。足りないと思ったのはこれら

  • パーティクル/VFX
  • UIデザイン
  • 3Dモデル
  • Cinemachine

この辺りは仕事だとデザイナーに任せっきりでいざ自分でやるとなるとできない。勉強せんとね。標準の機能はどれも覚えないといけないが機能多い。。

既に出来ることを育てるのも大事だけど他のLv0をLv10でもLv20にでもするのも必要だし成長曲線的には0スタートの方が早いはず。

 

次回/今後に向けて

とりあえず表現力を上げたい。「俺には感情がない」を疑うぐらいデザインに興味がなくて無視してたけどちゃんと向き合わねば...

純粋なデザインもそうだし、上記のパーティクル、3Dもできるようになりたい。

そのうえで面白いものを生む発想やらスピリチュアルやらのインプットも必要になる。忙しい...

でもこれら一人で全部できれば最強!ゴリラ開発者目指そう...!

 

購入物 

やたら買ってみたものの利用したのはローポリ人々のみで他は無料のアセット、音源です。

 

  

以下は1日ごとの日記ですので興味ない場合はスキッポしてください。

ちょいちょい実装回りのメモがあります。

 

 

1日目

お題発表。「密」

ネタだしに使ったメモはこれ

 

f:id:meeeeee1021:20200507015029p:plain
モッサ~と敵がいてキモ~となるうごめく物量系の方向にする。大量地獄

密な敵がいるならまとめて撃破で気持ちよくしたい。スパロボのマップ兵器や!TOD2のBrusterや!という感じで大体の方向が決まりました。

この時頭の中では「黒が七で空が三」の勢いで敵が押し寄せてくるイメージでした。

 

攻撃方法としてホーミングレーザーで焼きたい気持ちが高まってしまったので動画の内容をパクったところで初日は終了しました。

(このときメーは密な敵とホーミングレーザーの融和性の低さに気づいていない)

 

毛がぴょろぴょろ飛んでく感じ

 

2日目

  •  引き続きホーミングレーザーを進めつつ
  • アセット集め(人間、エフェクト)
  • UI表示
  • 敵の生成、並べる
  • 攻撃が増えてもいいように基底クラスから継承するように修正

 

 3日目

やっぱ技が一つじゃ寂しいので増やしたい。そりゃもうゴン太ビームですね?

  • アニメーションコントローラとの格闘
  • 足ビーム実装

足ビームは主人公の正面に長いボックスコライダを配置し、OnTriggerStayで滞在している敵を拾ってます。

これは未検証の工夫ですが、拾った敵へヒット処理が必要なためGetComponentが必要になります。このゲームでは最大180回ほど発生しうるので各OnTriggerStayでGetComponentしていたらなかなか遅いはず。
そこでGetInstanceIdでヒットした敵を集めておいて次のUpdateで一気にヒット処理を回す手法を取りました。
GetComponentよりは早いはずですが。ちゃんと検証したいところです。

 

 4日目

 自分の作っているブツに対しての展望の無さ、ガンガン進む#unity1week、虚しくなりほぼ作業なしで天井を見つめる。

  • 一定時間ごとに敵を生成
  • フェードイン/アウト

 

5日目

いっぱいねてげんきでた。5日目以降仕事が休みなのでガンガン進める

  • 敵5パターン用意
  • スコア、ステージ情報追加
  • リザルト画面追加
  • ランキング、ツイート機能追加
  • 複数SE対応

複数SEについて。

以前用意したAudioManagerが複数SEに対応していなかったので対応しました。

AudioSourceは初期で4つ用意し、足りなくなり次第AddComponentする。えぇ割とゴリラ戦法です。ホーミングレーザーは60フレーム60発なのでとんでもないことになりました。ツイートしているのは発射数を削った状態です。たくさん再生させないように注意した方がいいですね。ちゃんとやるなら連射を表現するSEを作るべきです。

 

6日目

焦りを感じだす。非常事態宣言追加ってなんだ?

  • 敵HP表示
  • 非常事態宣言追加
  •  移動範囲設定
  • 同時撃破処理追加
  • ゾンビ特殊処理追加
  • メニュー画面追加
  • タイトル「密蹴」を思いつく

HP表示はダサくなりそうだから嫌だったけど状態が見えるようになって良かったと思う。元からダサい

移動範囲設定はコライダではなく2点からなる矩形で収まるようにClampで移動制限をしています。

ゾンビ特殊処理は本当なら敵クラスを継承したゾンビクラスを作り処理を分けたいところでしたが時間が惜しいのと変更量も少なかったのでベタ書きでした。

お風呂入っているときに「密蹴」を思いつきました。ちょうど蹴りからビームが出ていたのもあり、密集とも掛かっててニチャァと笑ってしまった。

テンションが上がってしまい敵性能と無駄テキストを書いてしまいました。統一された名称が必要だったんだよ!

 

7日目 投稿日

投稿に向けて細かい作業が増える。当初企画の発端でもあったホーミングレーザーがゲーム的に不要となり泣く泣くオミットする。

  • タイトル画面
  • 密(減点)処理
  • ゲージ減少処理
  • TaskからCoroutineに変更
  • リソース整理
  • ビルド/デバッグ
  • 投稿!
  • gifアイコン作成

投稿2時間前にWebGLビルド/実機テストを始める危機感の無さ。WebGLだとTask(await Task.Delay?)が動作せず慌ててCoroutineに置き換えました。使っちゃダメなんだっけ?

gifアイコンの作成はこちらを利用しました。Unity Recorderでスクショ連射してリンク先でいい感じにgifにしてもらいます。gifアイコンあるなしで客入りが変わると信じている派です。

投稿後

  • みなさんのゲームを遊ぶ
  • これ
  • 表示回り修正
  • 処理負荷軽減対応
  • パーティクル学び始める