Exemplo n.º 1
0
        public override bool IsPassable()
        {
            AutoTileMap autoTileMap = AutoTileMap.Instance;

            if (autoTileMap.IsValidAutoTilePos(TileX, TileY))
            {
                for (int iLayer = autoTileMap.GetLayerCount() - 1; iLayer >= 0; --iLayer)
                {
                    if (autoTileMap.MapLayers[iLayer].LayerType == eLayerType.Ground)
                    {
                        AutoTile           autoTile = autoTileMap.GetAutoTile(TileX, TileY, iLayer);
                        eTileCollisionType collType = autoTile.Id >= 0 ? autoTileMap.Tileset.AutotileCollType[autoTile.Id] : eTileCollisionType.EMPTY;
                        if (IsEmptyTilePassable && collType == eTileCollisionType.EMPTY ||
                            collType == eTileCollisionType.PASSABLE || collType == eTileCollisionType.WALL)
                        {
                            return(true);
                        }
                        else if (collType == eTileCollisionType.BLOCK || collType == eTileCollisionType.FENCE)
                        {
                            return(false);
                        }
                    }
                }
            }
            return(false);
        }
Exemplo n.º 2
0
        void DrawCollisions()
        {
            float   fCollW       = MyAutoTileMap.Tileset.TileWorldWidth / 4;
            float   fCollH       = MyAutoTileMap.Tileset.TileWorldHeight / 4;
            Rect    rColl        = new Rect(0, 0, fCollW, -fCollH);
            Color   cColl        = new Color(1f, 0f, 0f, 0.1f);
            Vector3 vTopLeft     = HandleUtility.GUIPointToWorldRay(Vector3.zero).origin;
            Vector3 vBottomRight = HandleUtility.GUIPointToWorldRay(new Vector3(Screen.width, Screen.height)).origin;

            vTopLeft.y      = -vTopLeft.y;
            vBottomRight.y  = -vBottomRight.y;
            vTopLeft.x     -= (vTopLeft.x % fCollW) + fCollW / 2;
            vTopLeft.y     -= (vTopLeft.y % fCollH) + fCollH / 2;
            vBottomRight.x -= (vBottomRight.x % fCollW) - fCollW / 2;
            vBottomRight.y -= (vBottomRight.y % fCollH) - fCollH / 2;
            for (float y = vTopLeft.y; y <= vBottomRight.y; y += MyAutoTileMap.Tileset.TileWorldHeight / 4)
            {
                for (float x = vTopLeft.x; x <= vBottomRight.x; x += MyAutoTileMap.Tileset.TileWorldWidth / 4)
                {
                    eTileCollisionType collType = MyAutoTileMap.GetAutotileCollisionAtPosition(new Vector3(x, -y));
                    if (collType != eTileCollisionType.PASSABLE)
                    {
                        rColl.position = new Vector2(x - fCollW / 2, -(y - fCollH / 2));
                        UtilsGuiDrawing.DrawRectWithOutline(rColl, cColl, cColl);
                    }
                }
            }
        }
