feat : got the grid synced between the backend code and the UI code

This commit is contained in:
Damien Ostler 2024-01-14 15:51:07 -05:00
parent d26a28fafe
commit bf2de87f64
16 changed files with 231 additions and 60 deletions

0
.attach_pid63465 Normal file
View File

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Linq;
using Godot;
using GodotGridInventory.Code.Grid.Enums;
using GodotGridInventory.Code.UI;
namespace GodotGridInventory.Code.Grid;
@ -89,12 +90,33 @@ public class InventoryGrid
/// <param name="state">The state to set the cells</param>
private void SetCellAreaState(Vector2 position, Vector2 size, EnumInventoryGridCellState state)
{
foreach (var cell in GridCells.Where(cell => cell.Position.X >= position.X && cell.Position.X < position.X + size.X && cell.Position.Y >= position.Y && cell.Position.Y < position.Y + size.Y))
var cells = GridCells.Where(cell =>
cell.Position.X >= position.X && cell.Position.X < position.X + size.X && cell.Position.Y >= position.Y &&
cell.Position.Y < position.Y + size.Y).ToList();
foreach (var cell in cells)
{
cell.State = state;
}
}
/// <summary>
/// Sets the item of a selection of cells at a given position and size in inventory grid space.
/// </summary>
/// <param name="position">The position of the cells to set from the top left..</param>
/// <param name="size">The size of the area to set starting at the top left.</param>
/// <param name="item">The item to set the cells</param>
private void SetCellAreaItem(Vector2 position, Vector2 size, Item item, InventoryGridItem itemGraphic)
{
var cells = GridCells.Where(cell =>
cell.Position.X >= position.X && cell.Position.X < position.X + size.X && cell.Position.Y >= position.Y &&
cell.Position.Y < position.Y + size.Y).ToList();
foreach (var cell in cells)
{
cell.Item = item;
cell.ItemGraphic = itemGraphic;
}
}
/// <summary>
/// Gets the first available cell position that can fit an item of a given size.
/// </summary>
@ -102,13 +124,6 @@ public class InventoryGrid
/// <returns>The first coordinates available for something of the given size, or null if no space available.</returns>
private Vector2? GetAvailableCellPosition(Vector2 size)
{
var availableCells = GridCells.Where(cell => cell.State == EnumInventoryGridCellState.Available);
var cell = availableCells.FirstOrDefault();
if(cell != null)
{
return cell.Position;
}
for (int x = 0; x <= GridSize.X - size.X; x++)
{
for (int y = 0; y <= GridSize.Y - size.Y; y++)
@ -145,13 +160,13 @@ public class InventoryGrid
/// <param name="itemId">The ID of the item to add.</param>
/// <param name="position">The position to add the item at in inventory grid space. If null then will insert at first available place.</param>
/// <returns></returns>
public bool AddItem(string itemId, Vector2? position = null)
public Vector2? AddItem(string itemId, InventoryGridItem itemGraphic, Vector2? position = null)
{
var item = ItemDatabase.Instance.GetItemConfiguration(itemId);
if(item == null)
{
GD.PrintErr("Attempted to add item with id " + itemId + ", which does not exist.");
return false;
return null;
}
if(position.HasValue==false)
@ -162,11 +177,12 @@ public class InventoryGrid
if (position.HasValue==false)
{
GD.PrintErr("Attempted to add item with id " + itemId + ", but there is no space available.");
return false;
return null;
}
SetCellAreaState((Vector2)position, item.Size, EnumInventoryGridCellState.Unavailable);
return true;
SetCellAreaItem((Vector2)position, item.Size, item, itemGraphic);
return position;
}
/// <summary>

View File

@ -15,9 +15,22 @@ public partial class InventoryController : Control
private readonly ItemDatabase _itemDatabase = ItemDatabase.Instance;
private int _inventoryIdCounter = 0;
private Inventory _inventoryUI;
#endregion
[Export] public float CellSize { get; set; } = 25;
[Export] public PackedScene InventoryUIResource { get; set; }
[Export] public PackedScene InventoryGridUIResource { get; set; }
[Export] public PackedScene InventoryGridItemUIResource { get; set; }
public override void _Ready()
{
_inventoryUI = InventoryUIResource.Instantiate() as Inventory;
_inventoryUI.InitializeInventory(this);
AddChild(_inventoryUI);
AddInventory("Player Inventory", new Vector2(10, 10), new string[] {"item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small","item_small"});
base._Ready();
}
#region Public Methods
public List<InventoryModel> GetInventoriesLoaded()
@ -56,12 +69,10 @@ public partial class InventoryController : Control
public void AddInventory(string name, Vector2 size, string[] items)
{
var inventoryGrid = new InventoryGrid(this, size);
foreach (var item in items)
{
inventoryGrid.AddItem(item);
}
var gridInterface = InventoryGridUIResource.Instantiate() as UI.InventoryGrid;
_inventoryUI.AddChild(gridInterface);
gridInterface.InitializeInventoryGrid(inventoryGrid, this);
var itemGraphics = new List<InventoryGridItem>();
_inventories.Add(_inventoryIdCounter, new InventoryModel()
{
Id = _inventoryIdCounter,
@ -70,11 +81,19 @@ public partial class InventoryController : Control
Cells = inventoryGrid.GridCells,
Open = false,
Grid = inventoryGrid,
GridInterface = null,
GridInterface = gridInterface,
GridWidth = (int)Math.Round(size.X),
GridHeight = (int)Math.Round(size.Y)
});
foreach (var item in items)
{
var itemConfig = _itemDatabase.GetItemConfiguration(item);
var itemGraphic = InventoryGridItemUIResource.Instantiate() as InventoryGridItem;
itemGraphic.InitializeItem(itemConfig, this);
gridInterface.AddItem(itemGraphic,false);
itemGraphics.Add(itemGraphic);
}
_inventoryIdCounter++;
}
@ -86,7 +105,7 @@ public partial class InventoryController : Control
GD.PrintErr($"Inventory not found with id {Id}.");
return false;
}
inventory.GridInterface.QueueFree();
_inventories.Remove(Id);
GD.Print($"Inventory {inventory.Name} with id {inventory.Id} removed.");
return true;
@ -135,10 +154,6 @@ public partial class InventoryController : Control
#endregion
private Dictionary<int,InventoryModel> _inventories { get; set; } = new Dictionary<int,InventoryModel>();
public override void _Ready()
{
base._Ready();
}
}

