nikeeshi のコーディング記

コーディングの成果をはっつけるとこ。このブログにあるソースコードはNYSL Version 0.9982に従い公開します(2014/06/18)。

メモ:UnityのScriptableObjectで保存される値

前書き

メモです。気にしないでください。

ScriptableObjectとしてPrefab化したときに保存されるデータの型

Stringは保存される。

Delegateは保存されない。

Interfaceは保存されない。

Abstract classは保存されない。

ScriptableObjectを継承したAbstract classはType miss matchとでる。 一回実行すると実体が消える。

inspecterに表示されるかどうかと関係あるのだろうか

Unityでデータを扱うということ

注意

勉強中なので、適当(悪い意味)な事をかいてしまうかもしれません。許してください。

前書き

僕はOOPが苦手なので、なんでもかんでもクラス分割をしてしまい、無意味なクラスが増えてどうしようもなくなるということがよくおきます。

クラス分割をすると、モジュール同士の関係が疎結合になり、密結合なプログラムを書くのを防ぎます。

逆に言うと、本来、疎結合にするべきでないモジュールをクラス分割してしまうと、参照を相互に持ったり、コンストラクタに参照を渡さないといけなくなったり、無駄に継承関係が入ったり、散々なことになります。

まず、クラス設計を考える前にデータ設計を考えると良いと私は考えます。

型ベースで考えるのではなく、クラスをInstance化したオブジェクトをどう扱うかを考えます。

Unityでのデータの扱い方

Unityでは、スクリプト(MonoBehaviourの派生)をGUITextや3DモデルといったGameObjectにくっ付けることで、プログラムとの連携をとります。ただし、これはクラスをくっ付けたと考えるのではなく、オブジェクトをくっ付けたと考えるほうがいいでしょう。

それらのObjectはフィールドをinspectorで変更できます。ただし、それはUnityがデフォルトで認識できる種類のフィールドのみです。(基本型、配列、非GenericなSeriarizableオブジェクト等) 勿論そのObjectのクラスに対するinspectorを自分でむりやり定義することもできますが、恐らく値を保存するのはうまくいきません。(OnInspectorGui)

UnityではObjectをPrehabとして分離することができます。(ScriptableObject) C#プログラムにおける参照型のObjectのようなものです。これは、GameObjectとは独立で存在するObjectで、値をいじることもスクリプトから読み込むこともできます。 このObjectを活用できるようにプログラム全体の設計を組むと良いのではないでしょうか。

型について

Unityでは使いやすい型と使いにくい型があるようで、それを意識すると少しはプログラム設計がよくなるのではないでしょうか。

ジェネリック

データを表すのに本当にジェネリック型が必要ですか?

(でも右と左の事例は辛かった)

デリゲート型

デリゲート型はinspectorで見えないし、インターフェース使っても誰も文句言わないよ。

インターフェース

鬼門。インターフェースではそのインターフェース型とObject型であることは保証できるけど、UnityEngine.Object型であることは保証できない。諦めて、抽象クラスを使おう。 そのときに、多重継承問題がでてきたら、泣こう。

コレクション

inspectorに表示されない(?)。そのコレクションには多くのデータが入るのですか?挿入や削除といったクエリが頻繁に起こるのですか?そうでないなら、配列を使いましょう。

あとがき

と、思って今コードを書いているところです。 乱文すみません。

コルーチンを使った状態遷移

前書き

読んでも何も得られません。 「難しいよ」ということしか書いてありません。

議題

ゲームの状態遷移をどう書くか

案1

状態をなんらかのデータで保持し、状態と入力の組から次の状態を返す関数をベースに記述する。 つまり、離散マルコフ過程のような書き方。 特に、ゲームスピードを変化させるときとかに、頭がこんがらがりそう。

案2

状態を継続としてみなすと都合がよい。 Unityではコルーチンで多フレームにまたがる処理を簡単に書ける。http://docs-jp.unity3d.com/Documentation/ScriptReference/MonoBehaviour.StartCoroutine.html 入力が多種類の場合、状態に関する処理は分割しにくい。

案3

各入力に対してコルーチンをinvokeする。わけが分からないよ。

状態遷移の三軸

入力別に処理をかき分けたい。

状態の情報別に処理をかき分けたい。

ゲームの処理は時間に対して縦割りしたい処理である。

これらの三つの軸に対して、モジュール分割をしたい。

結論

各入力同士の結びつきが弱く、

各状態情報の結びつきが弱く、

時間軸方向にまとまっているような

適切なモジュール分割をさがす。

あとがき

不満を並べたただの検索妨害記事を書いてすみませんでした。

右と左

動機

右と左に同じ処理をする場合、2回書くのはめんどくさいよね ってことで、書いてしまった。

概要

Unityで上のC#で動くコードです。 Unityじゃなかったら適当にコード変えればいい。

右と左という関心事の分離をしたよ。 あと、ついでにC#に参照はないので、参照つくったよ。

コード

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UnityEngine;