Exemplo n.º 3
0
//		public bool IsPassable()
//		{
//			AutoTileMap autoTileMap = AutoTileMap.Instance;
//
//			if (autoTileMap.IsValidAutoTilePos(TileX, TileY))
//			{
//				for( int iLayer = autoTileMap.GetLayerCount() - 1; iLayer >= 0; --iLayer )
//				{
//					if( autoTileMap.MapLayers[iLayer].LayerType == eLayerType.Ground )
//					{
//						AutoTile autoTile = autoTileMap.GetAutoTile(TileX, TileY, iLayer);
//						eTileCollisionType collType = autoTile.Id >= 0 ? autoTileMap.Tileset.AutotileCollType[autoTile.Id] : eTileCollisionType.EMPTY;
//						if( collType == eTileCollisionType.PASSABLE || collType == eTileCollisionType.WALL )
//						{
//							return true;
//						}
//						else if( collType == eTileCollisionType.BLOCK || collType == eTileCollisionType.FENCE )
//						{
//							return false;
//						}
//					}
//				}
//			}
//			return false;
//		}

        //A* Style pathfinding
        public Vector3 findPath()
        {
            AutoTile m_CurTile;
            AutoTile m_CurTile2;
            AutoTile m_CurTile3;
            Vector3  targetMapPos;

            float[,] map = new float[3, 3]; //Represents the 8 surrounding the object
            float idx    = -(1f * .32f);    //far left tile Column
            float idy    = (1f * .32f);     //Top most Row of tiles
            float lowest = 100f;

            low = new Vector3(0f, 0f, 0f);
            //Loops through each row
            for (int i = 0; i < 3; i++)
            {
                //Loops through each tile in this row
                for (int j = 0; j < 3; j++)
                {
                    float temp = Vector3.Distance(this.transform.position + new Vector3(idx, idy, 0f), targetTile);


                    map [i, j] = temp;
                    m_CurTile  = RpgMapHelper.GetAutoTileByPosition(this.transform.position + new Vector3(idx, idy, 0f), 0);
                    m_CurTile2 = RpgMapHelper.GetAutoTileByPosition(this.transform.position + new Vector3(idx, idy, 0f), 1);
                    m_CurTile3 = RpgMapHelper.GetAutoTileByPosition(this.transform.position + new Vector3(idx, idy, 0f), 2);
                    //targetMapPos = new Vector2(m_CurTile.TileX, m_CurTile.TileY);
                    targetMapPos = RpgMapHelper.GetTileCenterPosition(m_CurTile.TileX, m_CurTile.TileY);
                    eTileCollisionType collType  = AutoTileMap.Instance.GetAutotileCollisionAtPosition(targetMapPos);
                    eTileCollisionType collType2 = AutoTileMap.Instance.GetAutotileCollisionAtPosition(targetMapPos);
                    eTileCollisionType collType3 = AutoTileMap.Instance.GetAutotileCollisionAtPosition(targetMapPos);
                    if ((i == 0 && j == 0) || (i == 2 && j == 0) || (i == 0 && j == 2) || (i == 2 && j == 2) || (i == 1 && j == 1) ||
                        collType != eTileCollisionType.PASSABLE
                        )
                    {
                        temp = 100f;
                    }

                    if (temp < lowest)
                    {
                        lowest = temp;

                        low = new Vector3(idx, idy, 0f);
                    }

                    idx += .32f;
                }

                idy -= .32f;

                idx = -.32f;
            }

            Vector3 decision = low;

            return(decision);
        }
