item bundling, viewmodel for icon things
This commit is contained in:
parent
4c56d6badc
commit
d2bbeb45dc
@ -1,13 +1,12 @@
|
|||||||
[gd_resource type="Resource" script_class="InventoryItem" load_steps=3 format=3 uid="uid://nrpcuqveh7io"]
|
[gd_resource type="Resource" script_class="InventoryItem" load_steps=3 format=3 uid="uid://nrpcuqveh7io"]
|
||||||
|
|
||||||
[ext_resource type="Texture2D" uid="uid://cb6qv3c0iojfl" path="res://icon.svg" id="1_u477x"]
|
[ext_resource type="Texture2D" uid="uid://dw3x3h3f34sy3" path="res://assets/coin_flower.png" id="1_vrj0d"]
|
||||||
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="3_fe16f"]
|
[ext_resource type="Script" path="res://src/lib/inventory_item.gd" id="3_fe16f"]
|
||||||
|
|
||||||
[resource]
|
[resource]
|
||||||
script = ExtResource("3_fe16f")
|
script = ExtResource("3_fe16f")
|
||||||
icon = ExtResource("1_u477x")
|
icon = ExtResource("1_vrj0d")
|
||||||
name = "Coin Flower"
|
name = "Coin Flower"
|
||||||
id = &"coin_flower"
|
id = &"coin_flower"
|
||||||
stackable = false
|
stackable = false
|
||||||
stack_limit = 8
|
stack_limit = 8
|
||||||
count = 0
|
|
||||||
|
@ -25,7 +25,7 @@ var _projectile_speed := 12.0
|
|||||||
var _interaction_selection: Node3D
|
var _interaction_selection: Node3D
|
||||||
|
|
||||||
var controls_disabled := false
|
var controls_disabled := false
|
||||||
var held_thing: InventoryItem
|
var held_thing := { "item_id": &"empty_hand", "count": 0 }
|
||||||
|
|
||||||
|
|
||||||
# What the others see.
|
# What the others see.
|
||||||
@ -59,7 +59,7 @@ func _physics_process(delta: float) -> void:
|
|||||||
## Process interactivity selection.
|
## Process interactivity selection.
|
||||||
if id == multiplayer.get_unique_id():
|
if id == multiplayer.get_unique_id():
|
||||||
var collider: Object = null
|
var collider: Object = null
|
||||||
if held_thing == null and _line_of_sight.is_colliding():
|
if empty_handed() and _line_of_sight.is_colliding():
|
||||||
collider = _line_of_sight.get_collider(0)
|
collider = _line_of_sight.get_collider(0)
|
||||||
if collider != _interaction_selection:
|
if collider != _interaction_selection:
|
||||||
if _interaction_selection != null:
|
if _interaction_selection != null:
|
||||||
@ -103,17 +103,22 @@ func _physics_process(delta: float) -> void:
|
|||||||
|
|
||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func hold_thing(p_item_instance_id: int) -> void:
|
func hold_thing(p_bundle: Dictionary) -> void:
|
||||||
var item = instance_from_id(p_item_instance_id) as InventoryItem
|
var item := GameState.fetch().INVENTORY_ITEM_DB[p_bundle["item_id"]] as InventoryItem
|
||||||
assert(item != null)
|
held_thing = p_bundle
|
||||||
held_thing = item
|
|
||||||
var base_node := _camera_pivot.get_node("HeldViewmodel")
|
var base_node := _camera_pivot.get_node("HeldViewmodel")
|
||||||
for child in base_node.get_children():
|
for child in base_node.get_children():
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
if item.model != null:
|
if item.model != null:
|
||||||
var model = item.model.instantiate()
|
var model = item.model.instantiate()
|
||||||
base_node.add_child(model)
|
base_node.add_child(model)
|
||||||
if id == multiplayer.get_unique_id():
|
else:
|
||||||
|
# Create a icon sprite based one instead.
|
||||||
|
var model := preload("res://src/quad_viewmodel.tscn").instantiate()
|
||||||
|
model.reflect_bundle(p_bundle)
|
||||||
|
base_node.add_child(model)
|
||||||
|
|
||||||
|
if item.model != null and id == multiplayer.get_unique_id():
|
||||||
# Disable depth test and increase render priority.
|
# Disable depth test and increase render priority.
|
||||||
# TODO: in more complex scenarios model scene might want to have its own callback for this.
|
# TODO: in more complex scenarios model scene might want to have its own callback for this.
|
||||||
for model in base_node.get_children():
|
for model in base_node.get_children():
|
||||||
@ -127,11 +132,15 @@ func hold_thing(p_item_instance_id: int) -> void:
|
|||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func throw_thing() -> void:
|
func throw_thing() -> void:
|
||||||
held_thing = null # TODO: represent 'empty hand' as a unique item ?
|
held_thing = { "item_id": &"empty_hand", "count": 0 }
|
||||||
for child in _camera_pivot.get_node("HeldViewmodel").get_children():
|
for child in _camera_pivot.get_node("HeldViewmodel").get_children():
|
||||||
child.queue_free()
|
child.queue_free()
|
||||||
|
|
||||||
|
|
||||||
|
func empty_handed() -> bool:
|
||||||
|
return held_thing["item_id"] == &"empty_hand"
|
||||||
|
|
||||||
|
|
||||||
func _unhandled_input(event: InputEvent) -> void:
|
func _unhandled_input(event: InputEvent) -> void:
|
||||||
if controls_disabled or id != multiplayer.get_unique_id():
|
if controls_disabled or id != multiplayer.get_unique_id():
|
||||||
return
|
return
|
||||||
@ -142,12 +151,12 @@ func _unhandled_input(event: InputEvent) -> void:
|
|||||||
_camera_pivot.rotation.x = clamp(_camera_pivot.rotation.x, -1.2, 1.2)
|
_camera_pivot.rotation.x = clamp(_camera_pivot.rotation.x, -1.2, 1.2)
|
||||||
return
|
return
|
||||||
|
|
||||||
if event.is_action_pressed("pick") and held_thing == null:
|
if event.is_action_pressed("pick") and empty_handed():
|
||||||
if _interaction_selection != null:
|
if _interaction_selection != null:
|
||||||
hold_thing.rpc(_interaction_selection.owner.item_component.get_instance_id())
|
|
||||||
_interaction_selection.owner.get_picked_up.rpc()
|
_interaction_selection.owner.get_picked_up.rpc()
|
||||||
|
hold_thing.rpc(_interaction_selection.owner.item_bundle)
|
||||||
|
|
||||||
if event.is_action_pressed("fire") and held_thing != null:
|
if event.is_action_pressed("fire") and not empty_handed():
|
||||||
var new_projectile: Node3D = _projectile_scene.instantiate()
|
var new_projectile: Node3D = _projectile_scene.instantiate()
|
||||||
_projectile_holder.add_child(new_projectile, true)
|
_projectile_holder.add_child(new_projectile, true)
|
||||||
_set_projectile_authority.rpc(new_projectile.get_path(), id)
|
_set_projectile_authority.rpc(new_projectile.get_path(), id)
|
||||||
|
@ -5,7 +5,7 @@ extends Node3D
|
|||||||
@export var _mesh: MeshInstance3D
|
@export var _mesh: MeshInstance3D
|
||||||
@export var _area: Area3D
|
@export var _area: Area3D
|
||||||
|
|
||||||
@export var item_component: InventoryItem
|
var item_bundle := { "item_id": &"coin_flower", "count": 1 }
|
||||||
|
|
||||||
var needs_water := true
|
var needs_water := true
|
||||||
var stage: int = 1
|
var stage: int = 1
|
||||||
@ -47,6 +47,7 @@ func water(sender_id: int) -> void:
|
|||||||
|
|
||||||
@rpc("any_peer", "call_local", "reliable")
|
@rpc("any_peer", "call_local", "reliable")
|
||||||
func get_picked_up() -> void:
|
func get_picked_up() -> void:
|
||||||
|
assert(stage == final_stage)
|
||||||
stage = 1
|
stage = 1
|
||||||
_mesh.material_override.set("shader_parameter/albedo_texture", load("res://assets/sprout%s.png" % stage))
|
_mesh.material_override.set("shader_parameter/albedo_texture", load("res://assets/sprout%s.png" % stage))
|
||||||
_area.collision_layer ^= 1 << 4
|
_area.collision_layer ^= 1 << 4
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
[gd_scene load_steps=10 format=3 uid="uid://bysgtksvovyur"]
|
[gd_scene load_steps=9 format=3 uid="uid://bysgtksvovyur"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/sprout.gd" id="1_snma1"]
|
[ext_resource type="Script" path="res://src/ingame/sprout.gd" id="1_snma1"]
|
||||||
[ext_resource type="Resource" uid="uid://nrpcuqveh7io" path="res://data/coin_flower.tres" id="2_amjnn"]
|
|
||||||
[ext_resource type="Texture2D" uid="uid://d35y5ckne72qe" path="res://assets/sprout1.png" id="2_ipgad"]
|
[ext_resource type="Texture2D" uid="uid://d35y5ckne72qe" path="res://assets/sprout1.png" id="2_ipgad"]
|
||||||
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline2.gdshader" id="2_oa2it"]
|
[ext_resource type="Shader" path="res://assets/shaders/interactivity_outline2.gdshader" id="2_oa2it"]
|
||||||
[ext_resource type="Texture2D" uid="uid://cwbl0r1e26eja" path="res://assets/drop.png" id="3_kghdv"]
|
[ext_resource type="Texture2D" uid="uid://cwbl0r1e26eja" path="res://assets/drop.png" id="3_kghdv"]
|
||||||
@ -36,7 +35,6 @@ _need_water_drop = NodePath("NeedWaterDrop")
|
|||||||
_production_timer = NodePath("ProductionTimer")
|
_production_timer = NodePath("ProductionTimer")
|
||||||
_mesh = NodePath("Mesh")
|
_mesh = NodePath("Mesh")
|
||||||
_area = NodePath("Area3D")
|
_area = NodePath("Area3D")
|
||||||
item_component = ExtResource("2_amjnn")
|
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
replication_config = SubResource("SceneReplicationConfig_rs2qp")
|
replication_config = SubResource("SceneReplicationConfig_rs2qp")
|
||||||
|
@ -8,8 +8,8 @@ extends Node3D
|
|||||||
@export var body: RigidBody3D
|
@export var body: RigidBody3D
|
||||||
## no longer exists and shouldn't be considered, but not ready to be freed yet
|
## no longer exists and shouldn't be considered, but not ready to be freed yet
|
||||||
@export var is_dead := false
|
@export var is_dead := false
|
||||||
## by convention is looked up in owner from areas
|
|
||||||
@export var item_component: InventoryItem
|
const item_bundle := { "item_id": &"water_bomb", "count": 1 }
|
||||||
|
|
||||||
var _in_splash_range := {}
|
var _in_splash_range := {}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
[gd_scene load_steps=12 format=3 uid="uid://tdsbo3e5ic86"]
|
[gd_scene load_steps=11 format=3 uid="uid://tdsbo3e5ic86"]
|
||||||
|
|
||||||
[ext_resource type="Script" path="res://src/ingame/water_bomb.gd" id="1_lk5fq"]
|
[ext_resource type="Script" path="res://src/ingame/water_bomb.gd" id="1_lk5fq"]
|
||||||
[ext_resource type="AudioStream" uid="uid://dtjpv2b74g24m" path="res://assets/sfx/splash-small.wav" id="2_0wk8g"]
|
[ext_resource type="AudioStream" uid="uid://dtjpv2b74g24m" path="res://assets/sfx/splash-small.wav" id="2_0wk8g"]
|
||||||
[ext_resource type="Resource" uid="uid://cmeif37pci2ek" path="res://data/water_bomb.tres" id="2_b3357"]
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ba2mut58elwrh" path="res://assets/water-bomb.glb" id="2_v2imr"]
|
[ext_resource type="PackedScene" uid="uid://ba2mut58elwrh" path="res://assets/water-bomb.glb" id="2_v2imr"]
|
||||||
[ext_resource type="AudioStream" uid="uid://blgrl2wl05feq" path="res://assets/sfx/splash-small-quiet.wav" id="3_hgy7l"]
|
[ext_resource type="AudioStream" uid="uid://blgrl2wl05feq" path="res://assets/sfx/splash-small-quiet.wav" id="3_hgy7l"]
|
||||||
|
|
||||||
@ -58,7 +57,6 @@ _model = NodePath("Model")
|
|||||||
_splash_particles = NodePath("SplashParticles")
|
_splash_particles = NodePath("SplashParticles")
|
||||||
_picking_area = NodePath("PickingArea")
|
_picking_area = NodePath("PickingArea")
|
||||||
body = NodePath("RigidBody3D")
|
body = NodePath("RigidBody3D")
|
||||||
item_component = ExtResource("2_b3357")
|
|
||||||
|
|
||||||
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
[node name="MultiplayerSynchronizer" type="MultiplayerSynchronizer" parent="."]
|
||||||
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
replication_config = SubResource("SceneReplicationConfig_0ebrr")
|
||||||
|
@ -1,17 +1,18 @@
|
|||||||
class_name GameState
|
class_name GameState extends Resource
|
||||||
extends Resource
|
|
||||||
|
|
||||||
|
# TODO: build dynamically?
|
||||||
const INVENTORY_ITEM_DB = {
|
const INVENTORY_ITEM_DB = {
|
||||||
&"meat": preload("res://data/meat.tres"),
|
&"meat": preload("res://data/meat.tres"),
|
||||||
&"water_bomb": preload("res://data/water_bomb.tres"),
|
&"water_bomb": preload("res://data/water_bomb.tres"),
|
||||||
&"coin_flower": preload("res://data/coin_flower.tres"),
|
&"coin_flower": preload("res://data/coin_flower.tres"),
|
||||||
}
|
}
|
||||||
|
|
||||||
# keys are multiplayer ID ints, values are PlayerData
|
## keys are multiplayer ID ints, values are PlayerData
|
||||||
@export var player_data := {}
|
@export var player_data := {}
|
||||||
# keys are InventoryItem resource IDs (from db), values are InventoryItems
|
## keys are InventoryItem resource IDs (from db),
|
||||||
|
## values are { "item": InventoryItem, "count": int }
|
||||||
@export var inventory := {}
|
@export var inventory := {}
|
||||||
@export var coins: int
|
@export var coins: int # TODO: might it make sense to have even them as items?
|
||||||
|
|
||||||
static var _instance := GameState.new()
|
static var _instance := GameState.new()
|
||||||
|
|
||||||
|
@ -8,5 +8,3 @@ extends Resource
|
|||||||
|
|
||||||
@export var stackable := false
|
@export var stackable := false
|
||||||
@export var stack_limit := 8
|
@export var stack_limit := 8
|
||||||
# TODO: should it be here? or context dependent, for different inventories
|
|
||||||
@export var count := 0
|
|
||||||
|
@ -185,32 +185,36 @@ func set_coins(value: int) -> void:
|
|||||||
GameState.fetch().coins = value
|
GameState.fetch().coins = value
|
||||||
|
|
||||||
|
|
||||||
|
## Make sure it exists and all.
|
||||||
|
func prepate_inventory_idem(item_id: StringName) -> void:
|
||||||
|
if not GameState.fetch().inventory.has(item_id):
|
||||||
|
GameState.fetch().inventory[item_id] = {
|
||||||
|
"item": GameState.INVENTORY_ITEM_DB[item_id],
|
||||||
|
"count": 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func add_inventory_item(item_id: StringName, amount: int) -> void:
|
func add_inventory_item(item_id: StringName, amount: int) -> void:
|
||||||
if not GameState.fetch().inventory.has(item_id):
|
prepate_inventory_idem(item_id)
|
||||||
GameState.fetch().inventory[item_id] = GameState.INVENTORY_ITEM_DB[item_id].duplicate()
|
GameState.fetch().inventory[item_id]["count"] += amount
|
||||||
|
|
||||||
GameState.fetch().inventory[item_id].count += amount
|
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func remove_inventory_item(item_id: StringName, amount: int) -> void:
|
func remove_inventory_item(item_id: StringName, amount: int) -> void:
|
||||||
assert(GameState.fetch().inventory.has(item_id))
|
assert(GameState.fetch().inventory.has(item_id))
|
||||||
|
|
||||||
GameState.fetch().inventory[item_id].count -= amount
|
GameState.fetch().inventory[item_id]["count"] -= amount
|
||||||
assert(GameState.fetch().inventory[item_id].count >= 0)
|
assert(GameState.fetch().inventory[item_id]["count"] >= 0)
|
||||||
|
|
||||||
if GameState.fetch().inventory[item_id].count == 0:
|
if GameState.fetch().inventory[item_id]["count"] == 0:
|
||||||
GameState.fetch().inventory.erase(item_id)
|
GameState.fetch().inventory.erase(item_id)
|
||||||
|
|
||||||
|
|
||||||
@rpc("authority", "call_local", "reliable")
|
@rpc("authority", "call_local", "reliable")
|
||||||
func set_inventory_item_count(item_id: StringName, value: int) -> void:
|
func set_inventory_item_count(item_id: StringName, value: int) -> void:
|
||||||
assert(value >= 0)
|
prepate_inventory_idem(item_id)
|
||||||
if not GameState.fetch().inventory.has(item_id):
|
GameState.fetch().inventory[item_id]["count"] = value
|
||||||
GameState.fetch().inventory[item_id] = GameState.INVENTORY_ITEM_DB[item_id].duplicate()
|
|
||||||
|
|
||||||
GameState.fetch().inventory[item_id].count = value
|
if GameState.fetch().inventory[item_id]["count"] == 0:
|
||||||
|
|
||||||
if GameState.fetch().inventory[item_id].count == 0:
|
|
||||||
GameState.fetch().inventory.erase(item_id)
|
GameState.fetch().inventory.erase(item_id)
|
||||||
|
Loading…
Reference in New Issue
Block a user