投稿記事

2023年 08月の記事 (3)

なんやかんやモーション自作始めました

モーションについて

3D移行するとして目下の課題でした
当初は規約的に問題なさそうなMMDのモーションデータを使用する想定でした
(改変、再配布、商用利用可など確実にセーフなものを選定)
としていたのですが、やっぱり実装段階で無理があるというのがわかりました

最初にテストした1モーションはかなりよさげ立ったのですが、規約的にグレーな部分がありお蔵入り、別モーションで試した軒並みダメだった見たいな経緯です、、、


なのでモーションは自作することにしました
3Dソフト初心者なのでかなりお見苦しいと思います

基本的にはブレンダーで作ろうと思ってます
↓作業風景


これもお蔵入りですが供養のためさらします


Unity上の実装なら楽なんですけどねぇ。。。
Humanoidはモデリングツール上じゃないと不具合多くて大変ですね

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

進捗~ショップ周りとメインゲーム~

ショップ

とりあえず購入とアイテム数の保存、エフェクト、サウンドとか実装しました
(gifなので音はわかりませんが。。。)
Shop周りは拡張予定なのでまだお金の計算とかもざっくりしてます



メインゲーム

ランダムスポーン、移動、武器の装備、内部のステータスロジック
敵のランダムスポーン、敵アニメーション
これぐらい作りました

敵AIの作成、攻撃ロジック、敵攻撃ロジックなどまだまだ作るものもたくさんです


後書き

エッな要素入れる場所決まっているのですが、なかなか入れるまでの道のりが長いです
モーションの準備やIKの設定、チ〇コシェーダーなど色々用意済みなのですが、ゲームに組み込むのはまだまだかかりそうです

エッなの液体表現やペイントシェーダー、汚れシェーダーなど作る予定
こちらの要素は大体息抜きに作ってます
楽しいけど作りすぎると燃え尽きちゃうので程々な感じでやってます

敵配置とか階層設定とかのマスタデータ作るのが本当にだるいので優先的にやってはいます。。。

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

Unityでのセーブデータに悩んだ話と進捗報告

前書き

お久しぶりです
仕事忙しかったり、ゲームの仕組みの一部を作り直したりでなかなか更新できませんでした
あんまりネタがないので今回はTechな話をしたいと思います
あと、最後にちょっとだけ今のゲームの進捗貼ります

セーブデータの話

結論

SQLite使うようにした

今までと変えるに至った経緯

もともとはセーブデータは暗号化してMsgPackを用いて保存してました
採用理由はデシリアライズ速度でした

しかし、作っていった結果。。。。



細かいデータを保存したりするのに毎回デシリアライズ用のコード書くのめんどい!
ってなりました
まぁ、MsgPackのコンテナ系のデシリアライズの対応がいまいち悪いのも原因の一つです



作りずらいことこの上ないという状態でした


シームレスに大量のデータをリアルタイムで保存したいなー

DBみたいな仕組みあればいいなー

DBでいいじゃん

SQLiteがあるじゃん

といった感じで採用に至りました

実際の作り

大まかな部分はこちらの記事を参考にしています

UnityにSQLite-netを導入する


↑に加えてある程度のラッパーと自動生成する機構を作ったりしました


    <Entity>
        <Name>TestUser</Name>
        <Param>
            <Name>user_id</Name>
            <Type>uint</Type>
            <Primary>true</Primary>
            <Comment>ユーザーID</Comment>
        </Param>
        <Param>
            <Name>name</Name>
            <Type>string</Type>
            <Comment>name</Comment>
            <DefaultValue>Test</DefaultValue>
        </Param>
    </Entity>

こんなXMLを書くと

///Don't write
///This is Generated Code

using System;
using System.Collections.Generic;
using System.Linq;
using Cysharp.Threading.Tasks;
using SQLite;
using UniRx;

[Table("TestUser")]
public class TestUserEntity
{
    /// <summary>
    /// ユーザーID
    /// <summary>
    [PrimaryKey]
    [Column("user_id")]
    public uint user_id { get; set; }
    /// <summary>
    /// name
    /// <summary>
    [Column("name")]
    public string name { get; set; }

}

public class TestUserModel
{
    private static bool Initialized = false;
    private static List<TestUserModel> items = null;

    public static IList<TestUserModel> Items
    {
        get
        {
            if(items == null)
            {
                GetAll();
            }
            return items;
        }
    }

    private TestUserEntity entity = new TestUserEntity();
    private CompositeDisposable disposable = new CompositeDisposable();
    
    public uint UserId => entity.user_id;
    private ReactiveProperty<string> name = new ReactiveProperty<string>();
    public IReadOnlyReactiveProperty<string> Name => name;

    


    public static async UniTask<TestUserModel> Get(uint user_id)
    {
        if (!Initialized)
        {
            await SaveDataCore.CreateTable<TestUserEntity>();
            Initialized = true;
        }
        
        if(items == null)
        {
            await GetAll();
        }
        
        if(items.Exists(i => i.UserId == user_id))
        {
            return items.First(i => i.UserId == user_id);
        }

        var entity = new TestUserEntity();
        entity.user_id = user_id;
        entity.name = Test;

        await SaveDataCore.InsertData(entity);
        var model = new TestUserModel(entity);
        items.Add(model);
        return model;
    }

    private static async UniTask GetAll()
    {
        if (!Initialized)
        { 
            await SaveDataCore.CreateTable<TestUserEntity>();
            Initialized = true;
        }

        if (items == null)
        {
            var datas = await SaveDataCore.GetAllData<TestUserEntity>();
            var models = new List<TestUserModel>();
            foreach (var data in datas)
            {
                models.Add(new TestUserModel(data));
            }
            items = models;
        }
    }

    private TestUserModel(TestUserEntity _entity)
    {
        entity = _entity;
        name.Value = entity.name;
        name.Do(v => entity.name = v).Subscribe(_ => UpdateData()).AddTo(disposable);

    }

    private async UniTask UpdateData()
    {
        await SaveDataCore.UpdateData(entity);
    }
     
    public void UpdateName(string _name)
    {
        name.Value = _name;
    }

    
    ~TestUserModel()
    {
        disposable.Dispose();
    }
}

こんなコードができます
どうやって作っているのといわれると、ある程度のテンプレートを作成してreplaceとstreingBuilderで頑張って作ってるって感じです
かなりゴリラな作り方なのである程度できる方ならわかっちゃうと思います

こんな感じセーブデータを保存するクラスをバンバン量産できるようにしてます

フラグ管理などもDBなのでいっぱいデータ作れる安心感が良いです


作ってるゲームの話

今作っている画面はこんな感じです
街中でのショップ機能とか作ってます
Gif


スクリーンショット



本来であればShop機能などが右側に乗るはずなので、こちらも少々お待ちを。。。。



小言
最初はランダム生成でキャラのバリエーション増やすつもりだったのですが、プチプチと作っていくうちに、ある程度ユニークなキャラがいたほうがいいなと思い至り↑のShop店員さんたちを作成することになりました

こうやっていろいろ作っちゃうと、ランダム生成キャラは汎用的なエロで済ませるつもりだったのが、ユニークなキャラには専用の何かを設けたくなってしまいますね。。。。

この記事が良かったらチップを贈って支援しましょう!

チップを贈るにはユーザー登録が必要です。チップについてはこちら

月別アーカイブ

限定特典から探す

記事を検索