using System;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class TextureTest2 : MonoBehaviour
    {
        //このスクリプトはDigitMaxで指定した桁まで対応可能
        const int DigitMax = 10;
        const float fps = 60.0f;

        //これらはインスペクターで指定する
        public int number;        //表示したい数値
        public int digitMax;      //表示したい桁数
    
        int digit = 0;                  //現在処理している桁
         float timecount = 0f;

        Image image;               //イメージ情報
        Shader shader;             //シェーダー情報
        Material[] material = new Material[DigitMax];          //マテリアル情報
    
        Vector2 textureSize;      //テクスチャ(数字1文字)の大きさ
        Vector2 textureOffset;   //イメージ内のテクスチャ(数字1文字の位置
        
    
        //インスペクターのデータで設定した内容を保存する
        [System.Serializable]
        public struct NumberRenderData
        {
            public Transform parentTrasform;  //親オブジェクト情報
            public Color color;                          //表示色
            public float justification;                 //位置揃いする間隔
            
            public NumberRenderData(Transform _parentTrasform, Color _color, float _justification): this()
            { 
                this.parentTrasform = _parentTrasform;
                this.color = _color;
                this.justification = _justification;
            }
        }
    
        [SerializeField]
        NumberRenderData data;
    
        //数字1桁あたりの情報
        struct CreateData
        {
            public RectTransform rectTrans;    //親オブジェクトからの距離など
            public Material material;               //マテリアル情報
        }
        //1桁当たりの情報をListで管理する
        List<CreateData> createList = new List<CreateData>();
    
        //新しい1桁を作成する
        CreateData Create(Image _image, int _number, int _digit)
        {
            //新しいゲームオブジェクト(インスタンス)を作成する
            var instance = new GameObject();
            instance.name = _image.sprite.name + _number.ToString();
            instance.transform.SetParent(data.parentTrasform);
    
            //新しいインスタンスのサイズをrectTransに記録する
            var rectTrans = instance.AddComponent<RectTransform>();
            instance.transform.localScale = Vector3.one;
            rectTrans.sizeDelta = data.parentTrasform.GetComponent<RectTransform>().sizeDelta;
    
            //使用するイメージ(テクスチャ)を新しいインスタンスに取得する
            instance.AddComponent<Image>();
            var image = instance.GetComponent<Image>();
            image.sprite = _image.sprite;
    
            //取得したシェーダーを元に新しいマテリアルを作成
            material[_digit] = new Material(shader);
             material[_digit].name = "_Material" + _number.ToString();
    
            //テクスチャ上の表示したい位置を取得(今回はX軸方向のみ)
            material[_digit].mainTextureOffset = CalcOffset( textureOffset,  _number);
    
            // 色を変更する
            material[_digit].color = new Color( data.color.r, data.color.g, data.color.b, 1.0f);
    
            //新しいマテリアルを適用
            instance.GetComponent<Image>().material =  material[_digit];
    
            var createData = new CreateData() { rectTrans = rectTrans , material = material[_digit]};
    
            return createData;
        }
    
        void Rendering(int number)
        {
            var num = number;
    
            //数値の最下位から(最上位-1)桁までの処理
            digit = 1;
            while( digit < digitMax  ){
                var createData = Create( image, num % 10, digit);
                createData.rectTrans.anchoredPosition3D = new Vector3(( digitMax - digit)* (createData.rectTrans.sizeDelta.x - data.justification), 0, 0);
                createList.Add(createData);
                num = (int)(num / 10);
                digit++;
            }
    
            //最上位桁(自分自身)の処理
            //シェーダー情報からマテリアルを作成
            material[0] = new Material(shader);
    
            //テクスチャ上の表示したい位置を取得(今回はX軸方向のみ)
            material[0].mainTextureOffset = CalcOffset( textureOffset, num);
    
            // 色を変更する
            material[0].color = new Color( data.color.r, data.color.g, data.color.b, 1.0f);
    
            //新しいマテリアルを適用
            GetComponent<Image>().material = material[0];
    
            digit = 0;
        }
    
        //オフセット移動する座標を計算する
        Vector2 CalcOffset(Vector2 _textureOffset,int _num)
        {
            Vector2 ret = new Vector2( _textureOffset.x * _num, _textureOffset.y);
            return ret;
        }
        
        //数字の更新時に呼ばれる関数
        void updateNumber(int _number)
        {
            var num = _number;

            //数値の最下位から(最上位-1)桁までの処理
            digit = 1; 
            while( digit < digitMax  ){
                //マテリアルのオフセットを桁の数字に合わせて変更する
                material[digit].mainTextureOffset = CalcOffset(textureOffset, num % 10 );
                num = (int)(num / 10);
                digit++;
            }
            //最上位桁のマテリアルのオフセットの変更
            material[0].mainTextureOffset = CalcOffset(textureOffset, num);
        }
        
        // 最初に呼び出される関数
        void Start()
        {
            //イメージ情報を取得
            image = this.GetComponent<Image>();
    
            //今ののシェーダー情報を取得
            shader = this.GetComponent<Image>().material.shader;
    
            //作成したマテリアルからテクスチャ1つあたりのサイズを得る
            var tex = this.GetComponent<Image>().sprite.texture;
            textureSize =new Vector2( tex.width, tex.height);
    
            //テクスチャ1つ分のオフセット幅を得る
            //1文字あたりの数字画像は正方形が前提なのでオフセットはテクスチャ画像の縦幅である
            textureOffset = new Vector2(   (float)tex.height / (float)tex.width ,  0f);  
       
            if (number < 0) return;
            Rendering(number);
        }
        
        //実行中に呼び出される関数
        void Update()
        {
            //1秒ごとにnumberをカウントアップする
           timecount +=  Time.deltaTime;
            if( timecount >1.0){
                timecount = 0f;
                number = number + 1;
                updateNumber(number);
            }
            
        }
        
        //そのフレームの最終に呼び出される関数
        void FixUpdate(){
           
        }
    
        //シーンを終了するときに呼ばれる関数
        private void OnDestroy()
        {   
            //各マテリアルで使ったメモリを開放する。
            foreach( Material mat in material){
                if( mat != null )
                    Destroy(mat);
            }
        }
    }