Exemplo n.º 4
0
        // special case for walls
        bool _IsWallPassable(MapTileNode neighNode)
        {
            AutoTileMap        autoTileMap   = AutoTileMap.Instance;
            eTileCollisionType collType      = eTileCollisionType.EMPTY;
            eTileCollisionType collTypeNeigh = eTileCollisionType.EMPTY;

            for (int iLayer = autoTileMap.GetLayerCount() - 1; iLayer >= 0; --iLayer)
            {
                if (autoTileMap.MapLayers[iLayer].LayerType == eLayerType.Ground)
                {
                    AutoTile autoTile      = autoTileMap.GetAutoTile(TileX, TileY, iLayer);
                    AutoTile autoTileNeigh = autoTileMap.GetAutoTile(neighNode.TileX, neighNode.TileY, iLayer);

                    if (autoTile.Id == autoTileNeigh.Id) // you can walk over two wall tiles if they have the same type
                    {
                        if (autoTile.Id >= 0)
                        {
                            return(true);
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // collType will keep the first collision type found of type wall or passable
                        if (collType != eTileCollisionType.PASSABLE && collType != eTileCollisionType.WALL)
                        {
                            collType = autoTile.Id >= 0 ? autoTileMap.Tileset.AutotileCollType[autoTile.Id] : eTileCollisionType.EMPTY;
                        }
                        if (collTypeNeigh != eTileCollisionType.PASSABLE && collTypeNeigh != eTileCollisionType.WALL)
                        {
                            collTypeNeigh = autoTileNeigh.Id >= 0 ? autoTileMap.Tileset.AutotileCollType[autoTileNeigh.Id] : eTileCollisionType.EMPTY;
                        }

                        if (collType == eTileCollisionType.PASSABLE && collTypeNeigh == eTileCollisionType.PASSABLE)
                        {
                            return(true);
                        }
                        else if (collType == eTileCollisionType.WALL || collTypeNeigh == eTileCollisionType.WALL)
                        {
                            return(false);
                        }
                    }
                }
            }
            return(true);
        }
Exemplo n.º 5
0
        const int k_subDiv = 6;         // sub divisions
        public bool IsColliding(Vector3 vPos)
        {
            Vector3 vCheckedPos = Vector3.zero;

            for (int i = 0; i < k_subDiv; ++i)
            {
                for (int j = 0; j < k_subDiv; ++j)
                {
                    vCheckedPos.x = vPos.x + Mathf.Lerp(CollRect.x, CollRect.x + CollRect.width, (float)i / (k_subDiv - 1));
                    vCheckedPos.y = vPos.y + Mathf.Lerp(CollRect.y, CollRect.y + CollRect.height, (float)j / (k_subDiv - 1));

                    eTileCollisionType collType = AutoTileMap.Instance.GetAutotileCollisionAtPosition(vCheckedPos);
                    if (collType != eTileCollisionType.PASSABLE && collType != eTileCollisionType.OVERLAY)
                    {
                        return(true);
                    }
                }
            }
            return(false);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Use a Ray2D to check if there is a collision with the map trough the ray. If there is a collision, return value will be >= 0f.
        /// </summary>
        /// <param name="ray">Ray2D used for raycasting</param>
        /// <param name="distance">Distance to be checked</param>
        /// <param name="precission">Distance increment from ray origin to check with map for collisions. Leave it <= 0 for default value.</param>
        /// <returns></returns>
        public static float Raycast(Ray2D ray, float distance, float precission = 0f)
        {
            if (precission <= 0)
            {
                precission = AutoTileMap.Instance.CellSize.x / 2f;
            }
            Vector2 vInc   = ray.direction.normalized * precission;
            Vector2 curPos = ray.origin;

            for (float d = 0; d <= distance; d += precission)
            {
                eTileCollisionType collType = AutoTileMap.Instance.GetAutotileCollisionAtPosition(curPos);
                Debug.DrawLine(curPos, curPos + vInc, collType == eTileCollisionType.BLOCK? Color.red : Color.green);
                if (collType == eTileCollisionType.BLOCK)
                {
                    return(d);
                }
                curPos += vInc;
            }

            return(-1f);
        }
Exemplo n.º 7
0
        // NOTE: depending of the collType and tilePartType, this method returns the collType or eTileCollisionType.PASSABLE
        // This is for special tiles like Fence and Wall where not all of tile part should return collisions
        eTileCollisionType _GetTilePartCollision( eTileCollisionType collType, eTilePartType tilePartType, int tilePartIdx, Vector2 vTilePartOffset )
        {
            int tilePartHalfW = Tileset.TilePartWidth / 2;
            int tilePartHalfH = Tileset.TilePartHeight / 2;
            if( collType == eTileCollisionType.FENCE )
            {
                if( tilePartType == eTilePartType.EXT_CORNER || tilePartType == eTilePartType.V_SIDE )
                {
                    // now check inner collision ( half left for tile AC and half right for tiles BD )
                    // AX|BX|A1|B1	A: 0
                    // AX|BX|C1|D1	B: 1
                    // A2|B4|A4|B2	C: 2
                    // C5|D3|C3|D5	D: 3
                    // A5|B3|A3|B5
                    // C2|D4|C4|D2
                    if(
                       (tilePartIdx == 0 || tilePartIdx == 2) && (vTilePartOffset.x < tilePartHalfW ) ||
                       (tilePartIdx == 1 || tilePartIdx == 3) && (vTilePartOffset.x > tilePartHalfW )
                    )
                    {
                        return eTileCollisionType.PASSABLE;
                    }
                }
            }
            else if( collType == eTileCollisionType.WALL )
            {
                if( tilePartType == eTilePartType.INTERIOR )
                {
                    return eTileCollisionType.PASSABLE;
                }
                else if( tilePartType == eTilePartType.H_SIDE )
                {
                    if(
                       (tilePartIdx == 0 || tilePartIdx == 1) && (vTilePartOffset.y >= tilePartHalfH ) ||
                       (tilePartIdx == 2 || tilePartIdx == 3) && (vTilePartOffset.y < tilePartHalfH )
                       )
                    {
                        return eTileCollisionType.PASSABLE;
                    }
                }
                else if( tilePartType == eTilePartType.V_SIDE )
                {
                    if(
                       (tilePartIdx == 0 || tilePartIdx == 2) && (vTilePartOffset.x >= tilePartHalfW ) ||
                       (tilePartIdx == 1 || tilePartIdx == 3) && (vTilePartOffset.x < tilePartHalfW )
                       )
                    {
                        return eTileCollisionType.PASSABLE;
                    }
                }
                else
                {
                    Vector2 vRelToIdx0 = vTilePartOffset; // to check only the case (tilePartIdx == 0) vTilePartOffset coords are mirrowed to put position over tileA with idx 0
                    vRelToIdx0.x = (int)vRelToIdx0.x; // avoid precission errors when mirrowing, as 0.2 is 0, but -0.2 is 0 as well and should be -1
                    vRelToIdx0.y = (int)vRelToIdx0.y;
                    if (tilePartIdx == 1) vRelToIdx0.x = -vRelToIdx0.x + Tileset.TilePartWidth - 1;
                    else if (tilePartIdx == 2) vRelToIdx0.y = -vRelToIdx0.y + Tileset.TilePartHeight - 1;
                    else if (tilePartIdx == 3) vRelToIdx0 = -vRelToIdx0 + new Vector2(Tileset.TilePartWidth - 1, Tileset.TilePartHeight - 1);

                    if( tilePartType == eTilePartType.INT_CORNER )
                    {
                        if( (int)vRelToIdx0.x / tilePartHalfW == 1 || (int)vRelToIdx0.y / tilePartHalfH == 1 )
                        {
                            return eTileCollisionType.PASSABLE;
                        }
                    }
                    else if( tilePartType == eTilePartType.EXT_CORNER )
                    {
                        if( (int)vRelToIdx0.x / tilePartHalfW == 1 && (int)vRelToIdx0.y / tilePartHalfH == 1 )
                        {
                            return eTileCollisionType.PASSABLE;
                        }
                    }

                }
            }
            return collType;
        }
Exemplo n.º 8
0
        void Update()
        {
            if (!m_isInitialized)
            {
                Init();
                return;
            }

            #region Draw Collisions
            // Generate texture again in case window has been resized
            Vector2 screenSize = new Vector2(Screen.width, Screen.height);
            if (m_prevScreenSize != screenSize)
            {
                _GenerateCollisionTexture();
            }
            m_prevScreenSize = screenSize;

            m_spriteCollLayer.SetActive(m_showCollisions);
            if (m_showCollisions && (int)(Time.timeSinceLevelLoad * 4) % 2 == 0)
            {
                SpriteRenderer sprRender = m_spriteCollLayer.GetComponent <SpriteRenderer>();
                Vector3        vPos      = m_camera2D.transform.position;
                vPos.x -= (vPos.x % (m_autoTileMap.CellSize.x / 4));
                vPos.y -= (vPos.y % (m_autoTileMap.CellSize.y / 4));
                vPos.z += 1f;

                // Collision texture position snap to a quarter of tile part
                sprRender.transform.position = vPos;

                // Collision texture pixel scaled to a quarter of tile part
                sprRender.transform.localScale = new Vector3((m_autoTileMap.Tileset.TilePartWidth / 2), (m_autoTileMap.Tileset.TilePartHeight / 2), 1f);

                vPos = m_camera2D.Camera.WorldToScreenPoint(sprRender.transform.position);                   // vPos = center of collision texture in screen coords
                Vector3 vTopLeftOff = new Vector3(sprRender.sprite.texture.width * (m_autoTileMap.Tileset.TilePartWidth / 2) / 2, -sprRender.sprite.texture.height * (m_autoTileMap.Tileset.TilePartHeight / 2) / 2) * m_camera2D.Zoom;
                vPos -= vTopLeftOff;
                vPos  = m_camera2D.Camera.ScreenToWorldPoint(vPos); // vPos is now the top left corner of the collison texture in world coordinates

                Color32[] colors  = sprRender.sprite.texture.GetPixels32();
                float     factorX = m_autoTileMap.CellSize.x / 4; //smallest collision part has a size of a quarter of tile part
                float     factorY = m_autoTileMap.CellSize.y / 4;
                for (int y = 0; y < sprRender.sprite.texture.height; ++y)
                {
                    for (int x = 0; x < sprRender.sprite.texture.width; ++x)
                    {
                        Vector3 vCheckPos = vPos;
                        vCheckPos.x += (x + 0.5f) * factorX;
                        vCheckPos.y -= (y + 0.5f) * factorY;
                        eTileCollisionType collType = m_autoTileMap.GetAutotileCollisionAtPosition(vCheckPos);
                        //Color32 color = (x+y)%2 == 0? new Color32(0, 0, 64, 128) : new Color32(64, 0, 0, 128) ;
                        Color32 color = new Color32(0, 0, 0, 0);
                        colors[(sprRender.sprite.texture.height - 1 - y) * sprRender.sprite.texture.width + x] = (collType != eTileCollisionType.PASSABLE)? new Color32(255, 0, 0, 128) : color;
                    }
                }
                sprRender.sprite.texture.SetPixels32(colors);
                sprRender.sprite.texture.Apply();
            }
            #endregion

            if (Input.GetKeyDown(KeyCode.Delete))  //TODO: only delete the tiles in ground layer, fix this
            {
                // select delete tile
                m_selectedTileIdx = -1;

                // Remove Brush
                m_autoTileMap.BrushGizmo.Clear();
                m_tilesetSelStart = m_tilesetSelEnd = -1;
            }

            #region Undo / Redo
            if (m_isCtrlKeyHold)
            {
                if (Input.GetKeyDown(KeyCode.Z))
                {
                    m_autoTileMap.BrushGizmo.UndoAction();
                }
                else if (Input.GetKeyDown(KeyCode.Y))
                {
                    m_autoTileMap.BrushGizmo.RedoAction();
                }

                //+++ Key Repetition Implementation
                if (Input.GetKey(KeyCode.Z))
                {
                    m_keyPressTimer += Time.deltaTime;
                    if (m_keyPressTimer >= k_timeBeforeKeyRepeat)
                    {
                        m_keyPressTimer -= k_timeBetweenKeyRepeat;
                        m_autoTileMap.BrushGizmo.UndoAction();
                    }
                }
                else if (Input.GetKey(KeyCode.Y))
                {
                    m_keyPressTimer += Time.deltaTime;
                    if (m_keyPressTimer >= k_timeBeforeKeyRepeat)
                    {
                        m_keyPressTimer -= k_timeBetweenKeyRepeat;
                        m_autoTileMap.BrushGizmo.RedoAction();
                    }
                }
                else
                {
                    m_keyPressTimer = 0f;
                }
                //---
            }
            #endregion

            if (Input.GetKeyDown(KeyCode.M))
            {
                m_showMinimap = !m_showMinimap;
            }
            if (Input.GetKeyDown(KeyCode.C))
            {
                m_showCollisions = !m_showCollisions;
            }

            bool isMouseLeft      = Input.GetMouseButton(0);
            bool isMouseRight     = Input.GetMouseButton(1);
            bool isMouseMiddle    = Input.GetMouseButton(2);
            bool isMouseLeftDown  = Input.GetMouseButtonDown(0);
            bool isMouseRightDown = Input.GetMouseButtonDown(1);

            m_drawSelectionRect = false;

            Vector3 vGuiMouse      = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
            Vector3 vGuiMouseDelta = vGuiMouse - m_mousePrevPos;
            m_mousePrevPos = vGuiMouse;

            //+++ Set window with focus
            if (!isMouseLeft)
            {
                if (m_rEditorRect.Contains(vGuiMouse))
                {
                    m_focusWindow = eEditorWindow.TOOLS;
                }
                else if (m_rMinimapRect.Contains(vGuiMouse) && m_showMinimap)
                {
                    m_focusWindow = eEditorWindow.MINIMAP;
                }
                // Added an extra padding to avoid drawing tiles when resizing window
                else if (new Rect(m_rEditorRect.x + m_rEditorRect.width + 10f, 10f, Screen.width - 20f - (m_rEditorRect.x + m_rEditorRect.width), Screen.height - 20f).Contains(vGuiMouse))
                {
                    m_focusWindow = eEditorWindow.MAPVIEW;
                }
                else
                {
                    m_focusWindow = eEditorWindow.NONE;
                }
            }
            //---

            // drag and move over the map
            if (isMouseMiddle)
            {
                if (m_camera2DFollowBehaviour)
                {
                    m_camera2DFollowBehaviour.Target = null;
                }
                Vector3 vTemp = vGuiMouseDelta; vTemp.y = -vTemp.y;
                m_camera2D.transform.position -= (vTemp / 100) / m_camera2D.Zoom;
            }

            //
            // Inputs inside Editor Rect
            //
            if (m_rEditorRect.Contains(vGuiMouse))
            {
                if (m_rTilesetRect.Contains(vGuiMouse))
                {
                    vGuiMouse += new Vector3(m_scrollPos.x, m_scrollPos.y);
                    Vector3 vOff        = new Vector2(vGuiMouse.x, vGuiMouse.y) - m_rTilesetRect.position;
                    int     tileX       = (int)(vOff.x / k_visualTileWidth);
                    int     tileY       = (int)(vOff.y / k_visualTileHeight);
                    int     autotileIdx = tileY * m_autoTileMap.Tileset.AutoTilesPerRow + tileX + (m_subTilesetIdx * 256);

                    if (isMouseLeftDown || isMouseRightDown && m_isCtrlKeyHold)
                    {
                        if (m_isCtrlKeyHold)
                        {
                            // cycle pressed tile collision type
                            int collType = (int)m_autoTileMap.Tileset.AutotileCollType[autotileIdx];
                            collType += isMouseLeftDown? 1 : (int)eTileCollisionType._SIZE - 1;
                            collType %= (int)eTileCollisionType._SIZE;
                            m_autoTileMap.Tileset.AutotileCollType[autotileIdx] = (eTileCollisionType)(collType);
                        }
                        else
                        {
                            // select pressed tile
                            m_selectedTileIdx = autotileIdx;

                            // Remove Brush
                            m_autoTileMap.BrushGizmo.Clear();
                            m_tilesetSelStart = m_tilesetSelEnd = -1;
                        }
                    }
                    else if (isMouseRightDown)
                    {
                        m_tilesetSelStart = m_tilesetSelEnd = autotileIdx;
                    }
                    else if (isMouseRight)
                    {
                        m_tilesetSelEnd = autotileIdx;
                    }
                    else if (m_tilesetSelStart >= 0 && m_tilesetSelEnd >= 0)
                    {
                        m_autoTileMap.BrushGizmo.RefreshBrushGizmoFromTileset(m_tilesetSelStart, m_tilesetSelEnd);
                        m_tilesetSelStart = m_tilesetSelEnd = -1;
                    }
                }
            }
            //
            // Inputs inside Minimap Rect
            //
            else if (m_showMinimap && m_rMinimapRect.Contains(vGuiMouse) && m_focusWindow == eEditorWindow.MINIMAP)
            {
                if (isMouseLeft)
                {
                    float   minimapScale = m_rMinimapRect.width / m_autoTileMap.MinimapTexture.width;
                    Vector3 vPos         = vGuiMouse - new Vector3(m_rMinimapRect.position.x, m_rMinimapRect.position.y);
                    vPos.y  = -vPos.y;
                    vPos.x *= m_autoTileMap.CellSize.x / minimapScale;
                    vPos.y *= m_autoTileMap.CellSize.y / minimapScale;
                    vPos.z  = m_camera2D.transform.position.z;
                    m_camera2D.transform.position = vPos;
                    if (m_camera2DFollowBehaviour)
                    {
                        m_camera2DFollowBehaviour.Target = null;
                    }
                }
            }
            //
            // Insputs inside map view
            //
            else if (m_focusWindow == eEditorWindow.MAPVIEW)
            {
                Vector3 vWorldMousePos = m_autoTileMap.ViewCamera.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, Input.mousePosition.y));
                m_autoTileMap.BrushGizmo.UpdateBrushGizmo(vWorldMousePos);

                if (isMouseRight || isMouseLeft)
                {
                    m_drawSelectionRect = isMouseRight;

                    //+++ Move camera automatically when near bounds
                    if (isMouseLeft)
                    {
                        float fAutoDragDistX = m_rMapViewRect.width / 15;
                        float fAutoDragDistY = m_rMapViewRect.height / 15;
                        float fHDist         = m_rMapViewRect.center.x - vGuiMouse.x;
                        float fVDist         = m_rMapViewRect.center.y - vGuiMouse.y;
                        float fHSpeed        = Mathf.Lerp(0f, -Mathf.Sign(fHDist), Mathf.Abs(fHDist) < (m_rMapViewRect.width / 2 - fAutoDragDistX)? 0 : 1f - (m_rMapViewRect.width / 2 - Mathf.Abs(fHDist)) / fAutoDragDistX);
                        float fVSpeed        = Mathf.Lerp(0f, Mathf.Sign(fVDist), Mathf.Abs(fVDist) < (m_rMapViewRect.height / 2 - fAutoDragDistY)? 0 : 1f - (m_rMapViewRect.height / 2 - Mathf.Abs(fVDist)) / fAutoDragDistY);
                        if (fVSpeed != 0f || fHSpeed != 0f)
                        {
                            if (m_camera2DFollowBehaviour)
                            {
                                m_camera2DFollowBehaviour.Target = null;
                            }
                            m_camera2D.transform.position += (new Vector3(fHSpeed, fVSpeed, 0f) / 30) / m_camera2D.Zoom;
                        }
                    }
                    //---

                    Ray   ray      = Camera.main.ScreenPointToRay(Input.mousePosition);
                    Plane hPlane   = new Plane(Vector3.forward, Vector3.zero);
                    float distance = 0;
                    if (hPlane.Raycast(ray, out distance))
                    {
                        // get the hit point:
                        Vector3 vPos   = ray.GetPoint(distance);
                        int     tile_x = (int)(vPos.x / m_autoTileMap.CellSize.x);
                        int     tile_y = (int)(-vPos.y / m_autoTileMap.CellSize.y);

                        // for optimization, is true when mouse is over a diffent tile during the first update
                        bool isMouseTileChanged = (tile_x != m_prevMouseTileX) || (tile_y != m_prevMouseTileY);

                        //if ( m_autoTileMap.IsValidAutoTilePos(tile_x, tile_y)) // commented to allow drawing outside map, useful when brush has a lot of copied tiles
                        {
                            int gndTileType        = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer).Id;
                            int gndOverlayTileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, m_autoTileMap.BrushGizmo.SelectedLayer + 1).Id;

                            // mouse right for tile selection
                            if (isMouseRightDown || isMouseRight && isMouseTileChanged)
                            {
                                if (isMouseRightDown)
                                {
                                    m_startDragTileX = tile_x;
                                    m_startDragTileY = tile_y;

                                    // copy tile
                                    if (m_isCtrlKeyHold)
                                    {
                                        m_selectedTileIdx = -2;                                         //NOTE: -2 means, ignore this tile when painting
                                    }
                                    else
                                    {
                                        m_selectedTileIdx = gndTileType >= 0? gndTileType : gndOverlayTileType;
                                    }
                                }
                                m_dragTileX = tile_x;
                                m_dragTileY = tile_y;

                                // Remove Brush
                                m_autoTileMap.BrushGizmo.Clear();
                                m_tilesetSelStart = m_tilesetSelEnd = -1;
                            }
                            // isMouseLeft
                            else if (isMouseLeftDown || isMouseTileChanged)                              // avoid Push the same action twice during mouse drag
                            {
                                AutoTileBrush.TileAction action = new AutoTileBrush.TileAction();
                                if (m_autoTileMap.BrushGizmo.BrushAction != null)
                                {
                                    //+++ case of multiple tiles painting
                                    action.CopyRelative(m_autoTileMap, m_autoTileMap.BrushGizmo.BrushAction, tile_x, tile_y);
                                    if (m_isCtrlKeyHold && (m_autoTileMap.BrushGizmo.SelectedLayer + 1) < m_autoTileMap.GetLayerCount())
                                    {
                                        // old functionality: ground tiles become ground overlay, ground overlay are removed, overlay tiles remains
                                        // Tiles in SelectedLayer are moved to next layer
                                        action.BecomeOverlay(m_autoTileMap.BrushGizmo.SelectedLayer);
                                    }
                                }
                                else
                                {
                                    //+++ case of single tile painting
                                    // If smart brush is enabled, the tiles with collision type Overlay will be placed directly in the first overlay layer found over current SelectedLayer
                                    int overlayLayer = m_autoTileMap.FindFirstLayerIdx(eLayerType.Overlay, m_autoTileMap.BrushGizmo.SelectedLayer);
                                    if (m_autoTileMap.BrushGizmo.SmartBrushEnabled && overlayLayer >= 0 && m_selectedTileIdx >= 0 && m_autoTileMap.Tileset.AutotileCollType[m_selectedTileIdx] == eTileCollisionType.OVERLAY)
                                    {
                                        action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, overlayLayer);
                                    }
                                    else
                                    {
                                        if (m_isCtrlKeyHold || m_autoTileMap.IsAutoTileHasAlpha(m_selectedTileIdx) && m_autoTileMap.BrushGizmo.SmartBrushEnabled)
                                        {
                                            // Put tiles with alpha in the layer over Selected Layer
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, m_autoTileMap.BrushGizmo.SelectedLayer + 1);
                                        }
                                        else if (m_selectedTileIdx >= 0)
                                        {
                                            // Paint the selected tile
                                            action.Push(m_autoTileMap, tile_x, tile_y, m_selectedTileIdx, m_autoTileMap.BrushGizmo.SelectedLayer);
                                        }
                                        else //if (m_selectedTileIdx < 0)
                                        {
                                            // Delete all tiles of all layers
                                            for (int i = 0; i < m_autoTileMap.GetLayerCount(); ++i)
                                            {
                                                if (
                                                    m_autoTileMap.MapLayers[i].LayerType == eLayerType.Ground ||
                                                    m_autoTileMap.MapLayers[i].LayerType == eLayerType.Overlay ||
                                                    m_autoTileMap.MapLayers[i].LayerType == eLayerType.FogOfWar
                                                    )
                                                {
                                                    action.Push(m_autoTileMap, tile_x, tile_y, -1, i);
                                                }
                                            }
                                        }
                                    }
                                }

                                m_autoTileMap.BrushGizmo.PerformAction(action);
                            }
                        }

                        m_prevMouseTileX = tile_x;
                        m_prevMouseTileY = tile_y;
                    }
                }
                else
                {
                    // Copy selected tiles
                    if (m_dragTileX != -1 && m_dragTileY != -1)
                    {
                        m_autoTileMap.BrushGizmo.BrushAction = new AutoTileBrush.TileAction();
                        int startTileX = Mathf.Min(m_startDragTileX, m_dragTileX);
                        int startTileY = Mathf.Min(m_startDragTileY, m_dragTileY);
                        int endTileX   = Mathf.Max(m_startDragTileX, m_dragTileX);
                        int endTileY   = Mathf.Max(m_startDragTileY, m_dragTileY);

                        for (int tile_x = startTileX; tile_x <= endTileX; ++tile_x)
                        {
                            for (int tile_y = startTileY; tile_y <= endTileY; ++tile_y)
                            {
                                // Tile position is relative to last released position ( m_dragTile )
                                if (m_isCtrlKeyHold)
                                {
                                    // Copy overlay only
                                    for (int i = m_autoTileMap.BrushGizmo.SelectedLayer + 1; i < m_autoTileMap.GetLayerCount(); ++i)
                                    {
                                        int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                        if (
                                            (m_autoTileMap.MapLayers[i].LayerType != eLayerType.Ground) ||
                                            (tileType >= 0) // this allow paste overlay tiles without removing ground or ground overlay
                                            )
                                        {
                                            m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                        }
                                    }
                                }
                                else
                                {
                                    for (int i = 0; i < m_autoTileMap.GetLayerCount(); ++i)
                                    {
                                        int tileType = m_autoTileMap.GetAutoTile(tile_x, tile_y, i).Id;
                                        m_autoTileMap.BrushGizmo.BrushAction.Push(m_autoTileMap, tile_x - m_dragTileX, tile_y - m_dragTileY, tileType, i);
                                    }
                                }
                            }
                        }

                        m_autoTileMap.BrushGizmo.RefreshBrushGizmo(startTileX, startTileY, endTileX, endTileY, m_dragTileX, m_dragTileY, m_isCtrlKeyHold);

                        m_dragTileX = m_dragTileY = -1;
                    }

                    if (Input.GetAxis("Mouse ScrollWheel") < 0)                     // back
                    {
                        if (m_camera2D.Zoom > 1f)
                        {
                            m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom - 1, 1);
                        }
                        else
                        {
                            m_camera2D.Zoom = Mathf.Max(m_camera2D.Zoom / 2f, 0.05f);
                        }
                    }
                    else if (Input.GetAxis("Mouse ScrollWheel") > 0)                     // forward
                    {
                        if (m_camera2D.Zoom >= 1f)
                        {
                            m_camera2D.Zoom = Mathf.Min(m_camera2D.Zoom + 1, 10);
                        }
                        else
                        {
                            m_camera2D.Zoom *= 2f;
                        }
                    }
                }
            }
        }