From 97c931a50ecd4dc8ebde76bec64174ae1c889132 Mon Sep 17 00:00:00 2001 From: ObeseTermite Date: Tue, 16 Sep 2025 12:19:16 -0700 Subject: [PATCH] Added basic in chunk item spawning and movement --- combined/main.tscn | 6 +- logic/camera/camera.gd | 15 ++- logic/mechanics/arrow/arrow.gd | 3 + .../interaction/world_interaction.gd | 54 ++++++++++ .../interaction/world_interaction.gd.uid | 1 + .../interaction/world_interaction.tscn | 9 ++ logic/mechanics/item/item.gd | 3 +- logic/mechanics/item/item_globals.gd | 2 + logic/world/chunk/chunk.gd | 56 +++++++++++ logic/world/chunk/chunk.gdshader | 35 ++++++- logic/world/chunk/chunk_drawing.gd | 94 ++++++++++++------ logic/world/chunk/tile/tile_globals.gd | 5 + logic/world/world.gd | 36 ++++++- project.godot | 38 +++++++ resources/items/textures/item_atlas.png | Bin 468 -> 555 bytes .../items/textures/item_atlas.png.import | 2 +- resources/misc/arrows.png.import | 20 ++-- resources/tiles/textures/tile_atlas.png | Bin 426 -> 535 bytes .../tiles/textures/tile_atlas.png.import | 4 +- 19 files changed, 322 insertions(+), 61 deletions(-) create mode 100644 logic/mechanics/interaction/world_interaction.gd create mode 100644 logic/mechanics/interaction/world_interaction.gd.uid create mode 100644 logic/mechanics/interaction/world_interaction.tscn diff --git a/combined/main.tscn b/combined/main.tscn index aaf400d..1acabba 100644 --- a/combined/main.tscn +++ b/combined/main.tscn @@ -1,7 +1,8 @@ -[gd_scene load_steps=4 format=3 uid="uid://cjs660cs0u4rk"] +[gd_scene load_steps=5 format=3 uid="uid://cjs660cs0u4rk"] [ext_resource type="PackedScene" uid="uid://b17vn1ecnbc36" path="res://logic/world/world.tscn" id="1_tg0rs"] [ext_resource type="Script" uid="uid://f1n37ucrb0j4" path="res://logic/camera/camera.gd" id="2_ahkbh"] +[ext_resource type="PackedScene" uid="uid://dm5hhlwlhnmdb" path="res://logic/mechanics/interaction/world_interaction.tscn" id="3_5pa27"] [ext_resource type="PackedScene" uid="uid://cgrgaehjqja4d" path="res://logic/world/chunk/chunk_drawing.tscn" id="3_gphrn"] [node name="Main" type="Node2D"] @@ -11,6 +12,9 @@ [node name="Camera2D" type="Camera2D" parent="."] script = ExtResource("2_ahkbh") +[node name="World Interaction" parent="Camera2D" node_paths=PackedStringArray("world") instance=ExtResource("3_5pa27")] +world = NodePath("../../World") + [node name="Chunk Drawing" parent="." node_paths=PackedStringArray("world", "camera") instance=ExtResource("3_gphrn")] world = NodePath("../World") camera = NodePath("../Camera2D") diff --git a/logic/camera/camera.gd b/logic/camera/camera.gd index 1c05b47..0d117e8 100644 --- a/logic/camera/camera.gd +++ b/logic/camera/camera.gd @@ -8,8 +8,10 @@ var dragging = false @export var zoom_constant : float = 1.1 -@export var min_zoom = 0.3 -@export var max_zoom = 3 +@export var min_zoom : float = 0.3 +@export var max_zoom : float = 3 + +@export var speed : float = 1000 func get_camera_rect() -> Rect2: var pos = position @@ -39,3 +41,12 @@ func _process(delta: float) -> void: var current_mouse_position = get_local_mouse_position() position += (last_drag_position - current_mouse_position) last_drag_position = current_mouse_position + + if Input.is_action_pressed("camera_down"): + position.y += speed / zoom.y * delta + if Input.is_action_pressed("camera_up"): + position.y -= speed / zoom.y * delta + if Input.is_action_pressed("camera_left"): + position.x -= speed / zoom.x * delta + if Input.is_action_pressed("camera_right"): + position.x += speed / zoom.x * delta diff --git a/logic/mechanics/arrow/arrow.gd b/logic/mechanics/arrow/arrow.gd index a9ab684..e874bf3 100644 --- a/logic/mechanics/arrow/arrow.gd +++ b/logic/mechanics/arrow/arrow.gd @@ -2,3 +2,6 @@ class_name Arrow var direction : Vector2i var filter : int + +func _init(direction : Vector2i): + self.direction = direction diff --git a/logic/mechanics/interaction/world_interaction.gd b/logic/mechanics/interaction/world_interaction.gd new file mode 100644 index 0000000..5ef577e --- /dev/null +++ b/logic/mechanics/interaction/world_interaction.gd @@ -0,0 +1,54 @@ +extends Node2D + +@export var world : World + +@onready var object_shadow = $"Object Shadow" + +var direction : Vector2i = Vector2i(1, 0) + +func _input(event: InputEvent) -> void: + if event is InputEventMouseButton: + if event.button_index == MOUSE_BUTTON_LEFT and event.pressed: + var tile_position : Vector2i = world.global_position_to_tile(get_global_mouse_position()) + var chunk_position : Vector2i = world.tile_pos_to_chunk_pos(tile_position) + var position_in_chunk : Vector2i = tile_position - chunk_position * TileGlobals.chunk_size + + var chunk : Chunk = world.get_chunk_at(chunk_position) + + var new_arrow : Arrow = Arrow.new(direction) + + chunk.arrows[position_in_chunk] = new_arrow + chunk.recalculate() + world.updated.emit(chunk) + + elif event.button_index == MOUSE_BUTTON_RIGHT and event.pressed: + var tile_position : Vector2i = world.global_position_to_tile(get_global_mouse_position()) + var chunk_position : Vector2i = world.tile_pos_to_chunk_pos(tile_position) + var position_in_chunk : Vector2i = tile_position - chunk_position * TileGlobals.chunk_size + + var chunk : Chunk = world.get_chunk_at(chunk_position) + + chunk.arrows.erase(position_in_chunk) + chunk.recalculate() + world.updated.emit(chunk) + + elif event.is_action_pressed("rotate_right"): + direction = rotate_vector2i(direction) + elif event.is_action_pressed("rotate_left"): + direction = rotate_vector2i(direction, true) + +func rotate_vector2i(vector : Vector2i, counter_clockwise : bool = false) -> Vector2i: + if counter_clockwise: + return Vector2i(1,-1) * Vector2i(vector.y, vector.x) + return Vector2i(-1,1) * Vector2i(vector.y, vector.x) + +func _ready(): + object_shadow.z_index = 1 + object_shadow.texture = ImageTexture.create_from_image(preload("res://resources/misc/arrows.png").get_layer_data(0)) + +func _process(delta: float) -> void: + var tile_size = Vector2(TileGlobals.tile_size, TileGlobals.tile_size) + var object_shadow_position = (get_global_mouse_position() - tile_size/2).snapped(tile_size) + tile_size/2 + object_shadow.global_position = object_shadow_position + + object_shadow.look_at(object_shadow.global_position + Vector2(direction)) diff --git a/logic/mechanics/interaction/world_interaction.gd.uid b/logic/mechanics/interaction/world_interaction.gd.uid new file mode 100644 index 0000000..03a9080 --- /dev/null +++ b/logic/mechanics/interaction/world_interaction.gd.uid @@ -0,0 +1 @@ +uid://cpjhjc17ybuxg diff --git a/logic/mechanics/interaction/world_interaction.tscn b/logic/mechanics/interaction/world_interaction.tscn new file mode 100644 index 0000000..f35b810 --- /dev/null +++ b/logic/mechanics/interaction/world_interaction.tscn @@ -0,0 +1,9 @@ +[gd_scene load_steps=2 format=3 uid="uid://dm5hhlwlhnmdb"] + +[ext_resource type="Script" uid="uid://cpjhjc17ybuxg" path="res://logic/mechanics/interaction/world_interaction.gd" id="1_gh8ie"] + +[node name="World Interaction" type="Node2D"] +script = ExtResource("1_gh8ie") + +[node name="Object Shadow" type="Sprite2D" parent="."] +modulate = Color(1, 1, 1, 0.498039) diff --git a/logic/mechanics/item/item.gd b/logic/mechanics/item/item.gd index f5d2cc9..2c71475 100644 --- a/logic/mechanics/item/item.gd +++ b/logic/mechanics/item/item.gd @@ -3,5 +3,6 @@ class_name Item var id : int var direction : Vector2i -func _init(id : int): +func _init(id : int, direction : Vector2i): self.id = id + self.direction = direction diff --git a/logic/mechanics/item/item_globals.gd b/logic/mechanics/item/item_globals.gd index 7a4c301..c43ec79 100644 --- a/logic/mechanics/item/item_globals.gd +++ b/logic/mechanics/item/item_globals.gd @@ -3,6 +3,8 @@ extends Node var item_definitions : Array[ItemDefinition] var item_atlas : CompressedTexture2DArray +enum {WOOD, IRON} + const chunk_size : int = 32 const tile_size : int = 16 diff --git a/logic/world/chunk/chunk.gd b/logic/world/chunk/chunk.gd index 101ef68..a508bc9 100644 --- a/logic/world/chunk/chunk.gd +++ b/logic/world/chunk/chunk.gd @@ -3,10 +3,19 @@ class_name Chunk var tiles : Array[int] var position : Vector2i +var spawner_tiles : Array[Vector2i] + var items : Dictionary[Vector2i, Item] var arrows : Dictionary[Vector2i, Arrow] +var processed = false + +var incoming_items : Dictionary[Vector2i, Item] + +var tickable = false + func _init(position : Vector2i) -> void: + self.position = position var noise : FastNoiseLite = FastNoiseLite.new() @@ -36,6 +45,53 @@ func _init(position : Vector2i) -> void: tiles.append(tile_id) x += 1 + + if randi_range(0,10) == 0: + var tile_idx = randi_range(0, TileGlobals.chunk_size ** 2) + if tiles[tile_idx] == TileGlobals.GRASS: + tiles[tile_idx] = TileGlobals.TREE + + var tile_position = Vector2i(0, 0) + for tile : int in tiles: + if tile_position.x >= TileGlobals.chunk_size: + tile_position.y += 1 + tile_position.x = 0 + + if tile in TileGlobals.resource_tiles.keys(): + spawner_tiles.append(tile_position) + + tile_position.x += 1 + +## Updates chunk and returns whether it changed +func update() -> bool: + if not tickable: + return false + + var new_items : Dictionary[Vector2i, Item] + + for item_position : Vector2i in items.keys(): + var item = items[item_position] + + var new_position = item_position + item.direction + + new_items[new_position] = item + + items = new_items + + for tile_pos in spawner_tiles: + if arrows.has(tile_pos) and not items.has(tile_pos): + items[tile_pos] = Item.new(TileGlobals.resource_tiles[get_tile(tile_pos)], arrows[tile_pos].direction) + + return true + +func recalculate(): + if len(items) > 0 or len(arrows) > 0: + tickable = true + else: + tickable = false func get_tile(pos : Vector2i): return tiles[pos.y * TileGlobals.chunk_size + pos.x] + +func set_tile(pos : Vector2i, tile_id : int): + tiles[pos.y * TileGlobals.chunk_size + pos.x] = tile_id diff --git a/logic/world/chunk/chunk.gdshader b/logic/world/chunk/chunk.gdshader index e000c55..5a67b13 100644 --- a/logic/world/chunk/chunk.gdshader +++ b/logic/world/chunk/chunk.gdshader @@ -4,22 +4,47 @@ uniform float tile_count; const int chunk_size = 32; +uniform bool borders = true; +const float border_size = 0.01; + uniform int tiles[chunk_size*chunk_size]; uniform int items[chunk_size*chunk_size]; +uniform int arrows[chunk_size*chunk_size]; uniform sampler2DArray tile_texture : filter_nearest_mipmap; uniform sampler2DArray item_texture : filter_nearest; +uniform sampler2DArray arrow_texture : filter_nearest; void fragment() { - float item_id = float(items[int(floor(float(chunk_size) * UV.x) + float(chunk_size) * floor(float(chunk_size) * UV.y))]); - COLOR = texture(item_texture, - vec3(mod(UV.x * float(chunk_size), 1.0), mod(UV.y * float(chunk_size), 1.0), float(item_id)) // map - ); + COLOR = vec4(0,0,0,0); + int arrow_id = arrows[int(floor(float(chunk_size) * UV.x) + float(chunk_size) * floor(float(chunk_size) * UV.y))]; + if (arrow_id != -1){ + COLOR = texture(arrow_texture, + vec3(mod(UV.x * float(chunk_size), 1.0), mod(UV.y * float(chunk_size), 1.0), float(arrow_id)) // map + ); + } if (COLOR == vec4(0,0,0,0)){ - float tile_id = float(tiles[int(floor(float(chunk_size) * UV.x) + float(chunk_size) * floor(float(chunk_size) * UV.y))]); + int item_id = items[int(floor(float(chunk_size) * UV.x) + float(chunk_size) * floor(float(chunk_size) * UV.y))]; + if (item_id != -1){ + COLOR = texture(item_texture, + vec3(mod(UV.x * float(chunk_size), 1.0), mod(UV.y * float(chunk_size), 1.0), float(item_id)) // map + ); + } + } + if (COLOR == vec4(0,0,0,0)){ + int tile_id = tiles[int(floor(float(chunk_size) * UV.x) + float(chunk_size) * floor(float(chunk_size) * UV.y))]; COLOR = texture(tile_texture, vec3(mod(UV.x * float(chunk_size), 1.0), mod(UV.y * float(chunk_size), 1.0), float(tile_id)) // map ); } + + if (borders){ + if( + UV.x < border_size || UV.x > 1.0-border_size || + UV.y < border_size || UV.y > 1.0-border_size + ){ + COLOR -= vec4(0.1,0.1,0.1,0); + } + } } \ No newline at end of file diff --git a/logic/world/chunk/chunk_drawing.gd b/logic/world/chunk/chunk_drawing.gd index 0574d18..dfb74a2 100644 --- a/logic/world/chunk/chunk_drawing.gd +++ b/logic/world/chunk/chunk_drawing.gd @@ -7,60 +7,88 @@ extends Node2D var chunk_textures : Dictionary[Chunk, Sprite2D] +func _ready(): + world.updated.connect(update_chunk_shader_parameters) + func _draw(): - var camera_chunk = world.tile_pos_to_chunk_pos(Vector2i(camera.position / TileGlobals.tile_size / 2)) + var camera_chunk : Vector2i = world.tile_pos_to_chunk_pos(world.global_position_to_tile(camera.position)) var camera_size : Vector2 = camera.get_camera_rect().size / TileGlobals.chunk_size / TileGlobals.tile_size / 2 - var adjusted_size : Vector2i = Vector2i(ceil(camera_size.x) + 2, ceil(camera_size.y) + 2) - var generation_radius = maxi(adjusted_size.x, adjusted_size.y) + var adjusted_size : Vector2i = Vector2i(ceil(camera_size.x), ceil(camera_size.y)) - for y in range(camera_chunk.y - generation_radius, camera_chunk.y + generation_radius): - for x in range(camera_chunk.x - generation_radius, camera_chunk.x + generation_radius): + for y in range(-adjusted_size.y, adjusted_size.y+1): + for x in range(-adjusted_size.x, adjusted_size.x+1): draw_chunk(world.get_chunk_at(camera_chunk + Vector2i(x,y))) func draw_chunk(chunk : Chunk) -> void: - var x : int = 0 - var y : int = 0 var offset : Vector2 = chunk.position * TileGlobals.chunk_size * TileGlobals.tile_size if not chunk_textures.has(chunk): - var new_sprite2d : Sprite2D = Sprite2D.new() - new_sprite2d.texture = preload("res://resources/items/textures/blank_tile.png") - new_sprite2d.position = offset - new_sprite2d.scale = Vector2( + var chunk_sprite : Sprite2D = Sprite2D.new() + chunk_sprite.texture = preload("res://resources/items/textures/blank_tile.png") + chunk_sprite.position = offset + chunk_sprite.centered = false + chunk_sprite.scale = Vector2( TileGlobals.chunk_size, TileGlobals.chunk_size ) + + chunk_sprite.texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED + + chunk_textures[chunk] = chunk_sprite var new_shader_material : ShaderMaterial = ShaderMaterial.new() new_shader_material.shader = chunk_shader - new_sprite2d.material = new_shader_material + chunk_sprite.material = new_shader_material + add_child(chunk_sprite) - new_sprite2d.material.set_shader_parameter("tile_size", TileGlobals.tile_size) - new_sprite2d.material.set_shader_parameter("tile_count", len(TileGlobals.tile_definitions)) - new_sprite2d.material.set_shader_parameter("tile_texture", TileGlobals.tile_atlas) - - var item_array : Array[int] - - for iy in range(TileGlobals.chunk_size): - for ix in range(TileGlobals.chunk_size): - item_array.append(0) - - for item_pos in chunk.items.keys(): - item_array[item_pos.y*TileGlobals.chunk_size+item_pos.x] = chunk.items[item_pos].id - - new_sprite2d.material.set_shader_parameter("item_texture", ItemGlobals.item_atlas) + update_chunk_shader_parameters(chunk) - new_sprite2d.material.set_shader_parameter("tiles", chunk.tiles) - new_sprite2d.material.set_shader_parameter("items", item_array) - - new_sprite2d.texture_repeat = CanvasItem.TEXTURE_REPEAT_ENABLED - - chunk_textures[chunk] = new_sprite2d - add_child(new_sprite2d) +func update_chunk_shader_parameters(chunk : Chunk): + draw_chunk(chunk) + var chunk_sprite : Sprite2D = chunk_textures[chunk] + chunk_sprite.material.set_shader_parameter("tile_size", TileGlobals.tile_size) + chunk_sprite.material.set_shader_parameter("tile_count", len(TileGlobals.tile_definitions)) + chunk_sprite.material.set_shader_parameter("tile_texture", TileGlobals.tile_atlas) + var item_array : Array[int] + for iy in range(TileGlobals.chunk_size): + for ix in range(TileGlobals.chunk_size): + item_array.append(-1) + + for item_pos in chunk.items.keys(): + item_array[item_pos.y*TileGlobals.chunk_size+item_pos.x] = chunk.items[item_pos].id + + var arrow_array : Array[int] + + for iy in range(TileGlobals.chunk_size): + for ix in range(TileGlobals.chunk_size): + arrow_array.append(-1) + + for arrow_pos in chunk.arrows.keys(): + var arrow_direction = chunk.arrows[arrow_pos].direction + var int_direction = 0 + + match arrow_direction: + Vector2i(1, 0): + int_direction = 0 + Vector2i(0, 1): + int_direction = 1 + Vector2i(-1, 0): + int_direction = 2 + Vector2i(0, -1): + int_direction = 3 + + arrow_array[arrow_pos.y*TileGlobals.chunk_size+arrow_pos.x] = int_direction + + chunk_sprite.material.set_shader_parameter("item_texture", ItemGlobals.item_atlas) + chunk_sprite.material.set_shader_parameter("arrow_texture", preload("res://resources/misc/arrows.png")) + + chunk_sprite.material.set_shader_parameter("tiles", chunk.tiles) + chunk_sprite.material.set_shader_parameter("items", item_array) + chunk_sprite.material.set_shader_parameter("arrows", arrow_array) func _process(delta: float) -> void: diff --git a/logic/world/chunk/tile/tile_globals.gd b/logic/world/chunk/tile/tile_globals.gd index 0a21e65..cdcac8a 100644 --- a/logic/world/chunk/tile/tile_globals.gd +++ b/logic/world/chunk/tile/tile_globals.gd @@ -1,6 +1,11 @@ extends Node var tile_definitions : Array[TileDefinition] + +enum {WATER, GRASS, STONE, TREE} + +const resource_tiles : Dictionary[int, int] = {TREE : ItemGlobals.WOOD} + var tile_atlas : CompressedTexture2DArray var chunk_gradient : Gradient diff --git a/logic/world/world.gd b/logic/world/world.gd index 0b518ad..89ce8a9 100644 --- a/logic/world/world.gd +++ b/logic/world/world.gd @@ -4,6 +4,11 @@ class_name World var chunks : Dictionary[Vector2i, Chunk] +var tps = 1 +var update_timer = 0 + +signal updated(chunk : Chunk) + func get_chunk_at(position : Vector2i) -> Chunk: if chunks.has(position): return chunks[position] @@ -13,8 +18,35 @@ func get_chunk_at(position : Vector2i) -> Chunk: return new_chunk -func tile_pos_to_chunk_pos(position : Vector2i): - return position / TileGlobals.chunk_size +func tile_pos_to_chunk_pos(position : Vector2i) -> Vector2i: + return floor(Vector2(position) / TileGlobals.chunk_size) func _ready() -> void: pass + +func set_tile(position : Vector2i, tile_id : int): + var chunk_position : Vector2i = tile_pos_to_chunk_pos(position) + var position_in_chunk = position - chunk_position * TileGlobals.chunk_size + var chunk : Chunk = get_chunk_at(chunk_position) + + chunk.set_tile(position_in_chunk, tile_id) + updated.emit(chunk) + +func add_item(position : Vector2i, item : Item): + var chunk_position : Vector2i = tile_pos_to_chunk_pos(position) + var position_in_chunk = position - chunk_position * TileGlobals.chunk_size + var chunk : Chunk = get_chunk_at(chunk_position) + +func global_position_to_tile(position : Vector2) -> Vector2i: + return Vector2i(floor(position/TileGlobals.tile_size)) + +func update_chunks(): + for chunk in chunks.values(): + if chunk.update(): + updated.emit(chunk) + +func _process(delta): + update_timer -= delta + if update_timer <= 0: + update_timer = 1/tps + update_chunks() diff --git a/project.godot b/project.godot index 4c15d01..3da3de5 100644 --- a/project.godot +++ b/project.godot @@ -21,6 +21,44 @@ Globals="*res://globals.gd" TileGlobals="*res://logic/world/chunk/tile/tile_globals.gd" ItemGlobals="*res://logic/mechanics/item/item_globals.gd" +[input] + +camera_left={ +"deadzone": 0.2, +"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":65,"key_label":0,"unicode":97,"location":0,"echo":false,"script":null) +, 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":4194319,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +camera_right={ +"deadzone": 0.2, +"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":4194321,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +, 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":68,"key_label":0,"unicode":100,"location":0,"echo":false,"script":null) +] +} +camera_up={ +"deadzone": 0.2, +"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":87,"key_label":0,"unicode":119,"location":0,"echo":false,"script":null) +, 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":4194320,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +camera_down={ +"deadzone": 0.2, +"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":83,"key_label":0,"unicode":115,"location":0,"echo":false,"script":null) +, 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":4194322,"key_label":0,"unicode":0,"location":0,"echo":false,"script":null) +] +} +rotate_left={ +"deadzone": 0.2, +"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":81,"key_label":0,"unicode":113,"location":0,"echo":false,"script":null) +] +} +rotate_right={ +"deadzone": 0.2, +"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":69,"key_label":0,"unicode":101,"location":0,"echo":false,"script":null) +, 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,"location":0,"echo":false,"script":null) +] +} + [rendering] textures/canvas_textures/default_texture_filter=3 diff --git a/resources/items/textures/item_atlas.png b/resources/items/textures/item_atlas.png index a47fe340db883c3c3639738435b1d2b8ebf8389c..951d45ffa06210ecc692cd425c8cd833adbda23f 100644 GIT binary patch literal 555 zcmV+`0@VG9P)z@;j|==^1poj5AY({UO#lFTCIA3{ga82g0001h=l}q9FaQARU;qF* zm;eA5aGbhPJOBUy24YJ`L;(K){{a7>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007 zbV*G`2k8k96%hfJ-{8;y00D1FL_t(Y$JJG_O2j}AeS2Kv7hGpyohE4{&2<5r0}HE^ z3SugeYw`(cL@XqJfTR{|gn)$>L4>SD3bC-TOJ^gNYc-3b6#&SRB?v%#62^K0=N1g3nmoW}|PJ}kLldkX+?cG=+MD8}va zuJR?3W`&}4Rp!E~009BO&E|$auz3H{>m;0MBHiPgmkMcCsKfm|0Kn7p3uN03hzt}U znG*oD><778_Bux-e5&T)01!q2WZNOl3RRW4n3^xzfN9T3_<)B|pn)k!0c#JK;48{7 zQm6NgaDj(WU?nEo4ufY|p(eC;U1*XSQ-C+ykKnE`&PKO>XOIt2brd;^A`)KDt>kdOcX002ovPDHLkV1mMv-30&u literal 468 zcmV;_0W1EAP)Px$j!8s8R7i>CmLX5WKp2Lf5)8j!4uP)e44Ii*f?0w{Qa z-Q%qT0t#@ozNYK_*AKn!MJ;WlxPPhDg*Zvo{_YL{506jeSpm$Ac(J&CGJS!GPx$(Md!>R9JyQ|Y$ zd4+aDu(T2z8yi!Exr}?eGqdOYU}4=4Wd8GY+rZcU1^{Wc!f7%E&56@wTH2#I0F2Kw z9Jg0Izdj*^wEuE=58kuT&X<+%&PNwCNPrNo!7k(TthA;H!m$W&*#8vsPOp2n*Up!i zk1klOTc-ab=uV;?l#CC-jX!R$r8!@-(CKxHQ3qVGCZK!ShkGaFb-qS(-?_oCUs}sI zJN3*yUt+OtnWA7mx&Xl4xkmc&dE>P1^xwX{d)73lvj#{ag!U5G*qBI=&W6&! z_Z#@ja~f5lNN|yaQEPw&EvMZ`@I^*ldG3m!rA9NfA+3zm8yVXX;(AVAf+ zAbFdMAqf*>tb|2`1i1IMk1DMYD5r+6BUs@z;*mPx(gdm*XlaA7MoPrg2JU$+3cN*7 ziwNLfH1cxDSnG$-VAwClBe(`rJ@9o007%koRWewM2!3Akvh_nK-|UJ}H#{0#5+FVW zs4Ms)MQVw$pTGo<4k<#Ua1V)~K87^tF;unv@h?HQxLNZ4k=Gy~w82Px$WJyFpR7i=nm9cIDF${+PL#IB#O&u5z65Dlv6$y1mV&FY^5FVi~!N%M-Xa~BT zgl=R)%q-W*S6|{dPN1I@$rmTmZ(nQ|_-Hx+sE!9**ISTHT-RIAM>YVgZaZ8~cf7v6 zAcW>0x9`Dw777X=ge%x(b=!G+v4A+10NUo<+mqRJ;2Xs*YvMz2@t4!xv-zHd$!yv$ zmlB9)S;D;&$~xa8TRJyi)ZX6r*H83JQEm1e7m^Z8bv&S6eu_TpGy3-$h#}R0iyI98 zrU0~eu2Gs#CJ1zKebU(!(VSoaS}WBAYT348sRzRJgf#J%Cq(dI$bPg2MkG)pr