みかんばこ

プログラミングとかその他有益だと思ったことをメモ.主にUnity

Unityでドット絵を描く(4)~カラーピッカーを作る

今回はお絵描きツールを作るに当たって、塗るための色を自由に選択するUIを作りたいと思います。(カラーピッカーというらしい)
Unityにも付属していてますし、よく利用します。
f:id:mikanbox55:20170820005830p:plain

さすがにここまで作り込むと時間がかかるので、簡単なやつを作ろうと思います。
デザインはこんな感じ。
f:id:mikanbox55:20170820010123p:plain

ヒエラルキは以下の通りです。
f:id:mikanbox55:20170820010213p:plain

右のスライダ,HSideSliderで色相を選択し、 真ん中に表示されるwindowに対してX,YSliderで座標を指定し、指定した色を返します。

Canvasにアタッチしたスクリプトは下の通りです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using System;

public class colorPicWindow : MonoBehaviour {

    [SerializeField]private Image pick;
    [SerializeField]private Image slider;
    private Texture2D pickwindow;
    private Texture2D sliderwindow;

    [SerializeField]private Image NowColor;
    [SerializeField]private Image NextColor;

    private float color_h = 0;
    private float color_s = 0;
    private float color_v = 0;

    [SerializeField]private Slider slider_h;
    [SerializeField]private Slider slider_s;
    [SerializeField]private Slider slider_v;


    public delegate void Delefunc(Color value);
    public Delefunc child;

    public Color nowColorVector;

    void Start () {
        NowColor.color = nowColorVector;
        Color.RGBToHSV(nowColorVector,out color_h,out color_s,out color_v);
        slider_h.value = color_h;
        slider_s.value = color_s;
        slider_v.value = color_v;

        pickwindowCreate();
        SliderbackCreate();
    }

    private void pickwindowCreate() {
        int w = 256, h = 256;
        pickwindow = new Texture2D(w, h);
        for (int j = 0; j < h; j++) {
            for (int i = 0; i < w; i++) {
                float s = (float)i / 255f;
                float v = (float)j / 255f;
                pickwindow.SetPixel(i, j, Color.HSVToRGB(color_h, s, v));
            }
        }
        pickwindow.Apply();
        pick.sprite = Sprite.Create(pickwindow, new Rect(0, 0, w, h), Vector2.zero);
    }

    private void SliderbackCreate() {
        sliderwindow = new Texture2D(1, 256);
        for (int j = 0; j < 256; j++) {
            sliderwindow.SetPixel(0, j, Color.HSVToRGB((float)j / 255f, 1f, 1f));
        }
        sliderwindow.Apply();
        slider.sprite = Sprite.Create(sliderwindow, new Rect(0, 0, 1, 256), Vector2.zero);
    }

    public void H_SLiderMove(float vlaue) {
        color_h = vlaue;
        pickwindowCreate();
        setNextColor();
    }

    public void setColor_s(float value) {
        color_s = value;
        setNextColor();
    }
    public void setColor_v(float value) {
        color_v = value;
        setNextColor();
    }

    private void setNextColor(){
        NextColor.color = Color.HSVToRGB(color_h, color_s, color_v);
    }

    public void destroythis(){
        Destroy(this.gameObject);
    }

    public void Okbuttonclick(){
        if (child!=null)child(Color.HSVToRGB(color_h, color_s, color_v));
        Destroy(this.gameObject);
    }

    public static void CreatePrefab(Color nowc,Delefunc func){
        GameObject tmp = Instantiate(Resources.Load("Prefabs/ColorPicCanvas")) as 
        GameObject;
        tmp.GetComponent<colorPicWindow>().nowColorVector = nowc;
        tmp.GetComponent<colorPicWindow>().child = func;
    }
}


おおざっぱに説明すると
[SerializeField]ありのフィールド
:インスペクタでオブジェクトを設定。

pickwindowCreate関数
:色を選ぶためのウィンドウを色相に応じて生成する。空のテクスチャを生成してグラデーションを設定し、対象のImageに新しく設定したSpriteをセット。

SliderbackCreate関数
:pickwindowCreate関数と同様にして、右の彩度を設定するスライダーの背景、backgroundに対してグラデーションを設定する。

Okbuttonclick関数
:OKを押したときに、呼び出し側で登録した関数childを実行し、保存していたHSV値をRGBに変換して返す。

CreatePrefab関数
:staticで設定し、生成する際に外部から呼び出す。