View File

@ -4,14 +4,18 @@ using Godot.Collections;
namespace GodotGridInventory.Code;
public class ItemDatabase
public partial class ItemDatabase:Node
{
public static ItemDatabase Instance { get; } = new();
public static ItemDatabase Instance = null;
private readonly Dictionary<string, Item> _itemDatabase = new();
public ItemDatabase()
{
InitializeItemDatabase();
if (Instance == null)
{
Instance = this;
InitializeItemDatabase();
}
}
public Item GetItemConfiguration(string id)
@ -25,7 +29,7 @@ public class ItemDatabase
var items = DirAccess.GetFilesAt(ItemDatabaseConstants.ITEMS_PATH).Where(filePath => filePath.EndsWith(ItemDatabaseConstants.ITEM_EXTENSION));
foreach (var item in items)
{
var itemResource = GD.Load<Item>(item);
var itemResource = GD.Load<Item>($"{ItemDatabaseConstants.ITEMS_PATH}/{item}");
if (itemResource != null)
{
_itemDatabase.Add(itemResource.Id, itemResource);

View File

@ -2,6 +2,6 @@ namespace GodotGridInventory.Code;
public class ItemDatabaseConstants
{
public static string ITEMS_PATH = "res://grid_inventory_system/items";
public static string ITEMS_PATH = "res://Resources/Items";
public static string ITEM_EXTENSION = ".tres";
}

View File

@ -2,8 +2,8 @@ using Godot;
using GodotGridInventory.Code.Grid;
namespace GodotGridInventory.Code.UI;
public class Inventory: Control
public partial class Inventory: Control
{
private InventoryGridItem _inventoryItemDragged = null;
private Vector2 _inventoryItemCursorOffset = Vector2.Zero;
@ -11,9 +11,9 @@ public class Inventory: Control
private Vector2 _inventoryItemDraggedLastPos = Vector2.Zero;
private InventoryController _inventoryController;
[Export] public string InventoryDragActionName = "inventory_drag";
[Export] public string InventoryDropActionName = "inventory_release";
[Export] public string InventoryRotateActionName = "inventory_rotate";
[Export] public string InventoryDragActionName { get; set; } = "inventory_drag";
[Export] public string InventoryDropActionName { get; set; } = "inventory_release";
[Export] public string InventoryRotateActionName { get; set; } = "inventory_rotate";
#region Private Methods
@ -21,6 +21,8 @@ public class Inventory: Control
private InventoryModel GetInventoryUnderCursor(Vector2 cursor_pos)
{
GD.Print("Checking for inventory under cursor.");
if(_inventoryController== null)
return null;
foreach (var inventory in _inventoryController.GetInventoriesLoaded())
{
if (inventory.GridInterface.GetGlobalRect().HasPoint(cursor_pos))
@ -36,17 +38,33 @@ public class Inventory: Control
private void Grab(Vector2 cursorPos)
{
GD.Print("Grabbing item.");
var inventory = GetInventoryUnderCursor(cursorPos);
if (inventory != null)
{
var inventoryItem = inventory.Grid?.GetCell(cursorPos).ItemGraphic;
GD.Print("Inventory found under cursor.");
var inventoryItem = inventory.Grid?.GetCell(inventory.GridInterface.ScreenCoordsToInventoryGridCoords(cursorPos))?.ItemGraphic;
if (inventoryItem != null)
{
GD.Print("Inventory item found under cursor.");
_inventoryItemDragged = inventoryItem;
_inventoryItemDraggedLastContainer = inventory.GridInterface;
_inventoryItemDraggedLastPos = _inventoryItemDragged.GlobalPosition;
var parent = _inventoryItemDragged.GetParent();
if(parent!=null)
parent.RemoveChild(_inventoryItemDragged);
AddChild(_inventoryItemDragged);
_inventoryItemCursorOffset = _inventoryItemDragged.GlobalPosition - cursorPos;
GD.Print("Inventory item grabbed.");
}
else
{
GD.Print("Inventory item not found under cursor.");
}
}
else
{
GD.Print("Inventory not found under cursor.");
}
}
@ -61,6 +79,7 @@ public class Inventory: Control
ReturnItem();
return;
}
ReturnItem();
}
private void ReturnItem()
@ -95,15 +114,21 @@ public class Inventory: Control
var cursor_pos = GetGlobalMousePosition();
if (Input.IsActionJustPressed(InventoryDragActionName))
if (Input.IsActionJustPressed(InventoryDragActionName) && _inventoryItemDragged == null)
{
Grab(cursor_pos);
}
if (Input.IsActionJustReleased(InventoryDragActionName))
if (Input.IsActionJustReleased(InventoryDragActionName) && _inventoryItemDragged == null)
{
Release(cursor_pos);
}
if (_inventoryItemDragged != null)
{
_inventoryItemDragged.GlobalPosition = cursor_pos + _inventoryItemCursorOffset;
}
base._Process(delta);
}
#endregion

View File

@ -6,17 +6,15 @@ namespace GodotGridInventory.Code.UI;
public partial class InventoryGrid:Control
{
private PackedScene _gridSlotResource;
private Grid.InventoryGrid _inventoryGrid;
private InventoryController _inventoryController;
[Export] public Control GridContainer;
[Export] public string GridSlotPath;
[Export] public Control GridContainer { get; set; }
[Export] public PackedScene GridSlotResource { get; set; }
public override void _Ready()
{
_gridSlotResource = GD.Load<PackedScene>(GridSlotPath);
base._Ready();
}
@ -31,28 +29,46 @@ public partial class InventoryGrid:Control
{
var cellPosition = new Vector2(x, y);
var cell = _inventoryGrid.GetCell(cellPosition);
var gridSlot = _gridSlotResource.Instantiate() as Control;
var gridSlot = GridSlotResource.Instantiate() as Control;
gridSlot.Position = new Vector2(x * _inventoryController.CellSize, y * _inventoryController.CellSize);
gridSlot.Size = new Vector2(_inventoryController.CellSize-1, _inventoryController.CellSize-1);
GridContainer.AddChild(gridSlot);
}
}
}
private Vector2 ScreenCoordsToInventoryGridCoords(Vector2 cursorPos)
public Vector2 ScreenCoordsToInventoryGridCoords(Vector2 cursorPos)
{
var x = Mathf.FloorToInt(cursorPos.X / _inventoryController.CellSize);
var y = Mathf.FloorToInt(cursorPos.Y / _inventoryController.CellSize);
return new Vector2(x, y);
}
public void AddItem(InventoryGridItem inventoryItemDragged)
public void AddItem(InventoryGridItem inventoryItemDragged, bool useScreenCoords = true)
{
if (useScreenCoords == false)
{
var result = _inventoryGrid.AddItem(inventoryItemDragged.Item.Id, inventoryItemDragged);
if(result!=null)
{
var parent = inventoryItemDragged.GetParent();
if(parent!=null)
parent.RemoveChild(inventoryItemDragged);
AddChild(inventoryItemDragged);
inventoryItemDragged.Position = (Vector2)result * _inventoryController.CellSize;
}
return;
}
var cursorPos = GetGlobalMousePosition();
var gridCoords = ScreenCoordsToInventoryGridCoords(cursorPos);
if (_inventoryGrid.AddItem(inventoryItemDragged.Item.Id, gridCoords))
if (_inventoryGrid.AddItem(inventoryItemDragged.Item.Id, inventoryItemDragged, gridCoords)!=null)
{
inventoryItemDragged.Position = gridCoords * _inventoryController.CellSize;
var parent = inventoryItemDragged.GetParent();
if(parent!=null)
parent.RemoveChild(inventoryItemDragged);
AddChild(inventoryItemDragged);
inventoryItemDragged.Position = gridCoords * _inventoryController.CellSize;
}
}
}

View File

@ -4,9 +4,15 @@ namespace GodotGridInventory.Code.UI;
public partial class InventoryGridItem: Control
{
public InventoryGridItem(Item item)
private InventoryController _inventoryController;
[Export] private TextureRect Texture { get; set; } = null;
public Item Item { get; set; } = null;
public void InitializeItem(Item item, InventoryController inventoryController)
{
_inventoryController = inventoryController;;
Item = item;
Texture.Texture = item.Texture;
Texture.Size = new Vector2(Item.Size.X*_inventoryController.CellSize, Item.Size.Y*_inventoryController.CellSize);
}
public Item Item { get; } = null;
}

View File

@ -1,6 +1,6 @@
[gd_resource type="Resource" script_class="ItemConfiguration" load_steps=3 format=3 uid="uid://c8ge77yvt0q84"]
[gd_resource type="Resource" script_class="Item" load_steps=3 format=3 uid="uid://c8ge77yvt0q84"]
[ext_resource type="Script" path="res://Code/Items/ItemConfiguration.cs" id="1_8ae1i"]
[ext_resource type="Script" path="res://Code/Items/Item.cs" id="1_8ae1i"]
[ext_resource type="Texture2D" uid="uid://bj3tjdbw5xdlj" path="res://icon.svg" id="1_arnqm"]
[resource]
@ -8,7 +8,8 @@ script = ExtResource("1_8ae1i")
Id = "item_small"
Name = "Item Small"
Description = "A small item."
Size = Vector2(3, 3)
Size = Vector2(2, 2)
Texture = ExtResource("1_arnqm")
Actions = 0
Flags = 0
Slots = PackedStringArray()
Tags = PackedStringArray()

10
Scenes/inventory.tscn Normal file
View File

@ -0,0 +1,10 @@
[gd_scene load_steps=2 format=3 uid="uid://cywjpuiv83f8n"]
[ext_resource type="Script" path="res://Code/UI/Inventory.cs" id="1_n60jp"]
[node name="Inventory" type="Control"]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_n60jp")

View File

@ -0,0 +1,20 @@
[gd_scene load_steps=5 format=3 uid="uid://b217xbxheivtx"]
[ext_resource type="Script" path="res://Code/InventoryController.cs" id="1_fowd5"]
[ext_resource type="PackedScene" uid="uid://brwundq5p4s3c" path="res://Scenes/inventory_grid.tscn" id="2_74voh"]
[ext_resource type="PackedScene" uid="uid://cywjpuiv83f8n" path="res://Scenes/inventory.tscn" id="2_wrxgt"]
[ext_resource type="PackedScene" uid="uid://dxmeyjh8klieh" path="res://Scenes/inventory_item.tscn" id="4_8j1em"]
[node name="InventoryController" type="Control"]
layout_mode = 3
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
script = ExtResource("1_fowd5")
InventoryUIResource = ExtResource("2_wrxgt")
InventoryGridUIResource = ExtResource("2_74voh")
InventoryGridItemUIResource = ExtResource("4_8j1em")
[node name="Inventory" parent="." instance=ExtResource("2_wrxgt")]

View File

@ -0,0 +1,21 @@
[gd_scene load_steps=3 format=3 uid="uid://brwundq5p4s3c"]
[ext_resource type="Script" path="res://Code/UI/InventoryGrid.cs" id="1_5nylq"]
[ext_resource type="PackedScene" uid="uid://co3o3ra1efr45" path="res://Scenes/inventory_grid_slot.tscn" id="2_pkf75"]
[node name="InventoryGrid" type="Control" node_paths=PackedStringArray("GridContainer")]
layout_mode = 3
anchors_preset = 0
offset_right = 358.0
offset_bottom = 358.0
script = ExtResource("1_5nylq")
GridContainer = NodePath("Panel")
GridSlotResource = ExtResource("2_pkf75")
[node name="Panel" type="Panel" parent="."]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2

View File

@ -0,0 +1,8 @@
[gd_scene load_steps=2 format=3 uid="uid://co3o3ra1efr45"]
[sub_resource type="PlaceholderTexture2D" id="PlaceholderTexture2D_rtlwt"]
[node name="InventoryGridSlot" type="TextureRect"]
offset_right = 25.0
offset_bottom = 25.0
texture = SubResource("PlaceholderTexture2D_rtlwt")

View File

@ -0,0 +1,17 @@
[gd_scene load_steps=3 format=3 uid="uid://dxmeyjh8klieh"]
[ext_resource type="Script" path="res://Code/UI/InventoryGridItem.cs" id="1_wwufo"]
[ext_resource type="Texture2D" uid="uid://bj3tjdbw5xdlj" path="res://icon.svg" id="2_vmwaj"]
[node name="InventoryItem" type="Control" node_paths=PackedStringArray("Texture")]
layout_mode = 3
anchors_preset = 0
offset_right = 40.0
offset_bottom = 40.0
script = ExtResource("1_wwufo")
Texture = NodePath("InventoryItemGraphic")
[node name="InventoryItemGraphic" type="TextureRect" parent="."]
layout_mode = 0
texture = ExtResource("2_vmwaj")
expand_mode = 1

View File

@ -1,12 +1,10 @@
[gd_scene load_steps=3 format=3 uid="uid://cc8f5p1w5xdyx"]
[gd_scene load_steps=2 format=3 uid="uid://cc8f5p1w5xdyx"]
[ext_resource type="Script" path="res://debug.cs" id="1_al802"]
[ext_resource type="Script" path="res://Code/InventoryController.cs" id="2_0yu34"]
[ext_resource type="PackedScene" uid="uid://b217xbxheivtx" path="res://Scenes/inventory_controller.tscn" id="1_qwtka"]
[node name="UI" type="CanvasLayer"]
[node name="Debug" type="Node" parent="."]
script = ExtResource("1_al802")
[node name="Inventory Controller" type="Node" parent="."]
script = ExtResource("2_0yu34")
[node name="InventoryController" parent="." instance=ExtResource("1_qwtka")]
CellSize = 32.0

View File

@ -11,13 +11,27 @@ config_version=5
[application]
config/name="Godot Grid Inventory"
run/main_scene="res://main.tscn"
config/features=PackedStringArray("4.2", "C#", "Forward Plus")
config/icon="res://icon.svg"
[autoload]
ItemDatabase="*res://Code/ItemDatabase.cs"
ItemDatabase="*res://Code/ItemDatabase/ItemDatabase.cs"
[dotnet]
project/assembly_name="Godot Grid Inventory"
[input]
inventory_drag={
"deadzone": 0.5,
"events": [Object(InputEventMouseButton,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"button_mask":0,"position":Vector2(0, 0),"global_position":Vector2(0, 0),"factor":1.0,"button_index":1,"canceled":false,"pressed":false,"double_click":false,"script":null)
]
}
inventory_rotate={
"deadzone": 0.5,
"events": [Object(InputEventKey,"resource_local_to_scene":false,"resource_name":"","device":-1,"window_id":0,"alt_pressed":false,"shift_pressed":false,"ctrl_pressed":false,"meta_pressed":false,"pressed":false,"keycode":0,"physical_keycode":82,"key_label":0,"unicode":114,"echo":false,"script":null)
]
}