読者です 読者をやめる 読者になる 読者になる

developer_RYO’s blog

スマホアプリやPCゲーム、音楽やイラストを自由気ままに作っている人の技術ログです

サクラエディタのマクロでsqlテキスト整形

f:id:developer_RYO:20160928231018g:plain

totech.hateblo.jp
仕事効率化のために、マクロを作るよ。

■このマクロで実行すること
・変換対象→選択しているテキスト
・タブ→カンマとクオーテーションに変換「','」
・行末→クオーテーションとカンマと丸括弧追加「'),」
・行頭→クオーテーションと丸括弧追加「('」
・文末→クオーテーションとセミコロンと丸括弧追加「');」
・null,NULLにはクオーテーション付けない

function TabTextToSQLText(text) {
  
  //タブ→カンマ変換
  text = text.replace(/\t/g,"','");
  //「改行」→「'),改行」に変換
  text = text.replace(/\r\n/g,"'),\r\n");
  //行頭に「('」を追加
  text = text.replace(/^(.+?)$/mg,"('$1");
  //null文字にかっこがついていたら、かっこを外す
  text = text.replace(/\'null\'/g,"null");
  text = text.replace(/\'NULL\'/g,"NULL");
  //最後に');を付ける
  text += '\');'
 return text;
}
//==========
// MAIN
//==========
// 選択範囲のテキストを取得
var text = Editor.GetSelectedString(0);
// 変換後のテキストを出力
if ( text !== "" ) Editor.InsText(TabTextToSQLText(text));

【Unity5.4.1f1】入れ子にしたcanvasの大きさやアンカーがゲーム開始時にずれる現象

Unity5.3から、5.4にアップグレードしてときのバグ挙動についてメモ。

■現象の再現と内容
ヒエラルキー上で親canvasを作る
CanvasScalerのUIScaleModeを「Scale With Screen Size」にして、解像度を2560、1440に設定する。

②親Canvasの中に子Canvasを作る
CanvasのAnchorPresetsをmiddle・centerにする。(このときのwidthは2560、heightは1440)

デバッグ開始▶すると
AnchorPresetsがbottom・leftに自動で変更される。widthが837、heightが471になる。

デバッグ終了後
AnchorPresetsはbottom・leftのままでゲーム開始前に戻らない。
width、heightも同様にゲーム開始前に戻らない。

■解決方法
ゲームオブジェクトにアタッチされているCanvas、CanvasScaler、GraphicRaycasterを
すべて外す。(Remove Component)
外した後付け直す。

Unityでのゲーム開発メモ 曲の演奏時間に対して進捗を表すプログレスバー

f:id:developer_RYO:20160102230346g:plain


gif画像にある通りの、プログレスバーを作成。

プログレスバーの作り方については、検索してみると他の方が記事にされていました。
Unityのリファレンスにもいくつかヒントが記載されています。
docs.unity3d.com

fillAmount Image.type が Image.Type.Filled に設定されている時に表示されている Image の数
fillMethod どの fill タイプのメソッドを使用するか
fillOrigin Fill プロセスの原点位置をコントロールします。各 fill メソッド毎に違う結果をもたらすことを意味します。

ここら辺をインスペクターでいじればプログレスバーは作成可能です。

■曲の長さについては、AudioClipの変数lengthで取得します。


画像オブジェクトにつけたスクリプト

//画面上部に表示するタイムゲージを表示します。
//曲の長さと、現在の経過時間より、パーセンテージを取得し、表示。
using UnityEngine;
using UnityEngine.UI;

public class BarTimer : MonoBehaviour
{
    //タイマーと、再生する曲を入れる。

    [SerializeField]
    private Timer timer;
    [SerializeField]
    private AudioClip music;

    private float musicLength;
    private Image image;

    void Start () {
        //曲の長さを取得
        musicLength = music.length;
        //画像を格納
        image = this.GetComponent<Image>();
    }

	// Update is called once per frame
	void Update () {
        //画像のFillAmountを更新し続ける。
        image.fillAmount = 1 - (timer.Now / musicLength);
    }
}

タイマーのスクリプト

//////////////////////////////////////////
//ゲームオブジェクトをタイマーにするスクリプトです。

using UnityEngine;

public class Timer : MonoBehaviour {

	/////////////////////////////////////////

	//タイマー
	private float timer;

	//タイマーを進めるかどうかを決める変数
	public bool timerRun = false;

	//タイマーをリセットする。
	public void ResetTimer(){timer = 0;}

	//タイマーを進める
	public void AddTimer(){timer +=  Time.deltaTime;}

	//プロパティで値を変えられるようにする。
	//変数をpublicにしないのは、インスペクター上で変えられないようにしたいから
	public float Now{get{return timer;}}

	///////////////////////////////////////
	//初期化
	void Start()
	{
		//タイマーの初期化
		timer = 0;
	}
	////////////////////////////////////////
	//アップデート
	void Update()
	{
		//タイマーを進めるかどうか
		if(timerRun == false) return;

		//タイマーを進める
		AddTimer();
	}
}

c#でcsvファイルを配列に格納して返すクラスを作ってみた

音ゲーのタイミングデータをCSVで取り扱いたかったので、下記のクラスを作って見ました。

StreamReaderの、closeとかdisposeとかがまだあまり理解してないので、後で修正したいと思います。

配列について、タイミングデータの数が曲や難易度によって変化することを見込んで、List<>を使用しました。


////////////////////////////////////////////////
//ファイルからノート配列を作成する役割

using System.Collections.Generic;
using System.IO;

public class InputCSV
{
	
	////////////////////////////////////////
	//データ構造

	private List<Note> noteArray;
	private int index;
	
	private StreamReader csv;
	
	
	
	////////////////////////////////////////
	//処理
	
	//コンストラクタ
	public InputCSV(string fileName)
	{
		this.noteArray = new List<Note>();
		index = 0;
		
		InputNote(fileName);	
	}
	//インデックスの最大値を返す。
	public int getIndex{get{return index;}}
	
	//CSVデータを入れたノート配列を返す。
	public Note[] Output()
	{
		return noteArray.ToArray();
	}
	
	//ファイルを読み込んで、配列に格納する関数
	private void InputNote(string filename)
	{
		//ファイルを読み込み、配列にstringを格納していく。
		csv = new StreamReader("Assets/Resources/" + filename);
		ReadAllLineCSV();
		
	}
	
	
	//CSVファイルを1行ずつ読み込み、配列に足していく関数
	public void ReadAllLineCSV()
	{
		//indexMaxの値が実際と違わないように、この関数内で初期化する。
		index = 0;
		
		//操作用データ
		string line = "";
		string[] lineArray;
		
		//順次格納
		while (csv.Peek()>=0)
		{
			//ファイルから1行読み込み、配列に格納する。
			line = csv.ReadLine();
			lineArray = line.Split(',');
			
			noteArray.Add(new Note(float.Parse(lineArray[0]),int.Parse(lineArray[1])));
			
			//行数の追加
			index++;		
		}
		csv.Close();
	}
}

field type 型名 is less accessible than field の避け方

▪️問題点
変数の宣言箇所にfield type 型名 is less accessible than fieldっていうエラーが出た
出たのは、noteっていう変数のところ。

//譜面クラス
//入力タイミングと、音符のタイミングデータの結果を返す。
public class Music
{
	////////////////////////////////////////
	//データ構造
	
	protected Note[] note;
	
class Note
{
	/////////////////////////////////////////
	//データ
	
	//タイミング、サウンドタイプ、
	private float timing;
	private Sound sound;
	

▪️解決方法
Microsoftのサイトになんだか書かれていたので、参考にしました。
アクセシビリティ レベルの使用に関する制限事項 (C# リファレンス) | Microsoft Docs

直接基本クラスは、少なくともその派生クラスと同程度にアクセス可能である必要があります

僕の場合は派生クラスではないんですが、publicとかprivateとかをいじって、アクセスレベルってやつを合わせてあげるのが必要っぽいという認識だ。

unityで音ゲーのモックを作りました

f:id:developer_RYO:20151111222709g:plain

音ゲーを作っているのですが、ゲームの大体のロジックをつかみたいと思い、
こちらのサイトを参考にしつつサンプルを作ってみました。
blog.bokuweb.me

方針として、0,1,2,・・・番のタイミングデータとユーザーの入力時間を比較し、
誤差が少なければOK、多ければBADの結果を出力します。

データの持ち方
  • 曲開始からの時刻を格納する変数timer
  • 曲のタイミングデータを格納する配列timing
  • ユーザーの入力に対して、どのタイミングデータを比較するかを指定する変数indexTiming
  • 曲の判定結果を格納しておく変数cool,good,bad
処理的なもの
  • ユーザーがスペースキー入力したらtrue返すIsBeat()
  • 現在のtimerとタイミングデータtimingを比較し、判定結果をcool,good,badに追加していくcheckTiming()
  • cool,good,badを+1するadd●●()
ゲームのフロー

ゲーム開始時にタイマーに0を代入し、曲を開始します。
音符(といってもブロック)については、タイミングデータの1秒前に音符を生成していく。速度については生成1秒後にヒットバーに当たるようにする。
ゲーム中はユーザーの入力があればタイミングデータとの比較を行い、判定範囲であれば結果を変数にプラスしていきます。

感想

参考にさせていただいたサイトが非常にわかりやすく、1,2時間ほどでサンプルを作ることができました。ありがとうございます。
音符を消す処理をどうするか、音符を動かすラインが複数ある時の処理、音ズレ対策などまだまだやることがたくさんありますが、
簡単なサンプル作成によって作りたいもののイメージをより強く持つことができました。

ソースコード

ヒットバーのオブジェクトにつけたファイル

using UnityEngine;
using System.Collections;

public class Beat : MonoBehaviour {

    //本番作品では、なるべくstatic変数を使わないこと。
    //ゲームのタイマーを宣言。
    public static float timer;
    //曲のタイミングデータを宣言
    public static float[] timing;
    //音符のインデックスを宣言。
    private int indexTiming;
    //曲の判定結果を格納しておく変数を宣言。
    public static int cool; public static int good; public static int bad;

    //エフェクトを格納。
    public GameObject goodEffect;
    public GameObject badEffect;

    //開始時
	void Start () {
        
        //タイミングデータはDTMを見ながら作成した。
        timing = new float[] {1.495f,2.220f,2.580f,2.942f,3.664f,4.387f,4.749f,5.110f,5.472f,5.833f,6.556f,7.279f,7.818f,8.363f,8.725f,9.267f,9.809f,10.170f,10.713f,11.255f,11.616f,11.797f,11.978f,12.158f,12,339f,1000f};
        cool = 0; good = 0;bad = 0;indexTiming = 0;timer = 0; 	
	}
	
	void Update () {

        if (IsBeat())
            checkTiming();
        //音符がヒットバーより後ろに流れたときの処理
        else if (timer - timing[indexTiming] >= 0.12f)
        {
            addBad();
            indexTiming++;
            Instantiate(badEffect, transform.position, transform.rotation);
        }

        timer += Time.deltaTime;
    }

    //スペースキーで入力。
    public bool IsBeat()
    {
        if (Input.GetKeyDown(KeyCode.Space))
            return true;
        else
            return false;
    }

    //入力とタイミングデータの比較を行い、スコアを計上していく。
    public void checkTiming()
    {

        //タイミング誤差の範囲についてはいったんpublicにしてテストしやすくしたほうがいいかも
        if(timer - timing[indexTiming] >= -0.10f && timer - timing[indexTiming] <= 0.10f)
        {
            addCool();
            indexTiming++;
            Instantiate(goodEffect, transform.position, transform.rotation);
        }
        else if(timer - timing[indexTiming] >= -0.12f && timer - timing[indexTiming] <= 0.12f)
        {
            addGood();
            indexTiming++;
            Instantiate(goodEffect, transform.position, transform.rotation);

        }
        else if(timer - timing[indexTiming] >= -0.6f && timer - timing[indexTiming] <= 0.6f)
        {
            addBad();
            indexTiming++;
            Instantiate(badEffect, transform.position, transform.rotation);

        }
        else
        {
            //何もしません。
        }

        //デバッグログ用
        //outputResult();
    }

    //結果の追加
    public void addCool(){cool++;}
    public void addGood(){good++;}
    public void addBad(){bad++;}

    //デバッグログに結果の出力
    //public void outputResult()
    //{
    //    Debug.Log("cool=" + cool + "\t" + "good=" + good + "\t" + "bad=" + bad + "\n");
    //}
}

音符を生成して、初期速度を持たせるファイル

using UnityEngine;
using System.Collections;

public class CreateNote : MonoBehaviour {

    //音符オブジェクトを生成するため
    public GameObject note;

    //音符の生成位置指定用
    public Vector3 position = new Vector3(-10, 0, 0);

    private int index = 0;

    void Start()
    {
    }
	
    void Update () {

        //スタート時にまとめて作ったほうがカクツキが少なくなるかも
        if(Beat.timer >=  Beat.timing[index] -1)
        {
            Create();
            index++;
        }
    }

    //音符を作る関数
    public void Create()
    {
        Instantiate(note, position, this.transform.rotation);

    }
}

音符のデータを格納するクラス

ClassNote.cs

//音符のデータをクラスにする。
public class Note
{
	//曲が開始してから、いつ入力したら正なのかのタイミングデータ
	private float timingData;
	//何小節目か
	private byte barNumber;
	//音符の属性
	private byte type;
	
	//データのセットはインスタンス化する時に行う。
	Note(float noteTiming,byte noteBarNumber,byte noteType)
	{
		this.timingData = noteTiming;
		this.barNumber = noteBarNumber;
		this.type = noteType;
	}
}