namespace Utility
{
    public enum LR
    {
        Left,
        Right
    }
    static public class Selector
    {
        static public LR TheOther(this LR val) { return (LR)(1 - (int)val); }
        static public Pair<Type> Cons(Type a, Type d) { return new Pair<Type>(a, d); }
        static public readonly LR[] selector = new LR[] { LR.Left, LR.Right };
    }
    [System.Serializable]
    public struct Pair<Type>
    {
        public Pair(Type left, Type right)
        {
            this.left = left;
            this.right = right;
        }
        [SerializeField]
        Type left, right;
        public Type Get(LR pos)
        {
            if (pos == LR.Left)
                return left;
            else return right;
        }
        public void Set(LR pos, Type value)
        {
            if (pos == LR.Left)
                left = value;
            else right = value;
        }
    }
    public struct Reference<Type>
    {
        public Reference(Func<Type> get, Action<Type> set)
        {
            this.get = get;
            this.set = set;
        }
        public Func<Type> get;
        public Action<Type> set;
    }
}

SRM626

久しぶりのC++過ぎて頭からC++の仕様がすっ飛んでいます。 やはり、C++といえど、仕様をまとめた自分用チートシートをつくらないといけませんね

250

ほんとにC++?と疑うようなコードです。 いちいち配列0埋めしてるし、まあいいけど。

#include <cstring>
class FixedDiceGameDiv1
{
public:
    double getExpectation(int a, int b, int c, int d) {
        if(a*b<=c)return -1.0;
        double dp[2501][2];//this is not dp
        for(int i=0; i<2501; i++)
            for(int j=0; j<2; j++)
                dp[i][j]=0;
        auto makedp=[&](int a, int b, int tar) {
            double tempdp[2501][2];
            for(int i=0; i<2501; i++)
                for(int j=0; j<2; j++)
                    tempdp[i][j]=0;
            int point=0;
            tempdp[0][0]=1;
            for(int pa=0; pa<a; pa++){
                for(int pb=1; pb<=b; pb++){
                    for(int i=0; i<=a*b; i++){
                        tempdp[i+pb][1-point]+=tempdp[i][point];
                    }
                }
                point=1-point;
                for(int i=0; i<2501; i++)
                    tempdp[i][1-point]=0;
            }
            for(int i=0; i<2501; i++)
                dp[i][tar]=tempdp[i][point];
        };
        makedp(a, b, 0);
        makedp(c, d, 1);
        double sum=0;
        double cnt=0;
        for(int pa=0; pa<2501; pa++){
            for(int pb=0; pb<pa; pb++){
                sum+=pa*dp[pa][0]*dp[pb][1];
                cnt+=dp[pa][0]*dp[pb][1];
            }
        }
        return (double)sum/(double)cnt;
    }
};

600

これに時間が残っていれば解けたであろうLevel2

一瞬1000000000*50nodesのグラフの最短路問題かと思ったがもちろんそんなの無理

これは、行列の高速2乗法で解きます。

Mat_x,y=xからyへのコスト

積Mat1*Mat2_x,y=min(zがnode) Mat1_x,z + Mat2_z,y

和Mat1+Mat2_x,y=min (Mat1_x,y , Mat2_x,y)

と行列演算を定義

Dist_x,y=min(from=x_i to=y_i) weight_i 無かったら無限大

Base=Dist+Dist2+Dist3+..+Dist~N

Nbase_x,y=min(from=x_i to=y_i) -weight_i 無かったら無限大

Cost_1=BaseNbaseBase

Cose_2n=Cost_n*Cost_n

で高速冪乗法を使ってCost_chargesを求めて、

答えはCost_charges_1,N

追記

っていうか600の問題はtropical mathematicsじゃん

追記2

誤字つらい

追記3

Baseはワーシャルフロイド使うかN乗するかしてならしとかないと

UnityでFrameRateを表示させてみた

あらすじ

花札の会社のインターンを受けようと思い、急ぎ足でゲームを作り始めた。 構想は半年前からずっとあるので、困らないだろう。 とりあえず、FrameRateを表示するプログラム(ゲームプログラミングにおけるHelloWorldみたいなもの)を作った。 Unityは仕組みを覚えるのは少し大変そうだが、その分強力で、DirectXで作った時(本当はDXライブラリ。見栄を張った。)より速く作れた。 まあとにかくコードだコード。

コード

using UnityEngine;
using System.Collections;
using System;

public class FPSViewer : MonoBehaviour
{
    public int framePerUpdate = 10;

    void Start()
    {
        StartCoroutine(calcFPS());
    }

    IEnumerator calcFPS()
    {
        while (true)
        {
            var totalTime = 0F;
            for (int i = 0; i < framePerUpdate; i++)
            {
                totalTime += Time.deltaTime;
                yield return null;
            }
            guiText.text = String.Format("{0} FPS ({1}ms)", framePerUpdate / (totalTime / Time.timeScale),

              1000 * (totalTime / Time.timeScale) / framePerUpdate);
        }
    }
}

説明

継続マスターである私は、なんでもかんでも継続を使わないと気が済まないので、C#のコルーチンを使って書いてみた。 あっさりしていて読みやすい。 我ながら素晴らしいコードである。

Unityはpublicなメンバに対して、エディターで値をいじれるようになっているので、frameParUpdateがそうなっているのはそのためである。

ちなみにFPSを測る際にtimeScaleで時間を割ってやらないとスロー再生したときにFPSがおかしくなってしまう。

追記

書くのを忘れたが、このブログのPVなど高が知れているしかまわないだろう。 もちろん上のコードはUnityのGUITextに対して適用するスクリプトである。

C#の壁

Unityをインストールしたのだが、開発はC#JavaScriptを使わなければならないらしい。

JavaScriptは人間の使う言語じゃないらしいので、C#を使うことになるのだが、僕はJavaを書くと頭痛に襲われる。

果たして、C#をストレスなく習得することができるのか!?