using UnityEngine;
    using UnityEngine.Tilemaps;
    
    public class Box : MonoBehaviour
    {
        const float Gravity = -0.01f;
        const float OffsetY = -0.5f;
        const int   StrCut  = 8;
        const float TAnker  = 0.5f;
    
        [SerializeField]
        Tilemap tilemap;
        
        Time60     time60;
        Vector3    pos;
        Vector3Int gridPos;
        Vector3    speed    = new Vector3();
        Vector2[]  line     = new Vector2[2];
    
        int    index = 0;   //タイル(スプライト)の番号
        float  dist  = 0;   //めり込んだ長さ
        float  px    = 0;
        float  py    = 0;
        string str   = "";  //テキスト表示用
    
        bool   isGround = false;
    
        public string sText;
    
        // Start is called before the first frame update
        void Start()
        {
            GameObject time60Obj = GameObject.Find("Time60");
            time60 = time60Obj.GetComponent<Time60>();
    
            pos = this.transform.position;
            speed = Vector3.zero;
        }
    
        // Update is called once per frame
        void Update()
        {
            dist = 0;
    
            // 1/60秒ごとに処理をするための門番
            if( time60.CheckFlame() != true) return;
    
            //現在位置を受け取る
            pos = this.transform.position;
    
            //ボックスの横移動量
            speed.x = 0.01f;
            //ボックスの自由落下量
            speed.y = speed.y + Gravity;
    
            //接地状態では、Y方向の移動量をゼロにする
            if( isGround == true)  speed.y = 0;
    
            //まず、座標の仮移動
            pos.x = pos.x + speed.x;
            pos.y = pos.y + speed.y;
    
            //接地フラグをクリアする
            isGround = false;
    
            //今の場所のタイルの種類の番号を得る(1回目)
            index = this.CheckTerrain(pos);
    
            //タイルのローカル座標を得る(1回目)
            px = pos.x % 1;
            py = pos.y % 1;
            
             //まず、進入禁止を判定
            if( index == 1){
                line[0].x = gridPos.x;
                line[0].y = gridPos.y;
                line[1].x = gridPos.x + 1.0f;
                line[1].y = gridPos.y;
                
                //線分と現在座標の関係をチェックする
                dist = CheckLine( pos, line, 0);
                //接地フラグ
                isGround = true;
                //Y座標を補正
                pos.y = pos.y + dist;
            }
            
            //補正後再びびチェックする----------------------------------
            dist = 0;
    
            //今の場所のタイルの種類の番号を得る(2回目)
            index = this.CheckTerrain(pos);
    
            //タイルのローカル座標を得る(2回目)
            px = pos.x % 1;
            py = pos.y % 1;
    
            //タイルの種類ごとに処理を分ける
            switch(index){
                case 0:
                break;
                case 1: //進入禁止
                break;
                case 2: //上り45度
                    //線分の始点と終点を決める
                    line[0].x = gridPos.x;
                    line[0].y = gridPos.y;
                    line[1].x = gridPos.x + 1.0f;
                    line[1].y = gridPos.y + 1.0f;      
                    //線分と現在座標の関係をチェックする
                    dist = CheckLine( pos, line, 0);
                break;
                default:
                    dist = 0;
                break;
            }
    
            if( dist < 0){
                //接地フラグを立てる
                isGround = true;
            }
            //地形にめり込んだ長さを戻す
            pos.y = pos.y - dist;
    
            transform.position = pos;
        }
    
        //地形の線分より下にあるか調べ、その長さを返す
        private float CheckLine( Vector3 _cPos, Vector2[] _line,float _offsetY){
            bool inv  = false;  //上り下り反転フラグ
            float ret = 0;
            float x1  = 0;
            float y1  = 0;
    
            px = _cPos.x % 1;
            py = _cPos.y % 1;
    
            //Y軸の距離を出す
            y1 = _line[1].y - _line[0].y;
    
            //平行の場合
            if( y1 == 0) return 1 - py;
    
            //下り坂ならフラグを立てる
            if( y1 < 0) inv = true;
    
            //X軸の距離を出す
            x1 = _line[1].x - _line[0].x;
    
            //上り坂の場合(高さが+)
            if( inv != true){
                //Y位置と線分の高さを計算する
                ret = py - (y1 / x1) * px + _offsetY;
                if( ret > 0)
                    return 0;
                return ret;
            }
    
            //Y位置と線分の高さを計算する
            ret = py - (y1 / x1) * px - _offsetY;
            //下り坂の場合(高さが-)
            if( ret > 0)
                return 0;
            return  ret;
        }
    
        //指定の場所が地形その他の当たり判定に重なっているか?
        private int CheckTerrain(Vector3 _checkPos)
        {
            int number;

            //グリッド座標に変換する
            Vector3Int targetPosInt = tilemap.WorldToCell(_checkPos);
            //グリッド座標のスプライト情報を取得する
            Sprite spr = tilemap.GetSprite(targetPosInt);
    
            if(spr != null)
                str = spr.name.Substring( 8, spr.name.Length - 8); //"Terrain_"の文字を取り除く
            else
                str = "-1"; 
    
            //Int型に変換
            number = int.Parse(str);
            if( number > -1){
                return number;
            }
    
            return -1;
        }