setColor_ 関数
各スライダーのOnvalueChangeから呼び出し、valueの値をhsvとして保存する。

だいたいこんな感じです。

完成するとこんな感じのウィンドウが生成され、OKを押すとRGBを返します。
f:id:mikanbox55:20170820012935p:plain

Unityでドット絵を描く(3)

今回はドット絵を塗るキャンパスの拡大-縮小とキャンパスの移動を実装

まずは、キャンパスの移動と拡大縮小に関するUIを作ります.
f:id:mikanbox55:20170819022818p:plain

8方向に移動するため、キャンパス周りに8つのボタンを設置。
そして、その下に拡大縮小を制御するSliderを設置します。
矢印アイコンはAspect Ratio filterで縦横比を1:1に固定しています。
f:id:mikanbox55:20170819023033p:plain
ワイヤフレームで表示するとこんな感じです。
f:id:mikanbox55:20170819022917p:plain

ボタン押しっぱなしで操作させたいので、各ボタンにEvent Triggerを加えて、Pointer UpとPointer Downを加え関数を登録します。

拡大縮小に関する部分は以下の通り。前々回作成したクラスに以下の部分を付け加えます。

    public void Scalingcanvas(float value){
        Vector3 baseSize = new Vector3(0.4f,0.4f,0.4f *   (float)height / (float)width);
        GetComponent<Transform>().localScale = (value+0.1f) * 4 * baseSize;
        Nowscale = (value+0.1f)*4;
    }

この関数をSliderのOnValueChangeに登録することでスライダーを操作したときに呼び出され、valueにはSliderオブジェクトの値がはいります。
関数内では最初にベースとなる基本サイズを設定し、描画するキャンバスのサイズを受け取ったvalueと基本サイズの積によって計算し、設定します。



次に、移動は以下の通り。

    void Update () 
    {
.....
        if (buttonOn == true){
            Movecanvas(movenum);
        }
    }

    public void startMove(int num){
        movenum = num;
        buttonOn = true;
    }

    public void endMove(int num){
        buttonOn = false;
    }

    public void Movecanvas(int num){
        int ysign = 1 - 2*(num/8);
        int xsign = 1 - 2*((num/4)%2 );
        int x = num%2;
        int y =(num/2)%2;
        Nowposition = GetComponent<Transform>().localPosition;
        Nowposition = Nowposition + new Vector3((float)x * xsign,(float)y * ysign,0) * Nowscale/4;
        GetComponent<Transform>().localPosition = Nowposition;

        if (num==-1){
            Nowposition = new Vector3(0,0.2f,0);
            GetComponent<Transform>().localPosition = Nowposition;
        }
    }

StartMoveと endMoveをそれぞれボタンのEventtriggerのPointer Up とPointer Downに登録します。実際に移動を実現しているのはMovecanvas関数で、マウスが押されている間、実行されます。
Movecanvasは最初int型2つを引数とする関数として作成しようと思ったのですが、Unityのインスペクタは引数1つまでしか対応していないため、引数の値によって場合分けするような処理になってしまいました。まあここでしか使わないのでわざわざインスペクタの拡張するのもめんどくさいし。
各ボタンを押すことで、任意の方向に移動可能、移動量は現在の拡大倍率によって左右されます。

これでキャンバスの塗り、移動、拡大縮小などの機能は一通りできたので、次から塗り、着色の部分を実装していきます。
次はおそらくカラーピックの実装になると思います。

Unityでドット絵を描く(2)

前回とりあえず描くところまでは実装したので、今回はUIの配置とかを考えました
↓完成図
f:id:mikanbox55:20170817182612p:plain

手順は以下の通り
まずUI-Canvasを作成。このときCanvas-CanvasScalerをScale with Screen sizeに設定しておく.
ついでにUIなのでSort Orderも1とか2にしておく

作成したCanvasにimageを配置していく.基本的にはAnchorを使って思い通りのレイアウトになるよう調整

変種画面のサイズは後々変更するだろうからUI-Sliderを配置。SliderのFill Areaは削除しておく。
f:id:mikanbox55:20170817182951p:plain

プレビューとかは画面に置くときに縦横比を固定しておきたいので、Aspect Ratio Filterを Componentより追加
f:id:mikanbox55:20170817183143p:plain


パレット部分は画面に表示しきれないなーと思ったのでScrollRectで作成
ざっとこんな感じです。

次回はスライダー周りの動作を作っていこうと思います.

Unityでドット絵を描く(1)

Unityでドット絵を描こうと思い立ったので記事に。

