Godot Version
GODOT4
Question
Hey there! I think this may be a simple one. What do I have to do to make this work? Trying to get the sprite to flash (on damage), so turning it’s saturation all the way up for a split second, then returning it to the original. This is for the Player node’s child Sprite2D .
var _original_color = $Player/Sprite2D.modulate
func flash_color():
$Sprite2D.modulate = Color.from_hsv(_original_color.h, 0, _original_color.v)
flash_color() would trigger in the player hurt event. I’m getting the “Invalid get index ‘modulate’ (on base: ‘null instance’).” error. What can I do to fix the locations? Or maybe I’m approaching a sprite flash the wrong way?
The error message states that it is trying to find the property on a null instance - or in other words, the $Sprite2D
is null and can’t be found. I suspect that you instead want to use $Player/Sprite2D
just as in the line where you initialize the original color.
1 Like
I tried that, and now it yields this error:
Node not found: “Player/Sprite2D” (relative to “CharacterBody2D”)
I mean it was just a guess from my side what the correct path is. Please show pictures of your node tree so that we can see what the correct path is.
1 Like
Here we go! Thanks for helping
Ah then the first node path seem to be wrong. Please check if this works:
var _original_color = $Sprite2D.modulate
func flash_color():
$Sprite2D.modulate = Color.from_hsv(_original_color.h, 0, _original_color.v)
Basically the script is attached on the Player node already, so you shouldn’t reference player in the node path as that is already the relative starting point
I see! I tried implementing though and got “Invalid get index ‘modulate’ (on base: ‘null instance’).”
Hm so both paths (variable definition and in the function) are without player now?
That’s really weird, as $Sprite2D
should be correct assuming we are talking about a script attached to the Player
noder
1 Like
This script extends another script called Character, does that matter? Should I try doing this with the Character script, even if this Hero script is the one the Player is connected to?
What matters is where the script is attached to. I am currently assuming the code you posted is in a script attached to the Player (so the one that opens if you click this button). Is that correct? (doesn’t matter what it inherits from)
that’s weird then… Can you show the full script just to be sure?
class_name Hero extends Character
@export_category("Equip")
@export var _has_sword : bool
@onready var _attack_input_buffer : Timer = $HitBox/InputBuffer
@export var _dash_speed : float = 80
@export var _slide_speed : float = 80
@export var _double_jump_mult : float = .8
@export var _djump_dust : PackedScene
@export var _slide_dust : PackedScene
@export var _dash_dust : PackedScene
@export_category("Mechanics")
@export var _can_animation_cancel : bool = false #burst animation
@export var _is_bursting : bool
var _original_color = $Sprite2D.modulate
var _sword : RigidBody2D
func jump():
if _is_dead or _wants_to_attack or _is_attacking:
return
elif is_on_floor():
_spawn_dust(_jump_dust)
velocity.y = _jump_velocity
_is_dashing = false
elif not _is_hit and _double_jump > 0 and not is_on_floor() and velocity.y >= 0:
if not _is_dashing:
velocity.y = _jump_velocity * _double_jump_mult
_double_jump -= 1
_spawn_dust(_djump_dust)
func face_left():
if _is_dead || _is_attacking:
return
if not _is_dashing:
_is_facing_left = true
_player_direction = -1
_sprite.flip_h = not _sprites_face_left
_hit_box.scale.x = 1 if _sprites_face_left else -1
changed_direction.emit(_is_facing_left)
func face_right():
if _is_dead || _is_attacking:
return
if not _is_dashing or _is_attacking:
_is_facing_left = false
_player_direction = 1
_sprite.flip_h = _sprites_face_left
_hit_box.scale.x = -1 if _sprites_face_left else 1
changed_direction.emit(_is_facing_left)
func attack():
if _is_dead || _is_hit || _is_attacking:
return
_wants_to_attack = true
_attack_input_buffer.start()
await _attack_input_buffer.timeout
_wants_to_attack = false
_is_dashing = false
func can_equip_sword() -> bool:
return not _has_sword && not _is_dead
func equip_sword(sword : RigidBody2D):
_sword = sword
_has_sword = true
func flash_color():
$Sprite2D.modulate = Color.from_hsv(_original_color.h, 0, _original_color.v)
func take_damage(amount : int, direction : Vector2):
flash_color()
_is_dashing = false
_is_hit = true
_is_attacking = false
_wants_to_attack = false
_hit_points = max(_hit_points - amount,0)
health_changed.emit(float(_hit_points) / _max_hit_points)
velocity = direction * Global.ppt * _hurt_recoil
if _hit_points <= 0:
_die()
if _inv_dur != 0:
become_invincible(_inv_dur)
func dash(): #dash and ground slide
if _is_dead or _wants_to_attack or _is_attacking or _is_hit:
return
#ground slide, requires being on the ground
if is_on_floor() and not _is_dashing:
_spawn_dust(_slide_dust)
_is_dashing = true
if _is_attacking:
velocity.x = 0
else:
velocity.x = (_dash_speed)* _player_direction * Global.ppt
#air dash, requires a dash charge and not touching the ground
elif not is_on_floor() and _dash_charge > 0:
_dash_charge -= 1
_can_animation_cancel = false
_spawn_dust(_dash_dust)
_is_dashing = true
velocity.x = (_dash_speed)* _player_direction * Global.ppt
func drop_sword():
#if not _has_sword:
return
#_has_sword = false
#_sword.be_dropped(global_position)
#_sword = null
func _die():
if _has_sword:
drop_sword()
super._die()
func _on_hit_box_area_entered(area : Area2D):
if _is_dead || not _is_attacking:
return
if not is_on_floor() && area.global_position.y > global_position.y:
velocity.y = _jump_velocity / 4
super._on_hit_box_area_entered(area)
Here we go!
Ahh I think I realized what the error is now. This line is outside any function:
var _original_color = $Sprite2D.modulate
So at this point, the node tree is not ready and it can not find the child node.
Try delaying the variable initialization until the tree is ready:
@onready var _original_color = $Sprite2D.modulate
1 Like
Yes that did the trick! Experimenting now with different numbers. Thank you for all the help!
system
Closed
July 2, 2024, 10:26pm
18
This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.