<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>TweakGame</title>
	<atom:link href="https://tweakgame.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://tweakgame.com/</link>
	<description>Game Devlog, Tutorial, and reviews</description>
	<lastBuildDate>Fri, 24 May 2024 16:03:21 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.7.5</generator>

<image>
	<url>https://tweakgame.com/wp-content/uploads/2024/03/android-chrome-512x512-1.png</url>
	<title>TweakGame</title>
	<link>https://tweakgame.com/</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Isometric Camera Controller 3D &#8211; Godot Engine</title>
		<link>https://tweakgame.com/isometric-camera-controller-3d-godot-engine/</link>
					<comments>https://tweakgame.com/isometric-camera-controller-3d-godot-engine/#respond</comments>
		
		<dc:creator><![CDATA[Samee]]></dc:creator>
		<pubDate>Tue, 07 May 2024 08:30:31 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[godot]]></category>
		<category><![CDATA[Isometric Camera]]></category>
		<guid isPermaLink="false">https://tweakgame.com/?p=3080</guid>

					<description><![CDATA[<p>Introduction Hello everyone, this post is about setting up an Isometric Camera Controller for the Godot Engine. This controller enables&#8230;</p>
<p>The post <a href="https://tweakgame.com/isometric-camera-controller-3d-godot-engine/">Isometric Camera Controller 3D &#8211; Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<h4 class="wp-block-heading">Introduction</h4>



<p>Hello everyone, this post is about setting up an Isometric Camera Controller for the Godot Engine. This controller enables us to grab, rotate, zoom, and edge pan the camera similar to other Real-Time Strategy (RTS) games. For this guide, I will be using Godot version 4.2.2, and the scripting language will be C#.</p>



<h4 class="wp-block-heading">Isometric Camera Setup in Godot Editor</h4>



<p>First, create a new project and set up a basic scene with a plane and cubes. Then, add a Camera3D node. If you select the Camera3D node, you will see a preview button which, as the name implies, gives you a preview of the camera view.</p>



<figure class="wp-block-image size-full is-resized"><img fetchpriority="high" decoding="async" width="1023" height="437" src="https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201041-1.png?x24571" alt="" class="wp-image-3099" style="width:780px;height:auto" srcset="https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201041-1.png 1023w, https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201041-1-300x128.png 300w, https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201041-1-768x328.png 768w, https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201041-1-585x250.png 585w" sizes="(max-width: 1023px) 100vw, 1023px" /></figure>



<div class="wp-block-media-text is-stacked-on-mobile is-vertically-aligned-center" style="grid-template-columns:30% auto"><figure class="wp-block-media-text__media"><img decoding="async" width="283" height="269" src="https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-200941.png?x24571" alt="" class="wp-image-3097 size-full"/></figure><div class="wp-block-media-text__content">
<p>Then, under Inspector -&gt; Camera3D properties, make sure that the projection is orthogonal, which ensures that objects remain the same size on the screen no matter how far away they are. The &#8220;Size&#8221; property is used to adjust the camera size and can be used for the zoom in/out feature.</p>
</div></div>



<div class="wp-block-media-text is-stacked-on-mobile is-vertically-aligned-center" style="grid-template-columns:30% auto"><figure class="wp-block-media-text__media"><img decoding="async" width="275" height="304" src="https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201005.png?x24571" alt="" class="wp-image-3100 size-full" srcset="https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201005.png 275w, https://tweakgame.com/wp-content/uploads/2024/05/Screenshot-2024-05-04-201005-271x300.png 271w" sizes="(max-width: 275px) 100vw, 275px" /></figure><div class="wp-block-media-text__content">
<p class="has-text-align-left">Currently, if you look at the preview, you will see nothing being projected. To make it work, we have to modify the Transform Properties, especially the y-position and x-rotation. The y-position moves the camera up or down depending on the value and can be used to avoid clipping. Here, a rotation of x=-90 gives a flat orthogonal view, while x=-45 gives you an isometric view. You can easily adjust the angle for your desired camera view or effect.</p>
</div></div>



<p>Now, after finishing the camera setup, let&#8217;s move toward the camera controller script.</p>



<h4 class="wp-block-heading">Isometric Camera Controller Script</h4>



<p>Since we will be panning and rotating the camera, we don&#8217;t want to pan/rotate the actual camera node. Instead, make a new 3D Node and name it appropriately; for this guide, I will name it &#8216;CameraHolder&#8217;. Make the Camera3D a child of the &#8216;CameraHolder&#8217; node. Create a new script called &#8216;CameraController&#8217; and attach it to the &#8216;CameraHolder&#8217; node and open it.</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;--cbp-line-number-width:calc(3 * 0.6 * .75rem);line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#ffffff"><span style="background:#2f363c;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#ffffff">C#</span></span><span role="button" tabindex="0" data-code="
public partial class CameraController : Node3D
{
    private readonly float _edgePanningTriggerOffsetValue = 2f;
    private readonly float _panningCameraSpeed = 50f; 
    private readonly float _middleMouseGrabCameraSpeed = 5f;
    private readonly int _zoomMinDisatance = 20;
    private readonly int _zoomMaxDisatance = 60;
    private readonly int _zoomAmountPerRoll = 10;
    private float _currentSize = 0f;
    private float _smoothTimer = 0.0f;
    private float _smoothZoomTime = 1.0f;
    private float _screenRatio;

    private Vector2 _size;
    private Vector2 _mouseRelativeVel = Vector2.Zero;
    private bool _applyZoomSmooth = false;
    private bool _rotateCamera = false;
    private bool _isDragging = false;

    [Export] private Camera3D _camera;
    public EdgePannigState pannigState = EdgePannigState.None;
    public override void _Ready()
    {
        _currentSize = _camera.Size;
        _size = GetViewport().GetVisibleRect().Size;
        _screenRatio = _size.X / _size.Y;
        GetViewport().SizeChanged += SizeChanged;
        Input.MouseMode = Input.MouseModeEnum.Confined;
    }

    public override void _ExitTree()
    {
        GetViewport().SizeChanged -= SizeChanged;
    }

    private void SizeChanged()
    {
        _size = GetViewport().GetVisibleRect().Size;
        _screenRatio = _size.X / _size.Y;
    }

    public override void _Process(double delta)
    {
        if (_isDragging)
        {
            GlobalPosition -=
                    GlobalTransform.Basis.X * _mouseRelativeVel.X * _middleMouseGrabCameraSpeed * (float)delta +
                    GlobalTransform.Basis.Z * _mouseRelativeVel.Y * _middleMouseGrabCameraSpeed * (float)delta * _screenRatio;
        }
        else
        {
            ApplyPanningStateToCamera(delta);
        }
        if (_applyZoomSmooth)
        {
            ApplyZoom(delta);
        }
        if (_rotateCamera)
        {
            RotateY(-_mouseRelativeVel.X * 0.5f * (float)delta);
        }
        //relative mouse velocity need to be reset after every frame
        _mouseRelativeVel = Vector2.Zero;
    }

    private void ApplyZoom(double delta)
    {
        _smoothTimer += (float)delta;
        if (_smoothTimer &lt; _smoothZoomTime)
        {
            _camera.Size = Mathf.Lerp(_camera.Size, _currentSize, _smoothTimer / _smoothZoomTime);
        }
        else
        {
            _applyZoomSmooth = false;
        }
    }

    private void ApplyPanningStateToCamera(double delta)
    {
        switch (pannigState)
        {
            case EdgePannigState.None:
                break;
            case EdgePannigState.Left:
                GlobalPosition +=
                  GlobalTransform.Basis.X * -_panningCameraSpeed * (float)delta;
                break;
            case EdgePannigState.Right:
                GlobalPosition +=
                 GlobalTransform.Basis.X * _panningCameraSpeed * (float)delta;
                break;
            case EdgePannigState.Up:
                GlobalPosition +=
                  GlobalTransform.Basis.Z * -_panningCameraSpeed * (float)delta;
                break;
            case EdgePannigState.Down:
                GlobalPosition +=
                 GlobalTransform.Basis.Z * _panningCameraSpeed * (float)delta;
                break;
        }
    }
    public override void _Input(InputEvent @event)
    {
        if (@event is InputEventKey keyEvent)
        {
            if (keyEvent.Keycode == Key.Escape &amp;&amp; keyEvent.Pressed)
            {
                Input.MouseMode = Input.MouseMode == Input.MouseModeEnum.Confined ? Input.MouseModeEnum.Visible : Input.MouseModeEnum.Confined;
            }
        }
        if (@event is InputEventMouseButton mouseButton)
        {
            switch (mouseButton.ButtonIndex)
            {
                case MouseButton.WheelDown:
                case MouseButton.WheelUp:
                    {
                        if (!_isDragging)
                        {
                            _currentSize = mouseButton.ButtonIndex == MouseButton.WheelUp ? _currentSize - _zoomAmountPerRoll : _currentSize + _zoomAmountPerRoll;
                            _currentSize = Mathf.Clamp(_currentSize, _zoomMinDisatance, _zoomMaxDisatance);
                            _smoothTimer = 0;
                            _applyZoomSmooth = true;
                        }
                    }
                    break;
                case MouseButton.Middle when mouseButton.Pressed:
                    _isDragging = true;
                    break;
                case MouseButton.Right when mouseButton.Pressed:
                    _rotateCamera = true;
                    break;
                default:
                    _rotateCamera = false;
                    _isDragging = false;
                    break;
            }
        }
        if (@event is InputEventMouseMotion mouseMotion)
        {
            _mouseRelativeVel = mouseMotion.Relative;
            EdgePanningDetection(mouseMotion.Position);
        }
    }

    private void EdgePanningDetection(Vector2 mouseMotion)
    {
        if (mouseMotion.X &lt; _edgePanningTriggerOffsetValue)
        {
            pannigState = EdgePannigState.Left;
        }
        else if (mouseMotion.X &gt; (_size.X - _edgePanningTriggerOffsetValue))
        {
            pannigState = EdgePannigState.Right;
        }
        else if (mouseMotion.Y &lt; _edgePanningTriggerOffsetValue)
        {
            pannigState = EdgePannigState.Up;
        }
        else if (mouseMotion.Y &gt; (_size.Y - _edgePanningTriggerOffsetValue))
        {
            pannigState = EdgePannigState.Down;
        }
        else
        {
            pannigState = EdgePannigState.None;
        }
    }
}
public enum EdgePannigState
{
    None,
    Left,
    Right,
    Up,
    Down
}" style="color:#24292e;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki github-light" style="background-color: #fff" tabindex="0"><code><span class="line"></span>
<span class="line"><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">partial</span><span style="color: #24292E"> </span><span style="color: #D73A49">class</span><span style="color: #24292E"> </span><span style="color: #6F42C1">CameraController</span><span style="color: #24292E"> : </span><span style="color: #6F42C1">Node3D</span></span>
<span class="line"><span style="color: #24292E">{</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_edgePanningTriggerOffsetValue</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">2f</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_panningCameraSpeed</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">50f</span><span style="color: #24292E">; </span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_middleMouseGrabCameraSpeed</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">5f</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_zoomMinDisatance</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">20</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_zoomMaxDisatance</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">60</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_zoomAmountPerRoll</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">10</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_currentSize</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0f</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_smoothTimer</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0.0f</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_smoothZoomTime</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">1.0f</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">float</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_screenRatio</span><span style="color: #24292E">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_size</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_mouseRelativeVel</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Vector2.Zero;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_applyZoomSmooth</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_rotateCamera</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_isDragging</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    [</span><span style="color: #6F42C1">Export</span><span style="color: #24292E">] </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Camera3D</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_camera</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pannigState</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.None;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">override</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_Ready</span><span style="color: #24292E">()</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        _currentSize </span><span style="color: #D73A49">=</span><span style="color: #24292E"> _camera.Size;</span></span>
<span class="line"><span style="color: #24292E">        _size </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetViewport</span><span style="color: #24292E">().</span><span style="color: #6F42C1">GetVisibleRect</span><span style="color: #24292E">().Size;</span></span>
<span class="line"><span style="color: #24292E">        _screenRatio </span><span style="color: #D73A49">=</span><span style="color: #24292E"> _size.X </span><span style="color: #D73A49">/</span><span style="color: #24292E"> _size.Y;</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #6F42C1">GetViewport</span><span style="color: #24292E">().SizeChanged </span><span style="color: #D73A49">+=</span><span style="color: #24292E"> SizeChanged;</span></span>
<span class="line"><span style="color: #24292E">        Input.MouseMode </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Input.MouseModeEnum.Confined;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">override</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_ExitTree</span><span style="color: #24292E">()</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #6F42C1">GetViewport</span><span style="color: #24292E">().SizeChanged </span><span style="color: #D73A49">-=</span><span style="color: #24292E"> SizeChanged;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">SizeChanged</span><span style="color: #24292E">()</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        _size </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetViewport</span><span style="color: #24292E">().</span><span style="color: #6F42C1">GetVisibleRect</span><span style="color: #24292E">().Size;</span></span>
<span class="line"><span style="color: #24292E">        _screenRatio </span><span style="color: #D73A49">=</span><span style="color: #24292E"> _size.X </span><span style="color: #D73A49">/</span><span style="color: #24292E"> _size.Y;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">override</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_Process</span><span style="color: #24292E">(</span><span style="color: #D73A49">double</span><span style="color: #24292E"> </span><span style="color: #6F42C1">delta</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (_isDragging)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            GlobalPosition </span><span style="color: #D73A49">-=</span></span>
<span class="line"><span style="color: #24292E">                    GlobalTransform.Basis.X </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _mouseRelativeVel.X </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _middleMouseGrabCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta </span><span style="color: #D73A49">+</span></span>
<span class="line"><span style="color: #24292E">                    GlobalTransform.Basis.Z </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _mouseRelativeVel.Y </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _middleMouseGrabCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _screenRatio;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #6F42C1">ApplyPanningStateToCamera</span><span style="color: #24292E">(delta);</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (_applyZoomSmooth)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #6F42C1">ApplyZoom</span><span style="color: #24292E">(delta);</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (_rotateCamera)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #6F42C1">RotateY</span><span style="color: #24292E">(</span><span style="color: #D73A49">-</span><span style="color: #24292E">_mouseRelativeVel.X </span><span style="color: #D73A49">*</span><span style="color: #24292E"> </span><span style="color: #005CC5">0.5f</span><span style="color: #24292E"> </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta);</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #6A737D">        //relative mouse velocity need to be reset after every frame</span></span>
<span class="line"><span style="color: #24292E">        _mouseRelativeVel </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Vector2.Zero;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">ApplyZoom</span><span style="color: #24292E">(</span><span style="color: #D73A49">double</span><span style="color: #24292E"> </span><span style="color: #6F42C1">delta</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        _smoothTimer </span><span style="color: #D73A49">+=</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta;</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (_smoothTimer </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> _smoothZoomTime)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            _camera.Size </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Mathf.</span><span style="color: #6F42C1">Lerp</span><span style="color: #24292E">(_camera.Size, _currentSize, _smoothTimer </span><span style="color: #D73A49">/</span><span style="color: #24292E"> _smoothZoomTime);</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            _applyZoomSmooth </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">ApplyPanningStateToCamera</span><span style="color: #24292E">(</span><span style="color: #D73A49">double</span><span style="color: #24292E"> </span><span style="color: #6F42C1">delta</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">switch</span><span style="color: #24292E"> (pannigState)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E">.</span><span style="color: #6F42C1">None</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Left</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                GlobalPosition </span><span style="color: #D73A49">+=</span></span>
<span class="line"><span style="color: #24292E">                  GlobalTransform.Basis.X </span><span style="color: #D73A49">*</span><span style="color: #24292E"> </span><span style="color: #D73A49">-</span><span style="color: #24292E">_panningCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Right</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                GlobalPosition </span><span style="color: #D73A49">+=</span></span>
<span class="line"><span style="color: #24292E">                 GlobalTransform.Basis.X </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _panningCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Up</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                GlobalPosition </span><span style="color: #D73A49">+=</span></span>
<span class="line"><span style="color: #24292E">                  GlobalTransform.Basis.Z </span><span style="color: #D73A49">*</span><span style="color: #24292E"> </span><span style="color: #D73A49">-</span><span style="color: #24292E">_panningCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Down</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                GlobalPosition </span><span style="color: #D73A49">+=</span></span>
<span class="line"><span style="color: #24292E">                 GlobalTransform.Basis.Z </span><span style="color: #D73A49">*</span><span style="color: #24292E"> _panningCameraSpeed </span><span style="color: #D73A49">*</span><span style="color: #24292E"> (</span><span style="color: #D73A49">float</span><span style="color: #24292E">)delta;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">override</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">_Input</span><span style="color: #24292E">(</span><span style="color: #6F42C1">InputEvent</span><span style="color: #24292E"> </span><span style="color: #6F42C1">@event</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (@event </span><span style="color: #D73A49">is</span><span style="color: #24292E"> </span><span style="color: #6F42C1">InputEventKey</span><span style="color: #24292E"> </span><span style="color: #6F42C1">keyEvent</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (keyEvent.Keycode </span><span style="color: #D73A49">==</span><span style="color: #24292E"> Key.Escape </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> keyEvent.Pressed)</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"><span style="color: #24292E">                Input.MouseMode </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Input.MouseMode </span><span style="color: #D73A49">==</span><span style="color: #24292E"> Input.MouseModeEnum.Confined </span><span style="color: #D73A49">?</span><span style="color: #24292E"> Input.MouseModeEnum.Visible </span><span style="color: #D73A49">:</span><span style="color: #24292E"> Input.MouseModeEnum.Confined;</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (@event </span><span style="color: #D73A49">is</span><span style="color: #24292E"> </span><span style="color: #6F42C1">InputEventMouseButton</span><span style="color: #24292E"> </span><span style="color: #6F42C1">mouseButton</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">switch</span><span style="color: #24292E"> (mouseButton.ButtonIndex)</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">MouseButton</span><span style="color: #24292E">.</span><span style="color: #6F42C1">WheelDown</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">MouseButton</span><span style="color: #24292E">.</span><span style="color: #6F42C1">WheelUp</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                    {</span></span>
<span class="line"><span style="color: #24292E">                        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #D73A49">!</span><span style="color: #24292E">_isDragging)</span></span>
<span class="line"><span style="color: #24292E">                        {</span></span>
<span class="line"><span style="color: #24292E">                            _currentSize </span><span style="color: #D73A49">=</span><span style="color: #24292E"> mouseButton.ButtonIndex </span><span style="color: #D73A49">==</span><span style="color: #24292E"> MouseButton.WheelUp </span><span style="color: #D73A49">?</span><span style="color: #24292E"> _currentSize </span><span style="color: #D73A49">-</span><span style="color: #24292E"> _zoomAmountPerRoll </span><span style="color: #D73A49">:</span><span style="color: #24292E"> _currentSize </span><span style="color: #D73A49">+</span><span style="color: #24292E"> _zoomAmountPerRoll;</span></span>
<span class="line"><span style="color: #24292E">                            _currentSize </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Mathf.</span><span style="color: #6F42C1">Clamp</span><span style="color: #24292E">(_currentSize, _zoomMinDisatance, _zoomMaxDisatance);</span></span>
<span class="line"><span style="color: #24292E">                            _smoothTimer </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                            _applyZoomSmooth </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                        }</span></span>
<span class="line"><span style="color: #24292E">                    }</span></span>
<span class="line"><span style="color: #24292E">                    </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">MouseButton</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Middle</span><span style="color: #24292E"> </span><span style="color: #D73A49">when</span><span style="color: #24292E"> mouseButton.Pressed:</span></span>
<span class="line"><span style="color: #24292E">                    _isDragging </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                    </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">case</span><span style="color: #24292E"> </span><span style="color: #6F42C1">MouseButton</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Right</span><span style="color: #24292E"> </span><span style="color: #D73A49">when</span><span style="color: #24292E"> mouseButton.Pressed:</span></span>
<span class="line"><span style="color: #24292E">                    _rotateCamera </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                    </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">default</span><span style="color: #24292E">:</span></span>
<span class="line"><span style="color: #24292E">                    _rotateCamera </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                    _isDragging </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                    </span><span style="color: #D73A49">break</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (@event </span><span style="color: #D73A49">is</span><span style="color: #24292E"> </span><span style="color: #6F42C1">InputEventMouseMotion</span><span style="color: #24292E"> </span><span style="color: #6F42C1">mouseMotion</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            _mouseRelativeVel </span><span style="color: #D73A49">=</span><span style="color: #24292E"> mouseMotion.Relative;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #6F42C1">EdgePanningDetection</span><span style="color: #24292E">(mouseMotion.Position);</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePanningDetection</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">mouseMotion</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (mouseMotion.X </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> _edgePanningTriggerOffsetValue)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            pannigState </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.Left;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span><span style="color: #24292E"> </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (mouseMotion.X </span><span style="color: #D73A49">&gt;</span><span style="color: #24292E"> (_size.X </span><span style="color: #D73A49">-</span><span style="color: #24292E"> _edgePanningTriggerOffsetValue))</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            pannigState </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.Right;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span><span style="color: #24292E"> </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (mouseMotion.Y </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> _edgePanningTriggerOffsetValue)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            pannigState </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.Up;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span><span style="color: #24292E"> </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (mouseMotion.Y </span><span style="color: #D73A49">&gt;</span><span style="color: #24292E"> (_size.Y </span><span style="color: #D73A49">-</span><span style="color: #24292E"> _edgePanningTriggerOffsetValue))</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            pannigState </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.Down;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">else</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            pannigState </span><span style="color: #D73A49">=</span><span style="color: #24292E"> EdgePannigState.None;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"><span style="color: #24292E">}</span></span>
<span class="line"><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">enum</span><span style="color: #24292E"> </span><span style="color: #6F42C1">EdgePannigState</span></span>
<span class="line"><span style="color: #24292E">{</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #6F42C1">None</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #6F42C1">Left</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #6F42C1">Right</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #6F42C1">Up</span><span style="color: #24292E">,</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #6F42C1">Down</span></span>
<span class="line"><span style="color: #24292E">}</span></span></code></pre></div>



<p>Lets breakdown the above code:</p>



<h5 class="wp-block-heading">Variables | Constants</h5>



<ul class="wp-block-list">
<li><strong>_edgePanningTriggerOffsetValue</strong>:
<ul class="wp-block-list">
<li>A constant defining the threshold distance from the edge of the screen to trigger edge panning, meaning that if it has a value of 5, edge panning would start 5 pixels before reaching the edge.</li>
</ul>
</li>



<li><strong>_panningCameraSpeed</strong>:
<ul class="wp-block-list">
<li>This is a speed at which the camera move when using edge panning.</li>
</ul>
</li>



<li><strong>_middleMouseGrabCameraSpeed</strong>:
<ul class="wp-block-list">
<li>This define a speed at which the camera move when the middle mouse or grab button is held down.</li>
</ul>
</li>



<li><strong>_zoomMinDistance, _zoomMaxDistance:</strong>
<ul class="wp-block-list">
<li>These are the constants defining the minimum and maximum zoom distances for camera.</li>
</ul>
</li>



<li><strong>_zoomAmountPerRoll:</strong>
<ul class="wp-block-list">
<li>This is a amount by which the zoom changes per mouse wheel roll.</li>
</ul>
</li>



<li><strong>_currentCameraSize:</strong>
<ul class="wp-block-list">
<li>This give the current camera size used for zooming in/out.</li>
</ul>
</li>



<li><strong>_smoothTimer, _smoothZoomTime:</strong>
<ul class="wp-block-list">
<li>These are used for smooth zoom interpolation.</li>
</ul>
</li>



<li><strong>_screenRatio, _viewPortSize:</strong>
<ul class="wp-block-list">
<li>These are used to store the screen ratio and size of the viewport.</li>
</ul>
</li>



<li><strong>_mouseRelativeVel:</strong>
<ul class="wp-block-list">
<li>This give the relative mouse velocity whenever mouse is moved.</li>
</ul>
</li>



<li><strong>_applyZoomSmooth, _rotateCamera, _isDragging:</strong>
<ul class="wp-block-list">
<li>These flags are used to control zooming, camera rotation, and dragging behavior.</li>
</ul>
</li>



<li><strong>_camera:</strong>
<ul class="wp-block-list">
<li>Reference to the Camera3D node.</li>
</ul>
</li>



<li><strong>panningState:</strong>
<ul class="wp-block-list">
<li>The current panning state (e.g., Left, Right, Up, Down, None) represented by Enum.</li>
</ul>
</li>
</ul>



<h5 class="wp-block-heading">Methods</h5>



<ul class="wp-block-list">
<li><strong>_Ready():</strong>
<ul class="wp-block-list">
<li>In this method we Initializes variables related to camera size, viewport size, and aspect ratio and subscribes to the viewport size changed event.</li>
</ul>
</li>



<li><strong>_ExitTree():</strong>
<ul class="wp-block-list">
<li>This is called when the node is removed from the scene tree. we usually unsubscribes to all event here to avoid memory leaks.</li>
</ul>
</li>



<li><strong>SizeChanged():</strong>
<ul class="wp-block-list">
<li>This is called when the viewport size changes and will updates the size and aspect ratio variables accordingly.</li>
</ul>
</li>



<li><strong>_Process(double delta):</strong>
<ul class="wp-block-list">
<li>Here we handles camera movement, zooming, and rotation based on user input and current panning states.</li>
</ul>
</li>



<li><strong>ApplyZoom(double delta):</strong>
<ul class="wp-block-list">
<li>This is used to apply smooth zooming by interpolating the camera size over time.</li>
</ul>
</li>



<li><strong>EdgePanningDetection(Vector2 mouseMotion):</strong>
<ul class="wp-block-list">
<li>This method detects if the mouse cursor is near the edges of the screen and sets the corresponding panning state (Left, Right, Up, Down, or None) based on the cursor position.</li>
</ul>
</li>



<li><strong>ApplyPanningStateToCamera(double delta):</strong>
<ul class="wp-block-list">
<li>This method applies the current panning state to the camera, moving it in the corresponding direction based on the panning camera speed.</li>
</ul>
</li>



<li><strong>_Input(InputEvent @event):</strong>
<ul class="wp-block-list">
<li>Here we handles various input events such as key presses, mouse button presses, and mouse motion. Controls camera zoom, rotation, and dragging behavior.</li>
</ul>
</li>
</ul>



<h4 class="wp-block-heading">Conclusion</h4>



<p>In this post, we&#8217;ve created an Isometric Camera Controller in Godot Engine using C#. You can easily integrate this controller into your project to enable smooth camera movements for your RTS game or any other 3D project.</p>



<p>Feel free to customize the script further to suit your specific requirements and enhance your game&#8217;s camera control functionality. Here is the <a href="https://github.com/nepalisameer/godot-tutorial/tree/master/src/3D_Isometric_Camera_Control">Github link </a>for this project.</p>
<p>The post <a href="https://tweakgame.com/isometric-camera-controller-3d-godot-engine/">Isometric Camera Controller 3D &#8211; Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tweakgame.com/isometric-camera-controller-3d-godot-engine/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>How to Setup Visual Studio with Godot Engine</title>
		<link>https://tweakgame.com/how-to-setup-visual-studio-with-godot-engine/</link>
					<comments>https://tweakgame.com/how-to-setup-visual-studio-with-godot-engine/#respond</comments>
		
		<dc:creator><![CDATA[Samee]]></dc:creator>
		<pubDate>Wed, 24 Apr 2024 07:16:39 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[game engine]]></category>
		<category><![CDATA[godot]]></category>
		<category><![CDATA[Visual Studio]]></category>
		<guid isPermaLink="false">https://tweakgame.com/?p=3048</guid>

					<description><![CDATA[<p>Hello everyone, In this post, we&#8217;ll walk through setting up the Godot Engine with Visual Studio so we can launch&#8230;</p>
<p>The post <a href="https://tweakgame.com/how-to-setup-visual-studio-with-godot-engine/">How to Setup Visual Studio with Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hello everyone, In this post, we&#8217;ll walk through setting up the Godot Engine with Visual Studio so we can launch and debug our game directly from within Visual Studio. For this we need the latest versions of both<a href="https://visualstudio.microsoft.com/downloads/"> Visual Studio</a> and the <a href="https://godotengine.org/">Godot game engine</a> (.NET runtime). Once you&#8217;ve downloaded and installed both of them, we can proceed to set up Godot Engine with Visual Studio.</p>



<p>First, open Godot Engine and create a new project. Then, navigate to Editor -> Editor Settings. Find Dotnet -> Editor tab and select it. Make sure &#8220;External Editor&#8221; is set to Visual Studio and that the &#8220;Custom Exec Path&#8221; is pointing to your installed Visual Studio executable path.</p>



<figure class="wp-block-image size-full is-resized"><img loading="lazy" decoding="async" width="892" height="231" src="https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-115041.png?x24571" alt="" class="wp-image-3051" style="width:780px;height:auto" srcset="https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-115041.png 892w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-115041-300x78.png 300w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-115041-768x199.png 768w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-115041-585x151.png 585w" sizes="(max-width: 892px) 100vw, 892px" /></figure>



<p>Once you&#8217;ve completed the previous step, open your project in Visual Studio. Then, navigate to Debug -&gt; [Your Project Name] Debug Properties and open it. Also, you can delete the default launch profile if it exists.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="633" src="https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties-1024x633.png?x24571" alt="" class="wp-image-3052" srcset="https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties-1024x633.png 1024w, https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties-300x185.png 300w, https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties-768x474.png 768w, https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties-585x361.png 585w, https://tweakgame.com/wp-content/uploads/2024/04/vs_debug_properties.png 1151w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Next, select create a new profile option and choose the &#8220;Executable&#8221; option. You can also rename your profile to whatever you like.</p>



<figure class="wp-block-image size-full"><img loading="lazy" decoding="async" width="800" height="200" src="https://tweakgame.com/wp-content/uploads/2024/04/vs_llaunch_profile_executable.png?x24571" alt="" class="wp-image-3054" srcset="https://tweakgame.com/wp-content/uploads/2024/04/vs_llaunch_profile_executable.png 800w, https://tweakgame.com/wp-content/uploads/2024/04/vs_llaunch_profile_executable-300x75.png 300w, https://tweakgame.com/wp-content/uploads/2024/04/vs_llaunch_profile_executable-768x192.png 768w, https://tweakgame.com/wp-content/uploads/2024/04/vs_llaunch_profile_executable-585x146.png 585w" sizes="(max-width: 800px) 100vw, 800px" /></figure>



<p>First, make sure that the path to the executable to run is pointing to your Godot Engine executable file (Godot_v4.2-stable_mono_win64.exe).<br> For Command Line Arguments, you can pass any <a href="https://docs.godotengine.org/en/stable/tutorials/editor/command_line_tutorial.html">supported argument.</a> <br>Use &#8216;.&#8217; for the Working Directory to indicate that this is the current working directory. <br>Also, make sure to enable the &#8220;Native Code Debugging&#8221; option.</p>



<figure class="wp-block-image size-large"><img loading="lazy" decoding="async" width="1024" height="805" src="https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-1024x805.png?x24571" alt="" class="wp-image-3055" srcset="https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-1024x805.png 1024w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-300x236.png 300w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-768x604.png 768w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-1170x920.png 1170w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318-585x460.png 585w, https://tweakgame.com/wp-content/uploads/2024/04/Screenshot-2024-04-24-121318.png 1232w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>Once you have completed all these steps, you will be able to run and debug your game from within Visual Studio. If you encounter an error, you most likely have forgotten to set the startup Main Scene in Godot Engine.</p>
<p>The post <a href="https://tweakgame.com/how-to-setup-visual-studio-with-godot-engine/">How to Setup Visual Studio with Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tweakgame.com/how-to-setup-visual-studio-with-godot-engine/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Godot Engine &#8211; Build Custom Grid System using C#</title>
		<link>https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/</link>
					<comments>https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/#comments</comments>
		
		<dc:creator><![CDATA[Samee]]></dc:creator>
		<pubDate>Tue, 23 Apr 2024 08:04:47 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[game engine]]></category>
		<category><![CDATA[godot]]></category>
		<category><![CDATA[grid]]></category>
		<category><![CDATA[grid system]]></category>
		<guid isPermaLink="false">https://tweakgame.com/?p=3031</guid>

					<description><![CDATA[<p>Hello everyone, this post demonstrates how to build a custom grid system that can be utilized for various purposes such&#8230;</p>
<p>The post <a href="https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/">Godot Engine &#8211; Build Custom Grid System using C#</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hello everyone, this post demonstrates how to build a custom grid system that can be utilized for various purposes such as pathfinding, heatmaps, grid-based building systems, grid-based combat systems, and much more. This grid system leverages the generic features of the C# language. It enables you to store and manage data in a two-dimensional arrangement of cells. Being generic means you can use it to store any type of data, from integers and strings to complex objects and custom classes in each cell.</p>



<p>This code creates a grid, and I believe it&#8217;s largely self-explanatory. However, if you encounter any confusion, feel free to ask in the comments.</p>



<div class="wp-block-kevinbatdorf-code-block-pro padding-disabled" data-code-block-pro-font-family="Code-Pro-JetBrains-Mono" style="font-size:.75rem;font-family:Code-Pro-JetBrains-Mono,ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,monospace;line-height:1rem;--cbp-tab-width:2;tab-size:var(--cbp-tab-width, 2)"><span style="display:flex;align-items:center;padding:16px 0 0 16px;width:100%;text-align:left;background-color:#ffffff"><span style="background:#2f363c;padding:0.3rem 0.5rem 0.2rem;border-radius:1rem;font-size:0.8em;line-height:1;height:1.25rem;text-align:center;display:inline-flex;align-items:center;justify-content:center;color:#ffffff">C#</span></span><span role="button" tabindex="0" data-code="public class CustomGrid&lt;TItem&gt;
{
    public delegate void GridItemChangedDelegate(int coordinateX, int coordinateY, TItem obj);

    public event GridItemChangedDelegate GridItemChanged;

    public int Height { get; private set; }
    public int CellSize { get; private set; }
    public int Width { get; private set; }

    public TItem[,] GridCellCollection { get; private set; }

    public List&lt;Vector2&gt; GridPositions { get; private set; }

    private readonly Func&lt;Vector2&gt; _originPosition;
    public CustomGrid(int width, int height, int cellSize, Func&lt;Vector2&gt; originPosition = null)
    {
        _originPosition = originPosition;
        Height = height;
        CellSize = cellSize;
        Width = width;
        GridCellCollection = new TItem[width, height];
        GridPositions = new();
        // Initialize grid cells and positions
        for (int i = 0; i &lt; Width; i++)
        {
            for (int j = 0; j &lt; Height; j++)
            {

                GridCellCollection[i, j] = default;
                GridPositions.Add(GetWorldPosition(i, j));
            }
        }
    }
    private void CreateGrid()
    {
        for (int i = 0; i &lt; Width; i++)
        {
            for (int j = 0; j &lt; Height; j++)
            {
                //each cell data
            }
        }
    }


    private Vector2 GetParentPosition() =&gt; _originPosition?.Invoke() ?? Vector2.Zero;

    private bool TryGetGridCoordinate(Vector2 pos, Vector2 parentPos, out (int x, int y) coordinate)
    {
        var x = Mathf.FloorToInt((pos.X - parentPos.X) / (CellSize));
        var y = Mathf.FloorToInt((pos.Y - parentPos.Y) / (CellSize));
        coordinate = (x, y);
        return x &gt;= 0 &amp;&amp; x &lt; Width &amp;&amp; y &gt;= 0 &amp;&amp; y &lt; Height;
    }

    private bool IsCellEmpty(int x, int y)
    {
        var obj = GridCellCollection[x, y];
        return obj == null || EqualityComparer&lt;TItem&gt;.Default.Equals(obj, default);
    }

    private bool IsCellEmpty(int x, int y, out TItem item)
    {
        item = GridCellCollection[x, y];
        return GridCellCollection[x, y] == null || EqualityComparer&lt;TItem&gt;.Default.Equals(GridCellCollection[x, y], default);
    }

    public bool IsCellEmpty(Vector2 pos)
    {
        return TryGetGridCoordinate(pos, GetParentPosition(), out var coordinate) &amp;&amp; IsCellEmpty(coordinate.x, coordinate.y);
    }

    private Vector2 GetWorldPosition(int x, int y) =&gt; new Vector2(x * CellSize, y * CellSize) + GetParentPosition();

    public bool TrySetItem(Vector2 pos, TItem obj, out Vector2 positionToSet)
    {
        if (obj == null)
        {
            positionToSet = Vector2.Zero;
            return false;
        }
        var parentPos = GetParentPosition();
        if (TryGetGridCoordinate(pos, parentPos, out var coordinate) &amp;&amp; IsCellEmpty(coordinate.x, coordinate.y))
        {
            GridCellCollection[coordinate.x, coordinate.y] = obj;
            positionToSet = new Vector2(coordinate.x * CellSize, coordinate.y * CellSize) + parentPos;
            GridItemChanged?.Invoke(coordinate.x, coordinate.y, obj);
            return true;
        }
        positionToSet = Vector2.Zero;
        return false;
    }
    public void TriggerItemChangedEvent(int x, int y)
    {
        GridItemChanged?.Invoke(x, y, GridCellCollection[x, y]);
    }

    public bool TryGetItem(Vector2 pos, out TItem obj)
    {
        if (TryGetGridCoordinate(pos, GetParentPosition(), out var coordinate))
        {
            if (!IsCellEmpty(coordinate.x, coordinate.y))
            {
                obj = GridCellCollection[coordinate.x, coordinate.y];
                return true;
            }
        }
        obj = default;
        return false;
    }

    public bool TryRemoveItem(Vector2 pos, out TItem removedItem)
    {
        if (TryGetGridCoordinate(pos, GetParentPosition(), out var coordinate))
        {
            if (IsCellEmpty(coordinate.x, coordinate.y, out removedItem))
            {
                return false;
            }
            GridCellCollection[coordinate.x, coordinate.y] = default;
            return true;
        }
        removedItem = default;
        return false;
    }
}" style="color:#24292e;display:none" aria-label="Copy" class="code-block-pro-copy-button"><svg xmlns="http://www.w3.org/2000/svg" style="width:24px;height:24px" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2"><path class="with-check" stroke-linecap="round" stroke-linejoin="round" d="M4.5 12.75l6 6 9-13.5"></path><path class="without-check" stroke-linecap="round" stroke-linejoin="round" d="M16.5 8.25V6a2.25 2.25 0 00-2.25-2.25H6A2.25 2.25 0 003.75 6v8.25A2.25 2.25 0 006 16.5h2.25m8.25-8.25H18a2.25 2.25 0 012.25 2.25V18A2.25 2.25 0 0118 20.25h-7.5A2.25 2.25 0 018.25 18v-1.5m8.25-8.25h-6a2.25 2.25 0 00-2.25 2.25v6"></path></svg></span><pre class="shiki github-light" style="background-color: #fff" tabindex="0"><code><span class="line"><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">class</span><span style="color: #24292E"> </span><span style="color: #6F42C1">CustomGrid</span><span style="color: #24292E">&lt;</span><span style="color: #6F42C1">TItem</span><span style="color: #24292E">&gt;</span></span>
<span class="line"><span style="color: #24292E">{</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">delegate</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GridItemChangedDelegate</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinateX</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinateY</span><span style="color: #24292E">, </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E"> </span><span style="color: #6F42C1">obj</span><span style="color: #24292E">);</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">event</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GridItemChangedDelegate</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GridItemChanged</span><span style="color: #24292E">;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Height</span><span style="color: #24292E"> { </span><span style="color: #D73A49">get</span><span style="color: #24292E">; </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">set</span><span style="color: #24292E">; }</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">CellSize</span><span style="color: #24292E"> { </span><span style="color: #D73A49">get</span><span style="color: #24292E">; </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">set</span><span style="color: #24292E">; }</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Width</span><span style="color: #24292E"> { </span><span style="color: #D73A49">get</span><span style="color: #24292E">; </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">set</span><span style="color: #24292E">; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E">[,] </span><span style="color: #6F42C1">GridCellCollection</span><span style="color: #24292E"> { </span><span style="color: #D73A49">get</span><span style="color: #24292E">; </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">set</span><span style="color: #24292E">; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #6F42C1">List</span><span style="color: #24292E">&lt;</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E">&gt; </span><span style="color: #6F42C1">GridPositions</span><span style="color: #24292E"> { </span><span style="color: #D73A49">get</span><span style="color: #24292E">; </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">set</span><span style="color: #24292E">; }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">readonly</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Func</span><span style="color: #24292E">&lt;</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E">&gt; </span><span style="color: #6F42C1">_originPosition</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #6F42C1">CustomGrid</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">width</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">height</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">cellSize</span><span style="color: #24292E">, </span><span style="color: #6F42C1">Func</span><span style="color: #24292E">&lt;</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E">&gt; </span><span style="color: #6F42C1">originPosition</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">null</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        _originPosition </span><span style="color: #D73A49">=</span><span style="color: #24292E"> originPosition;</span></span>
<span class="line"><span style="color: #24292E">        Height </span><span style="color: #D73A49">=</span><span style="color: #24292E"> height;</span></span>
<span class="line"><span style="color: #24292E">        CellSize </span><span style="color: #D73A49">=</span><span style="color: #24292E"> cellSize;</span></span>
<span class="line"><span style="color: #24292E">        Width </span><span style="color: #D73A49">=</span><span style="color: #24292E"> width;</span></span>
<span class="line"><span style="color: #24292E">        GridCellCollection </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">new</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E">[width, height];</span></span>
<span class="line"><span style="color: #24292E">        GridPositions </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">new</span><span style="color: #24292E">();</span></span>
<span class="line"><span style="color: #6A737D">        // Initialize grid cells and positions</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">for</span><span style="color: #24292E"> (</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">i</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E">; i </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Width; i</span><span style="color: #D73A49">++</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">for</span><span style="color: #24292E"> (</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">j</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E">; j </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Height; j</span><span style="color: #D73A49">++</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">                GridCellCollection[i, j] </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">default</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">                GridPositions.</span><span style="color: #6F42C1">Add</span><span style="color: #24292E">(</span><span style="color: #6F42C1">GetWorldPosition</span><span style="color: #24292E">(i, j));</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">CreateGrid</span><span style="color: #24292E">()</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">for</span><span style="color: #24292E"> (</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">i</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E">; i </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Width; i</span><span style="color: #D73A49">++</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">for</span><span style="color: #24292E"> (</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">j</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E">; j </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Height; j</span><span style="color: #D73A49">++</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"><span style="color: #6A737D">                //each cell data</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">() </span><span style="color: #D73A49">=&gt;</span><span style="color: #24292E"> _originPosition</span><span style="color: #D73A49">?</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Invoke</span><span style="color: #24292E">() </span><span style="color: #D73A49">??</span><span style="color: #24292E"> Vector2.Zero;</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TryGetGridCoordinate</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pos</span><span style="color: #24292E">, </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">parentPos</span><span style="color: #24292E">, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> (</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E">) </span><span style="color: #6F42C1">coordinate</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Mathf.</span><span style="color: #6F42C1">FloorToInt</span><span style="color: #24292E">((pos.X </span><span style="color: #D73A49">-</span><span style="color: #24292E"> parentPos.X) </span><span style="color: #D73A49">/</span><span style="color: #24292E"> (CellSize));</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Mathf.</span><span style="color: #6F42C1">FloorToInt</span><span style="color: #24292E">((pos.Y </span><span style="color: #D73A49">-</span><span style="color: #24292E"> parentPos.Y) </span><span style="color: #D73A49">/</span><span style="color: #24292E"> (CellSize));</span></span>
<span class="line"><span style="color: #24292E">        coordinate </span><span style="color: #D73A49">=</span><span style="color: #24292E"> (x, y);</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> x </span><span style="color: #D73A49">&gt;=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E"> </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> x </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Width </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> y </span><span style="color: #D73A49">&gt;=</span><span style="color: #24292E"> </span><span style="color: #005CC5">0</span><span style="color: #24292E"> </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> y </span><span style="color: #D73A49">&lt;</span><span style="color: #24292E"> Height;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">obj</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> GridCellCollection[x, y];</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> obj </span><span style="color: #D73A49">==</span><span style="color: #24292E"> </span><span style="color: #005CC5">null</span><span style="color: #24292E"> </span><span style="color: #D73A49">||</span><span style="color: #24292E"> EqualityComparer&lt;</span><span style="color: #6F42C1">TItem</span><span style="color: #24292E">&gt;.Default.</span><span style="color: #6F42C1">Equals</span><span style="color: #24292E">(obj, </span><span style="color: #D73A49">default</span><span style="color: #24292E">);</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E">, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E"> </span><span style="color: #6F42C1">item</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        item </span><span style="color: #D73A49">=</span><span style="color: #24292E"> GridCellCollection[x, y];</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> GridCellCollection[x, y] </span><span style="color: #D73A49">==</span><span style="color: #24292E"> </span><span style="color: #005CC5">null</span><span style="color: #24292E"> </span><span style="color: #D73A49">||</span><span style="color: #24292E"> EqualityComparer&lt;</span><span style="color: #6F42C1">TItem</span><span style="color: #24292E">&gt;.Default.</span><span style="color: #6F42C1">Equals</span><span style="color: #24292E">(GridCellCollection[x, y], </span><span style="color: #D73A49">default</span><span style="color: #24292E">);</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pos</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TryGetGridCoordinate</span><span style="color: #24292E">(pos, </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">(), </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinate</span><span style="color: #24292E">) </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> </span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(coordinate.x, coordinate.y);</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">private</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetWorldPosition</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E">) </span><span style="color: #D73A49">=&gt;</span><span style="color: #24292E"> </span><span style="color: #D73A49">new</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E">(x </span><span style="color: #D73A49">*</span><span style="color: #24292E"> CellSize, y </span><span style="color: #D73A49">*</span><span style="color: #24292E"> CellSize) </span><span style="color: #D73A49">+</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">();</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TrySetItem</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pos</span><span style="color: #24292E">, </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E"> </span><span style="color: #6F42C1">obj</span><span style="color: #24292E">, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">positionToSet</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (obj </span><span style="color: #D73A49">==</span><span style="color: #24292E"> </span><span style="color: #005CC5">null</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            positionToSet </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Vector2.Zero;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">parentPos</span><span style="color: #24292E"> </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">();</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #6F42C1">TryGetGridCoordinate</span><span style="color: #24292E">(pos, parentPos, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinate</span><span style="color: #24292E">) </span><span style="color: #D73A49">&amp;&amp;</span><span style="color: #24292E"> </span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(coordinate.x, coordinate.y))</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            GridCellCollection[coordinate.x, coordinate.y] </span><span style="color: #D73A49">=</span><span style="color: #24292E"> obj;</span></span>
<span class="line"><span style="color: #24292E">            positionToSet </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">new</span><span style="color: #24292E"> </span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E">(coordinate.x </span><span style="color: #D73A49">*</span><span style="color: #24292E"> CellSize, coordinate.y </span><span style="color: #D73A49">*</span><span style="color: #24292E"> CellSize) </span><span style="color: #D73A49">+</span><span style="color: #24292E"> parentPos;</span></span>
<span class="line"><span style="color: #24292E">            GridItemChanged</span><span style="color: #D73A49">?</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Invoke</span><span style="color: #24292E">(coordinate.x, coordinate.y, obj);</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        positionToSet </span><span style="color: #D73A49">=</span><span style="color: #24292E"> Vector2.Zero;</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">void</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TriggerItemChangedEvent</span><span style="color: #24292E">(</span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">x</span><span style="color: #24292E">, </span><span style="color: #D73A49">int</span><span style="color: #24292E"> </span><span style="color: #6F42C1">y</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        GridItemChanged</span><span style="color: #D73A49">?</span><span style="color: #24292E">.</span><span style="color: #6F42C1">Invoke</span><span style="color: #24292E">(x, y, GridCellCollection[x, y]);</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TryGetItem</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pos</span><span style="color: #24292E">, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E"> </span><span style="color: #6F42C1">obj</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #6F42C1">TryGetGridCoordinate</span><span style="color: #24292E">(pos, </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">(), </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinate</span><span style="color: #24292E">))</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #D73A49">!</span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(coordinate.x, coordinate.y))</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"><span style="color: #24292E">                obj </span><span style="color: #D73A49">=</span><span style="color: #24292E"> GridCellCollection[coordinate.x, coordinate.y];</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        obj </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">default</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"></span>
<span class="line"><span style="color: #24292E">    </span><span style="color: #D73A49">public</span><span style="color: #24292E"> </span><span style="color: #D73A49">bool</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TryRemoveItem</span><span style="color: #24292E">(</span><span style="color: #6F42C1">Vector2</span><span style="color: #24292E"> </span><span style="color: #6F42C1">pos</span><span style="color: #24292E">, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #6F42C1">TItem</span><span style="color: #24292E"> </span><span style="color: #6F42C1">removedItem</span><span style="color: #24292E">)</span></span>
<span class="line"><span style="color: #24292E">    {</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #6F42C1">TryGetGridCoordinate</span><span style="color: #24292E">(pos, </span><span style="color: #6F42C1">GetParentPosition</span><span style="color: #24292E">(), </span><span style="color: #D73A49">out</span><span style="color: #24292E"> </span><span style="color: #D73A49">var</span><span style="color: #24292E"> </span><span style="color: #6F42C1">coordinate</span><span style="color: #24292E">))</span></span>
<span class="line"><span style="color: #24292E">        {</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">if</span><span style="color: #24292E"> (</span><span style="color: #6F42C1">IsCellEmpty</span><span style="color: #24292E">(coordinate.x, coordinate.y, </span><span style="color: #D73A49">out</span><span style="color: #24292E"> removedItem))</span></span>
<span class="line"><span style="color: #24292E">            {</span></span>
<span class="line"><span style="color: #24292E">                </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            }</span></span>
<span class="line"><span style="color: #24292E">            GridCellCollection[coordinate.x, coordinate.y] </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">default</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">            </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">true</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        }</span></span>
<span class="line"><span style="color: #24292E">        removedItem </span><span style="color: #D73A49">=</span><span style="color: #24292E"> </span><span style="color: #D73A49">default</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">        </span><span style="color: #D73A49">return</span><span style="color: #24292E"> </span><span style="color: #005CC5">false</span><span style="color: #24292E">;</span></span>
<span class="line"><span style="color: #24292E">    }</span></span>
<span class="line"><span style="color: #24292E">}</span></span></code></pre></div>



<p>But how does it all work? Let&#8217;s break down above code:</p>



<h5 class="wp-block-heading">Variables</h5>



<ul class="wp-block-list">
<li><strong>GridItemChanged (event):</strong>
<ul class="wp-block-list">
<li>This event is triggered when a grid item changes. It&#8217;s of type GridItemChangedDelegate, which defines the signature of methods that can be subscribed to this event.</li>
</ul>
</li>



<li><strong>Height, Width, CellSize:</strong>
<ul class="wp-block-list">
<li>These are properties that define the dimensions and cell size of the grid.</li>
</ul>
</li>



<li><strong>GridCellCollection:</strong>
<ul class="wp-block-list">
<li>It&#8217;s a 2D array of type TItem that holds grid items. Each cell in the grid can contain an item of type TItem. Since, TItem is generic, it can hold any type of data.</li>
</ul>
</li>



<li><strong>GridPositions:</strong>
<ul class="wp-block-list">
<li>It&#8217;s a list that stores grid positions as Vector2 and can be used to draw visual representation of grid.</li>
</ul>
</li>



<li><strong>_originPosition:</strong>
<ul class="wp-block-list">
<li>It&#8217;s a private field that holds a reference to a function returning a Vector2, representing the origin position of the grid.</li>
</ul>
</li>
</ul>



<h5 class="wp-block-heading">Methods</h5>



<ul class="wp-block-list">
<li><strong>CustomGrid() constructor:</strong>
<ul class="wp-block-list">
<li>This is use to Initializes a new instance of the CustomGrid class with specified width, height, cell size, and optionally, an origin position function.</li>
</ul>
</li>



<li><strong>GetParentPosition():</strong>
<ul class="wp-block-list">
<li>This method Returns the parent position of the grid. If _originPosition is not null, it invokes the function and returns the result; otherwise, it returns Vector2.Zero.</li>
</ul>
</li>



<li><strong>TryGetGridCoordinate(Vector2 pos, Vector2 parentPos, out (int x, int y) coordinate):</strong>
<ul class="wp-block-list">
<li>Given a world position and parent position, this method calculates the corresponding grid coordinate. This returns true if the coordinate is valid within the grid bounds.</li>
</ul>
</li>



<li><strong>IsCellEmpty(int x, int y), IsCellEmpty(int x, int y, out TItem item):</strong>
<ul class="wp-block-list">
<li>This method is use to check if the cell at the specified grid coordinates is empty (i.e., does not contain an item).</li>
</ul>
</li>



<li><strong>IsCellEmpty(Vector2 pos):</strong>
<ul class="wp-block-list">
<li>This is a overloaded method that checks if the cell at the specified world position is empty.</li>
</ul>
</li>



<li><strong>GetWorldPosition(int x, int y):</strong>
<ul class="wp-block-list">
<li>This method calculates and returns the world position of a grid cell based on its coordinates.</li>
</ul>
</li>



<li><strong>TrySetItem(Vector2 pos, TItem obj, out Vector2 positionToSet):</strong>
<ul class="wp-block-list">
<li>Tries to set an item at the specified world position in the grid. If the position is valid and the cell is empty, sets the item in the grid and returns true.</li>
</ul>
</li>



<li><strong>TriggerItemChangedEvent(int x, int y):</strong>
<ul class="wp-block-list">
<li>This is use to invokes the GridItemChanged event for the specified grid coordinates.</li>
</ul>
</li>



<li><strong>TryGetItem(Vector2 pos, out TItem obj)</strong>:
<ul class="wp-block-list">
<li>Attempts to get the item at the specified world position in the grid, respectively. Returns true if successful, along with the item.</li>
</ul>
</li>



<li><strong>TryRemoveItem(Vector2 pos, out TItem removedItem):</strong>
<ul class="wp-block-list">
<li>Attempts to remove the item at the specified world position in the grid, respectively. Returns true if successful, along with the item so it can be cleanup.</li>
</ul>
</li>
</ul>



<p><br>This is how you can create a custom grid. It&#8217;s important to note that this implementation isn&#8217;t perfect or exhaustive. It&#8217;s a simple demonstration, and further optimization and feature additions can be made based on specific requirements. If you&#8217;re unsure how to use this grid, you can refer to the <a href="https://github.com/nepalisameer/custom-grid-system">GitHub pages</a> for a simple demo.</p>



<p><strong>Check out my other post :</strong></p>



<ul class="wp-block-list">
<li><a href="https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/">Implementing Scene Management with Loading Screen in Godot Engine</a>.</li>



<li><a href="https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/">How to implement Google Game Play Services in Godot using C#</a>.</li>
</ul>
<p>The post <a href="https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/">Godot Engine &#8211; Build Custom Grid System using C#</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Scene Management with Loading Screen &#8211; Godot Engine</title>
		<link>https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/</link>
					<comments>https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/#respond</comments>
		
		<dc:creator><![CDATA[Samee]]></dc:creator>
		<pubDate>Fri, 29 Mar 2024 10:48:51 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[godot]]></category>
		<category><![CDATA[loading]]></category>
		<category><![CDATA[loading screen]]></category>
		<guid isPermaLink="false">https://tweakgame.com/?p=3020</guid>

					<description><![CDATA[<p>Hey everyone, In this post, we&#8217;re diving into a topic that&#8217;s crucial for any game developer: scene management. Specifically, we&#8217;ll&#8230;</p>
<p>The post <a href="https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/">Scene Management with Loading Screen &#8211; Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hey everyone, In this post, we&#8217;re diving into a topic that&#8217;s crucial for any game developer: scene management. Specifically, we&#8217;ll be exploring how to level up your scene transitions by implementing a threaded loading approach, complete with a loading screen. In game development, efficient scene management is crucial for creating seamless transitions between different parts of the game. Additionally, providing visual feedback during scene loading can greatly enhance the player experience.</p>



<p>First things first, let&#8217;s introduce the SceneManager class. This class is going to be our go-to for managing scene transitions. But before we get into the nitty-gritty, let&#8217;s talk about the importance of scene management in game development.</p>



<p>Smooth scene transitions are like the glue that holds your game together. Whether your players are moving between levels, accessing menus, or triggering cutscenes, you want those transitions to be seamless. And that&#8217;s where the SceneManager comes in. Our SceneManager class is designed to be a singleton, ensuring that there&#8217;s only ever one instance floating around. This helps prevent any messy conflicts during transitions and keeps things running smoothly behind the scenes. </p>



<p>Now, let&#8217;s talk about the loading screen. We&#8217;ve all experienced those moments when a game seems to freeze up while loading a new scene. It&#8217;s not the most elegant experience, is it? That&#8217;s why we&#8217;ve implemented a loading screen feature right into our SceneManager class for simplicity sake, but of course it can be done in many different ways.</p>



<p>With our loading screen in place, players get a visual cue that something&#8217;s happening in the background. No more staring at a blank screen wondering if the game has crashed! Plus, with the option to use threads for asynchronous loading, we can keep the main thread free and the gameplay uninterrupted.</p>



<pre class="wp-block-code"><code>public partial class SceneManager : Node
{
    public static SceneManager Instance { get; private set; }
    private string _sceneToLoad = "";
    private double _time = 0;
    private double _minimumWaitTime = 2f;
    private bool _useThread = false;
    private string _loadingScreenScenePath = "res://loading_screen.tscn";
    private LoadingScreen _loadingScreen;
    private Array _progressArray;
    public override void _Ready()
    {
        if (Instance == null)
        {
            Instance = this;
            _loadingScreen = ResourceLoader.Load&lt;PackedScene&gt;(_loadingScreenScenePath).Instantiate&lt;LoadingScreen&gt;();
        }
        else
        {
            QueueFree();
        }
    }
    /// &lt;summary&gt;
    /// Go to scene without loading screen and without using threads
    /// &lt;/summary&gt;
    /// &lt;param name="scenePath"&gt;&lt;/param&gt;
    public void GoToSceneNoLoadingScreen(string scenePath)
    {
        var packedScene = ResourceLoader.Load&lt;PackedScene&gt;(scenePath);
        var scene = packedScene.Instantiate();
        var root = GetTree().Root;
        // get current scene and remove it
        var currentScene = root.GetChild(root.GetChildCount() - 1);
        currentScene.QueueFree();
        root.AddChild(scene);
    }
    /// &lt;summary&gt;
    /// Go to scene with loading screen and using threads
    /// &lt;/summary&gt;
    /// &lt;param name="scenePath"&gt;&lt;/param&gt;
    /// &lt;param name="minimumWaitTime"&gt;&lt;/param&gt;
    /// &lt;param name="useSubThreads"&gt;&lt;/param&gt;
    public void GoToSceneThreadedWithLoadingScreen(string scenePath, double minimumWaitTime = 2f, bool useSubThreads = false)
    {
        AddChild(_loadingScreen);
        _progressArray = new Array();
        _useThread = true;
        _minimumWaitTime = minimumWaitTime;
        _sceneToLoad = scenePath;
        // currently retun value is discarded 
        // but if you need to log more information, you can use the return value
        _ = ResourceLoader.LoadThreadedRequest(path: scenePath, useSubThreads: useSubThreads);
    }
    public override void _Process(double delta)
    {

        if (_useThread)
        {
            _time += delta;
            
            if (ResourceLoader.LoadThreadedGetStatus(_sceneToLoad, _progressArray) == ResourceLoader.ThreadLoadStatus.InProgress)
            {
                _loadingScreen.SetProgress(_progressArray.First().AsSingle() * 100);
            }
            else if (ResourceLoader.LoadThreadedGetStatus(_sceneToLoad,_progressArray) == ResourceLoader.ThreadLoadStatus.Loaded &amp;&amp; _time &gt; _minimumWaitTime)
            {
                // You can also use CallDeferred method to run at idle time
                //CallDeferred(MethodName.LoadScene);
                LoadScene();
            }
            // or use dummy % for loading screen
            if (_time &lt; _minimumWaitTime)
            {
                _loadingScreen.SetProgress((float)(_time / _minimumWaitTime) * 100);
            }
        }
    }
    private void LoadScene()
    {
        if (ResourceLoader.LoadThreadedGet(_sceneToLoad) is PackedScene packedScene)
        {
            var scene = packedScene.Instantiate();
            var root = GetTree().Root;
            // remove current scene
            var currentScene = root.GetChild(root.GetChildCount() - 1);
            currentScene.QueueFree();
            root.AddChild(scene);
        }
        RemoveChild(_loadingScreen);
        ResetParam();
    }
    public override void _ExitTree()
    {
        // if you add node manually, make sure to free it
        _loadingScreen?.QueueFree();
    }
    private void ResetParam()
    {
        _time = 0;
        _useThread = false;
    }
}</code></pre>



<p>But how does it all work? Let&#8217;s break it down:</p>



<ol class="wp-block-list">
<li><strong>Scene Loading Methods</strong>: We&#8217;ve provided two handy methods for transitioning between scenes. Need to jump to a new scene without any fuss? Use <code>GoToSceneNoLoadingScreen</code>. Want to add some pizzazz with a loading screen? Opt for <code>GoToSceneThreadedWithLoadingScreen</code>.</li>



<li><strong>Threaded Loading</strong>: By leveraging threads, we can load resources in the background while the game continues to run smoothly. This is especially useful for loading large scenes or assets without causing any dreaded lag spikes.</li>



<li><strong>Loading Progress</strong>: Our SceneManager class continuously updates the loading progress on the loading screen. Players can see exactly how far along the loading process is, keeping them engaged and informed. It can be further optimized by checking status between certain interval.</li>



<li><strong>Cleanup</strong>: We&#8217;ve made sure to clean up after ourselves with the <code>_ExitTree</code> method. No orphaned nodes hanging around causing memory leaks here!</li>
</ol>



<p>In conclusion, scene management is a critical aspect of game development, and with the right tools, you can take your game to the next level. By implementing a threaded loading approach and incorporating a sleek loading screen, you can create seamless transitions that keep players immersed in your game world.</p>



<p>Also check out the full source code with demo on <a href="https://github.com/nepalisameer/scene-management-godot">GitHub</a>!&#8221;</p>



<p><strong>Check out my other post :</strong></p>



<ul class="wp-block-list">
<li><a href="https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/">Godot Engine – Build Custom Grid System using C#</a></li>



<li><a href="https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/">How to implement Google Game Play Services in Godot using C#</a>.</li>
</ul>
<p>The post <a href="https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/">Scene Management with Loading Screen &#8211; Godot Engine</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Google Play Game Services in Godot using C#</title>
		<link>https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/</link>
					<comments>https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/#comments</comments>
		
		<dc:creator><![CDATA[Samee]]></dc:creator>
		<pubDate>Mon, 04 Mar 2024 11:19:58 +0000</pubDate>
				<category><![CDATA[Tutorials]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[godot]]></category>
		<category><![CDATA[google game play services]]></category>
		<guid isPermaLink="false">https://tweakgame.com/?p=2967</guid>

					<description><![CDATA[<p>In this article, we&#8217;ll talk about how to integrate Google Play Game Services into Godot using C#. This can be&#8230;</p>
<p>The post <a href="https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/">Google Play Game Services in Godot using C#</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>In this article, we&#8217;ll talk about how to integrate Google Play Game Services into Godot using C#. This can be achieved using two approaches. One method involves creating a custom plugin utilizing the available SDK, while the other leverages existing plugins. We&#8217;ll focus on utilizing an available plugin to seamlessly implement the service using C#. By following these steps, you&#8217;ll be able to integrate Google Play Game Services into your Godot projects effortlessly.   </p>



<p>To achieve this, we&#8217;ll utilize <a href="https://github.com/Iakobs/godot-play-game-services">this plugin</a> (don&#8217;t forget to give it a star) and ensure to follow the setup process outlined on its official page. Once the plugin is correctly set up, it should function seamlessly. However, since everything is in GDScript, we need to create a wrapper around it to utilize it within C# code. This approach is not only applicable to <a href="https://github.com/Iakobs/godot-play-game-services">this plugin</a> but can also be applied to any other plugin. For simplicity, I&#8217;ll create a wrapper for initializing the plugin and SignInClient only. However, implementing other features is equally straightforward, as you&#8217;ll see below.</p>



<p>To begin, you can explore all the methods exposed by the plugin by referring to the <a href="https://godot.jacobibanez.com/plugin/index.html">Documentation Section</a> and locating the GodotAndroidPlugin class. Once you&#8217;ve familiarized yourself with the available methods, let&#8217;s dive into the implementation process.</p>



<p>Define the <code>GodotPlayGameService</code> class as a partial class inheriting from the <code>Node</code> class in Godot.</p>



<pre class="wp-block-code"><code>public partial class GodotPlayGameService : Node
{
}</code></pre>



<p>Define a property <code>Plugin</code> of type <a href="https://docs.godotengine.org/en/stable/classes/class_object.html"><code>GodotObject</code> </a>with a private setter. This property will be used to store a reference to the Android plugin for the <code>GodotPlayGameService</code>, allowing interaction with it within the class methods.</p>



<pre class="wp-block-code"><code>
public partial class GodotPlayGameService : Node
{
     public GodotObject Plugin { get; private set; }
}</code></pre>



<p>Implement the <code>_Ready()</code> method override and Initialize the plugin.</p>



<pre class="wp-block-code"><code>public partial class GodotPlayGameService : Node
{
    // Represents the Android plugin for the GodotPlayGameService.
    public GodotObject Plugin { get; private set; }
    const string plugin_name = "GodotPlayGameServices";
    public override void _Ready()
    {
        if (Plugin == null)
        {
            if (Engine.HasSingleton(plugin_name))
            {
                Plugin = Engine.GetSingleton(plugin_name);
                Plugin.Call("initialize");
            }
            else
            {
                GD.PrintErr("No plugin found.");
            }
        }
    }
}</code></pre>



<p>For the Sign In functionality, we will implement three methods of plugin: isAuthenticated, signIn, and requestServerSideAccess, along with their corresponding signals. Let&#8217;s proceed with the implementation process.</p>



<pre class="wp-block-code"><code> public partial class GodotPlayGameService : Node
 {
     // Represents the Android plugin for the GodotPlayGameService.
     public GodotObject Plugin { get; private set; }
     const string plugin_name = "GodotPlayGameServices";

     public delegate void AuthenticationDelegate(bool isAuthenticated);
     // Event for when the user is authenticated
     public event AuthenticationDelegate UserAuthenticated;

     // Event for when server side access is requested
     public event AuthenticationDelegate ServerSideAccessRequested;
     public override void _Ready()
     {
         if (Plugin == null)
         {
             if (Engine.HasSingleton(plugin_name))
             {
                 Plugin = Engine.GetSingleton(plugin_name);
                 Plugin.Call("initialize");
             }
             else
             {
                 GD.PrintErr("No plugin found.");
             }
         }
         // Connects signals from the AndroidPlugin instance to corresponding methods
         Plugin?.Connect("userAuthenticated", new Callable(this, nameof(OnUserAuthenticatedSignalConnected)));
         Plugin?.Connect("serverSideAccessRequested", new Callable(this, nameof(ServerSideAccessRequestedSignalConnected)));
     }
     /// &lt;summary&gt;
     /// Invokes the UserAuthenticated event with the specified authentication status.
     /// &lt;/summary&gt;
     /// &lt;param name="isAuthenticated"&gt;The authentication status.&lt;/param&gt;
     private void OnUserAuthenticatedSignalConnected(bool isAuthenticated)
     {
         UserAuthenticated?.Invoke(isAuthenticated);
     }

     /// &lt;summary&gt;
     /// Invokes the ServerSideAccessRequested event with the specified authentication status.
     /// &lt;/summary&gt;
     /// &lt;param name="isAuthenticated"&gt;The authentication status.&lt;/param&gt;
     private void ServerSideAccessRequestedSignalConnected(bool isAuthenticated)
     {
         ServerSideAccessRequested?.Invoke(isAuthenticated);
     }
     /// &lt;summary&gt;
     /// Check if the user is authenticated.
     /// &lt;/summary&gt;
     public void IsAuthenticated()
     {
         Plugin?.Call("isAuthenticated");
     }

     /// &lt;summary&gt;
     /// Sign in the user.
     /// &lt;/summary&gt;
     public void SignIn()
     {
         Plugin?.Call("signIn");
     }

     /// &lt;summary&gt;
     /// Request server side access with the specified server client ID and force refresh token flag.
     /// &lt;/summary&gt;
     /// &lt;param name="serverClientId"&gt;The server client ID to request access for.&lt;/param&gt;
     /// &lt;param name="forceRefreshToken"&gt;Whether to force refresh the token.&lt;/param&gt;
     public void RequestServerSideAccess(string serverClientId, bool forceRefreshToken)
     {
         Plugin?.Call("requestServerSideAccess", serverClientId, forceRefreshToken);
     }
 }</code></pre>



<p>If you&#8217;ve noticed, all methods and signals correspond to the exposed methods of the plugin, making it incredibly easy to work with. This is just a simple demonstration; for further details and a demo, you can check out <a href="https://github.com/nepalisameer/google-game-play-service-csharp-demo">this GitHub repository</a>.</p>



<p><strong>Check out my other post :</strong></p>



<ul class="wp-block-list">
<li><a href="https://tweakgame.com/implementing-scene-management-with-loading-screen-in-godot-engine/">Implementing Scene Management with Loading Screen in Godot Engine</a>.</li>



<li><a href="https://tweakgame.com/godot-engine-build-custom-grid-system-using-csharp/">Godot Engine – Build Custom Grid System using C#</a>.</li>
</ul>
<p>The post <a href="https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/">Google Play Game Services in Godot using C#</a> appeared first on <a href="https://tweakgame.com">TweakGame</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://tweakgame.com/how-to-implement-google-game-play-services-in-godot-using-csharp/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: tweakgame.com @ 2026-06-21 19:13:42 by W3 Total Cache
-->