参考記事↓
nn-hokuson.hatenablog.com


まずはオブジェクトの作成ということでヒエラルキーに3D ObjectのPlaneを生成
f:id:mikanbox55:20170815163038p:plain

テキトーに作ったmaterialをセットします。

で、アタッチするスクリプトは以下の通り。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class rayTexturePaint : MonoBehaviour {

    Texture2D drawTexture ;
    Color[] buffer;

    private int width=16;
    private int height=24;


    void Start () {
        buffer = new Color[width * height];

        drawTexture = new Texture2D (width, height, TextureFormat.RGBA32, false);
        drawTexture.filterMode = FilterMode.Point;
    }

    public void Draw(Vector2 p){
        Vector2 tmp = new Vector2(p.x*width,p.y*height);
        buffer.SetValue (Color.white, (int)(tmp.x) + (int)(tmp.y )* width );
    }

    void Update () 
    {
        if (Input.GetMouseButton (0)) 
        {
            Ray ray = Camera.main.ScreenPointToRay (Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast (ray, out hit, 100.0f)) Draw (hit.textureCoord);

            drawTexture.SetPixels (buffer);
            drawTexture.Apply ();
            GetComponent<Renderer> ().material.mainTexture = drawTexture;
        }
    }
}


参考にした記事では、アタッチしたオブジェクトのマテリアルにセットしたテクスチャ画像を操作していたため、サイズ変更とかアスペクト比が自由に変えられなかったため、
最初に空のオブジェクトを用意して上書きするようにしました。

実行するとこんな感じ
f:id:mikanbox55:20170815163838p:plain

これでとりあえず最低限のお絵描きはできたっぽいので、次は拡大縮小とかの機能をつけたいなと思います。

Android7.0以降におけるUnity での GameFeatプラグインの利用について

こんばんは

疾走勇者のアプリをリリースしてから数週間経ちましたが、どうやらいくつかの端末でクラッシュが起きているみたいなのでその原因を調査してみました。

GooglePlayConsole のAndroid Vitals のクラッシュより
f:id:mikanbox55:20170530001337p:plain


詳細をみたところGameFeat関連でエラーが起きている模様f:id:mikanbox55:20170530001420p:plain

なんかandroidのバージョンが7.0以降だけっぽいので以下のページより仕様を確認してきました

Android 7.0 の動作の変更点 | Android Developers

パーミッションの変更
の項目が怪しそうです。GameFeatプラグインが対応していない可能性はありますがなんとも言えないですね...

とりあえず手出しができないので困ったところです。
他にも同様の症状がみられるならGameFeatはそのうち外したほうがいいかもしれないですね...

疾走勇者リリース

RPG:疾走勇者をAndroidでリリースしました
https://play.google.com/store/apps/details?id=com.Company.mikanboxplay.google.com


制作期間は3ヶ月ほどです
そのうちIphoneでも出したいですね

それから、Admobのバナー広告を配置しているのですが、一番下に表示されなくてレビューも低くなってしまって失敗してしまったのですが原因がわからず困ってます。
同様の症状の人いませんかね..

配列宣言と初期化

多分、初歩的すぎてドン引きされそうですが、ちょっと躓いたので一応メモ

ゲームを作る際の敵データをクラスで作成し、それを配列にまとめたクラスを利用した時に、NullPointerエラーが出てしまった...以下その状況

public class En {
   public string name ="";
   public int DropItem1No;
   public int DropItem2No;
}

 

public static class Enemy{
 static int InstanceNo =1;
 public En[] Enlist = new En[InstanceNo];

}

\\別ソースで

Enemy.En[i].name ="敵";

\\↑ここでエラー

 

stringに代入する時にエラーがおきてるみたいで、なんでかなと考える事10分。

配列は宣言した時にメモリ空間だけ確保して実体を保っていないということを思いだした。だからstring型で代入エラーが出るんですね....多分

 

以下改変後

 

public class En {
   public string name ="";
   public int DropItem1No;
   public int DropItem2No;
}

 

public static class Enemy{
 static int InstanceNo =1;
 public En[] Enlist = new En[InstanceNo];//ここでメモリ空間のみ確保

 public Enemy(){//配列は初期化されないからコンストラクタで全部初期化する必要

  for(int i=0;i<InstanceNo;i++){
   Enlist[i]= new En();
  }

 }

}

 

 

はい無事コンパイル通りました。

すっごい初歩的だけどたまに忘れるので気をつけたいですね