class_name became an issue when I followed what kraasch suggested.
I am essentially trying to have some baking game where you put ingredients in a mixing bowl attached to a mixer.
Red scene is an ingredient and purple is the mixing bowl. Blue cylinder is the mixer.
When I pick up and attach the red scene to the blue cylinder it shows up on the purple mixing bowl:
This is the behavior I want, but I noticed that if I have a second purple mixing bowl that is not attached to the blue cylinder, it ALSO receives the action to add the red scene:
(The second one was way far back and I don’t think it is possible to have been touched by my raycast detector.)
I will post my code below but to get this working I essentially was looking to use signals to tell the purple scene to show the red scene when an interaction happened, and delete the red scene in the level.
player.gd:
extends CharacterBody3D
@onready var player: CharacterBody3D = $"."
@onready var level: Node3D = $".."
@onready var mesh_instance_3d: MeshInstance3D = $MeshInstance3D
@onready var item_detector: RayCast3D = $MeshInstance3D/ItemDetector
@onready var socket: Marker3D = $MeshInstance3D/Socket
@onready var equipment_detector: RayCast3D = $MeshInstance3D/EquipmentDetector
const MIXING_BOWL = preload("uid://cdox80irdgpab")
#Rotating Character
var newdir := Transform3D()
var orientation := Transform3D()
var motion := Vector2()
#Item
var detected_item
var attached_item
var groups_detected_item: Array
var isAttached: bool = false
var current_ingredients_in_mixing_bowl: Array
#Equipment
var detected_equipment
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
const PLAYER_ROTATION_SPEED = 10
func _ready() -> void:
#sets orientation equal to the global transform which contains position rotation scale and origin
orientation = mesh_instance_3d.global_transform
#sets orientation origin to a Vector 3
orientation.origin = Vector3()
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
#if (attached_item):
#attached_item.position = socket.position
var input_dir := Input.get_vector("left", "right", "forward", "backward")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
velocity.x = direction.x * SPEED
velocity.z = direction.z * SPEED
#putting direction in its own variable
var target := direction
# using Quaternion, get the rotation quaternion of the origin, which is of type basis
var q_from: Quaternion = orientation.basis.get_rotation_quaternion()
#this establishes a quaternion that gets the target rotation quaternion. This is done by taking the Basis - which is only position, rotation, and scale
#and using looking_at (target) which creates a vector looking at the target, and then gets the rotation quaternion of that.
var q_to: Quaternion = Basis.looking_at(target).get_rotation_quaternion()
#uses slerp (spherical linear interpolation). orientation.basis is becoming the q_to from q_from and slerped from there.
orientation.basis = Basis(q_from.slerp(q_to, delta * PLAYER_ROTATION_SPEED))
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
#Rotate Character. This is the code that actually rotates the character
orientation.origin = Vector3() # Clear accumulated root motion displacement (was applied to speed).
orientation = orientation.orthonormalized() # Orthonormalize orientation.
mesh_instance_3d.global_transform.basis = orientation.basis #this rotates the character.
func _input(event: InputEvent) -> void:
if event.is_action_pressed("Interact"):
if item_detector.is_colliding() and isAttached == false:
detect_item_type_and_attach()
elif equipment_detector.is_colliding() and isAttached == false:
pickup_item_from_equipment()
elif isAttached == true:
if equipment_detector.is_colliding() == true:
if groups_detected_item.has("MixingBowl"):
attach_mixing_bowl_to_mixer()
if !groups_detected_item.has("MixingBowl"):
if ItemManager.is_mixing_bowl_attached == true:
add_item_to_mixing_bowl()
else:
drop_item()
if event.is_action_pressed("RunEquipment"):
print("RunEquipment pressed")
if equipment_detector.is_colliding() == true:
detected_equipment = equipment_detector.get_collider()
var groups_detected_equipment = detected_equipment.get_groups()
if groups_detected_equipment.has("Mixer") and ItemManager.mixing_bowl_full == true:
print("run: ", detected_equipment)
SignalManager.on_start_mixer.emit()
if groups_detected_equipment.has("Mixer") and ItemManager.mixing_bowl_full == false:
print("Mixing bowl isnt full")
func _process(_delta: float) -> void:
pass
func attach_item_to_socket(item) -> void:
#SignalManager.on_pickup_item.emit(item)
item.reparent(socket)
#detected_item.add_child(socket)
#
item.freeze = true
#
item.global_transform = socket.global_transform
isAttached = true
return
func pickup_item_from_equipment() -> void:
detected_equipment = equipment_detector.get_collider()
if ItemManager.is_mixing_bowl_attached == true:
pick_up_mixing_bowl()
func detect_item_type_and_attach() -> void:
#print("Item detector collided and no item attached")
detected_item = item_detector.get_collider()
groups_detected_item = detected_item.get_groups()
#print(detected_item.get_groups())
if groups_detected_item.has("Item"):
attach_item_to_socket(detected_item)
func attach_mixing_bowl_to_mixer() -> void:
detected_equipment = equipment_detector.get_collider()
detected_item.global_transform = detected_equipment.equip_socket.global_transform
#Signal sent to main_level.gd
SignalManager.on_add_mix_bowl_to_mixer.emit(detected_equipment)
if ItemManager.mixing_bowl_information:
SignalManager.on_set_ingredients.emit(ItemManager.mixing_bowl_information)
detected_item.queue_free()
isAttached = false
func drop_item() -> void:
# I had to declare this variable because it wasn't getting the groups FAST enough before signal
var array_of_groups: Array = detected_item.get_groups()
SignalManager.on_dropped_object.emit(array_of_groups)
if groups_detected_item.has("MixingBowl"):
SignalManager.on_mixing_bowl_dropped.emit(current_ingredients_in_mixing_bowl)
detected_item.queue_free()
isAttached = false
func pick_up_mixing_bowl() -> void:
#ItemManager.mixing_bowl_information
var spawn_mixing_bowl = MIXING_BOWL.instantiate()
socket.add_child(spawn_mixing_bowl)
spawn_mixing_bowl.freeze = true
isAttached = true
detected_item = spawn_mixing_bowl
SignalManager.on_delete_mixing_bowl.emit()
if ItemManager.is_donut_dough_made == true:
SignalManager.on_donut_dough_made.emit()
else:
current_ingredients_in_mixing_bowl = ItemManager.mixing_bowl_information
groups_detected_item = spawn_mixing_bowl.get_groups()
print(current_ingredients_in_mixing_bowl)
SignalManager.on_set_ingredients.emit(current_ingredients_in_mixing_bowl)
func add_item_to_mixing_bowl() -> void:
var array_of_groups: Array = detected_item.get_groups()
SignalManager.on_item_equipment_interaction.emit(array_of_groups)
print(array_of_groups)
detected_item.queue_free()
isAttached = false
ItemManager.gd
extends Node
var mixing_bowl_information: Array
var mixing_bowl_full: bool = false
var is_mixing_bowl_attached: bool = false
var is_donut_dough_made: bool = false
func _ready() -> void:
SignalManager.transmit_list_of_ingredients.connect(_transmit_list_of_ingredients)
func _transmit_list_of_ingredients(list_of_ingredients) -> void:
mixing_bowl_information = list_of_ingredients
print(mixing_bowl_information)
print("Updated ingredients in mixing bowl")
if is_donut_dough_made == true:
print("donut dough made")
elif mixing_bowl_information == [true, true, true, true]:
mixing_bowl_full = true
func _process(delta: float) -> void:
#print(mixing_bowl_information)
pass
MainLevel.gd
extends Node3D
const ITEM = preload("uid://b4nkr60ehsdpk")
const PLAYER = preload("uid://8bx1an1edxv7")
const MAIN_LEVEL = preload("uid://bgatqathefj53")
const SUGAR = preload("uid://dasong7gubw4g")
const FLOUR = preload("uid://dxsbdv0ej3ybj")
const MIXING_BOWL = preload("uid://cdox80irdgpab")
const EGGS = preload("uid://bixgrycn7ga3t")
const YEAST = preload("uid://be7yidn8307s4")
var mixing_bowl_items: Array
#I don't think this is needed anymore but im going to leave it here in case I need it
var PickUpItems = {
"Item" : ITEM,
"Sugar" : SUGAR ,
"Flour" : FLOUR,
"MixingBowl" : MIXING_BOWL,
"Eggs" : EGGS,
"Yeast" : YEAST
}
@onready var level: Node3D = $"."
@onready var player: CharacterBody3D = $Player
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
SignalManager.on_dropped_object.connect(_on_dropped_object)
SignalManager.on_pickup_item.connect(_on_pickup_item)
SignalManager.on_mixing_bowl_dropped.connect(_on_mixing_bowl_dropped)
func _on_dropped_object(Items) -> void:
print(Items[1])
if Items[1] == "MixingBowl":
spawn_object(Items[1])
if ItemManager.is_donut_dough_made == false:
SignalManager.on_set_ingredients.emit(ItemManager.mixing_bowl_information)
if ItemManager.is_donut_dough_made == true:
SignalManager.on_donut_dough_made.emit()
else:
spawn_object(Items[1])
func spawn_object(ItemName) -> void:
var item_to_dict = PickUpItems[ItemName]
var spawnobject = item_to_dict.instantiate()
spawnobject.global_transform = player.socket.global_transform
level.add_child(spawnobject)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
pass
func _on_pickup_item(detected_item) -> void:
detected_item.global_transform = player.socket.global_transform
func _on_mixing_bowl_dropped(items_in_bowl) -> void:
if ItemManager.is_donut_dough_made == true:
SignalManager.on_donut_dough_made.emit()
if ItemManager.is_donut_dough_made == false:
ItemManager.mixing_bowl_information = items_in_bowl
mixing_bowl.gd
extends "res://Scripts/item.gd"
@onready var flour: MeshInstance3D = $flour
@onready var sugar: MeshInstance3D = $sugar
@onready var eggs: MeshInstance3D = $eggs
@onready var yeast: MeshInstance3D = $yeast
@onready var donutdough: MeshInstance3D = $donutdough
var has_flour: bool = false
var has_sugar: bool = false
var has_eggs: bool = false
var has_yeast: bool = false
var ingredients: Array = [has_flour,has_sugar, has_yeast, has_eggs]
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
flour.hide()
sugar.hide()
eggs.hide()
yeast.hide()
donutdough.hide()
SignalManager.on_item_equipment_interaction.connect(_on_item_equipment_interaction)
SignalManager.on_set_ingredients.connect(show_ingredients)
SignalManager.on_donut_dough_made.connect(_on_donut_dough_made)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
pass
func _on_item_equipment_interaction(item_to_attach) -> void:
print("Item to attach: ", item_to_attach)
for group in item_to_attach:
match group:
"Flour":
flour.show()
has_flour = true
"Sugar":
sugar.show()
has_sugar = true
"Yeast":
yeast.show()
has_yeast = true
"Eggs":
eggs.show()
has_eggs = true
ingredients = [has_flour, has_sugar, has_yeast, has_eggs]
SignalManager.transmit_list_of_ingredients.emit(ingredients)
print("ingredients updated: ", ingredients)
func show_ingredients(items) -> void:
print("items: ", items)
# there is probably a better way to do this but i dont know how else to do this right now
if (items):
if items[0] == true:
flour.show()
has_flour = true
if items[1] == true:
sugar.show()
has_sugar = true
if items[2] == true:
yeast.show()
has_yeast = true
if items[3] == true:
eggs.show()
has_eggs = true
if items == [false, false, false, false]:
flour.hide()
has_flour = false
sugar.hide()
has_sugar = false
yeast.hide()
has_yeast = false
eggs.hide()
has_eggs = false
print("mixingbowl.gd: Items: ", items)
ItemManager.mixing_bowl_information = items
func _on_donut_dough_made() -> void:
print("donut dough made")
donutdough.show()
ItemManager.is_donut_dough_made = true
mixer.gd
extends "res://Scripts/equipment.gd"
@onready var mixer_run_time: Timer = $MixerRunTime
@onready var equip_socket: Marker3D = $Equip_Socket
@onready var spindle: MeshInstance3D = $Spindle
const MIXING_BOWL = preload("uid://cdox80irdgpab")
var mixing_bowl
var detected_item
var mixbowl
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
SignalManager.on_add_mix_bowl_to_mixer.connect(_on_add_mix_bowl_to_mixer)
SignalManager.on_delete_mixing_bowl.connect(_on_delete_mixing_bowl)
SignalManager.on_start_mixer.connect(_on_start_mixer)
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(_delta: float) -> void:
pass
func _on_delete_mixing_bowl() -> void:
if ItemManager.is_mixing_bowl_attached == true:
if ItemManager.is_donut_dough_made == false:
SignalManager.transmit_list_of_ingredients.emit(mixbowl.ingredients)
ItemManager.is_mixing_bowl_attached = false
if ItemManager.is_donut_dough_made == true:
SignalManager.on_donut_dough_made.emit()
mixbowl.queue_free()
else:
pass
func _on_add_mix_bowl_to_mixer(equipment) -> void:
var spawn_mixing_bowl = MIXING_BOWL
#level.add_child(spawn_mixing_bowl)
print(spawn_mixing_bowl)
mixbowl = spawn_mixing_bowl.instantiate()
self.add_child(mixbowl)
mixbowl.global_transform = equipment.equip_socket.global_transform
mixbowl.freeze = true
ItemManager.is_mixing_bowl_attached = true
if ItemManager.is_donut_dough_made == false:
mixbowl.ingredients = ItemManager.mixing_bowl_information
if ItemManager.is_donut_dough_made == true:
SignalManager.on_donut_dough_made.emit()
func _on_start_mixer() -> void:
mixer_run_time.start()
print("Mixer started")
spindle.rotate(Vector3(100,100,10).normalized(), 90)
func _on_mixer_run_time_timeout() -> void:
print("Mixer FINISHED") # Replace with function body.
spindle.rotate(Vector3(1000,100,100).normalized(), 90)
ItemManager.mixing_bowl_information = [false, false, false, false]
ItemManager.mixing_bowl_full = false
SignalManager.on_set_ingredients.emit(ItemManager.mixing_bowl_information)
SignalManager.on_donut_dough_made.emit()