Player movement script: Invalid assignment of property or key 'flip_h' with value of type 'bool' on a base object of type 'Nil'

Godot Version

4.3

Question

It is not completely clear to me where is the bug…
I defined his script:

extends CharacterBody2D

class_name PlayerController
@export var player_controller: PlayerController
...
...
func _physics_process(delta: float) -> void:
	direction = Input.get_axis("go_left","go_right")
	## manage direction

	if direction == 1 :
		player_controller.sprite.flip_h=false
	elif direction ==-1:
		player_controller.sprite.flip_h= true

to player_controller I set a PlayerController istance which has:
Sprite2d
CollisionShape2D

I am in trouble…

player_controller.sprite is invalid, because you’re asking the code to take the player_controller variable, and inside of it, get the sprite variable, which does not exist.

To access your sprite node, you can export it, like this: @export var sprite: Sprite2D, and you should then be able to access it with the same code that’s currently not working.

Also, in your PlayerController script, you have a reference to a PlayerController. Is it intended?

1 Like

I am not sure but it does not seem right to assign a variable to a class name from within that class name’s definition. It seems very circular to me.

Also I think flip_h is only a method of things like sprite2d and texture rects and a few others. So ChatacterBody2D would not have that method anyway.

Would like to see what other people think about this.

Edit:
@sixrobin we crossed. But I think you are saying that this is circular too?

2 Likes

Hi, mmm just to avoid circular definition error I removed out from the script the player_controller definition:

extends CharacterBody2D

class_name PlayerController
@export var sprite: Sprite2D
##removed line @export var player_controller: PlayerController

the problem after that arise on the sprite var because It is null; I didn’t set any value for it just because I previously defined an AnimationTree. It is not clear too me what should I do…

Here’s a more precise explanation:

1/ You have a class called PlayerController, that extends CharacterBody2D. This class doesn’t do anything visual, it’s purely made for movement (since that’s what CharacterBody2D is made for).
Something like this:

extends CharacterBody2D
class_name PlayerController

func _physics_process(delta: float) -> void:
    direction = Input.get_axis("go_left", "go_right")

2/ You want to display a sprite for your player, so in your tree, you added a node of type Sprite2D, and you defined a texture to use.
Something like this, I guess:

3/ When moving, based on the direction, you want to flip the sprite. To do so, you first need a reference to it, by exporting the variable:

extends CharacterBody2D
class_name PlayerController

@export var sprite: Sprite2D

func _physics_process(delta: float) -> void:
    direction = Input.get_axis("go_left", "go_right")

and then assigning the node inside the Inspector.

4/ Now that you have a reference to your sprite, you can access it and change its flip_h value.

extends CharacterBody2D
class_name PlayerController

@export var sprite: Sprite2D

func _physics_process(delta: float) -> void:
    direction = Input.get_axis("go_left", "go_right")

    if direction == 1:
        sprite.flip_h = false
    elif direction == -1:
        sprite.flip_h = true

And that should do the job.
I think you got a bit lost with how scripts work, but basically you just extend the type of your node (here, CharacterBody2D), and then you export the other nodes you want to change along the way.

What we were concerned about is that you exported a PlayerController type, while already being inside the PlayerController script (which is valid from a pure code perspective, but does not make sense in your case).

Let me know if that helps. :slight_smile:

1 Like

hi, surely you helped me to better understinding the whole; i am not sure about is that I don’t use a Sprite2D, instead I use an AnimationTree because I defined some animations too, like :walking, idle and jump.
What i am not sure about is on what I should call sprite.flip_h ??as I dont use anymore: @export var sprite: Sprite2D ??hopefully I explained well my doubt

I’m not familiar with AnimationTree to be honest, but depending on what your scene looks like, you could do the flipping code a different way. I believe we can figure something out easily.
Could you share a screenshot of your scene?

.so, this is the code I wrote in my player_ctrl.tscn:

extends CharacterBody2D

class_name PlayerController

const SPEED = 150.0
@export var HP =100.0
@export var JUMP_VELOCITY = -800.0
@export var jump_mult = 0.90
@export var falling_mult = 0.90
@export var gravity = 72
@export var falling_mul = 30

## @export var sprite: Sprite2D
var is_jumping = false
var speed_mult = 30.0
var gravity_sys = ProjectSettings.get_setting("physics/2d/default_gravity")
var direction = 0
@export var electrified= false
var attacking = false

func damage(type: String):
	print('Damage caused by '+type)
	match type:
		"electricity":
			electrified=true
	
func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity_sys*delta
		'''
		print('mi trovo altezza di: '+str(velocity.y))
		#print('gravuty Nit in floor: '+str(gravity_sys*delta))
		if velocity.y < 0:
			velocity.y += (gravity_sys)*falling_mult #(gravity_sys*delta*0.6) 
		if velocity.y > 700:
			velocity.y=200
		'''
	if Input.is_action_pressed("Jump") and is_on_floor() :
		if(Glob.electricBlock == false):
			velocity.y =jump_mult*JUMP_VELOCITY
				
	direction = Input.get_axis("go_left","go_right")
	if Glob.electricBlock == false:
		if  direction:
			velocity.x =direction*SPEED
		else:
			velocity.x = move_toward(velocity.x,0, SPEED)
	else:
		velocity.x = 0.0 #move_toward(velocity.x,0, 0)
		
	## manage direction

	if direction == 1 and Glob.electricBlock == false:
		sprite.flip_h=false
	elif direction ==-1 and Glob.electricBlock == false:
		sprite.flip_h= true
			
		
	move_and_slide()

is it what do you intended??

Yes, but I don’t see any reference in your script to anything visual (either Sprite or Animation or some sort).
The idea is just that you need to access your visual node, and flip or scale it based on direction. With Sprite2D, it can be done with flip_h, with any Node2D, it can be done with scale.x, etc. The code is different but you just need to replace the lines here where you use a sprite.

hi, i have just reviewed the code but I didnt find the cause of the problem; within the script I write:

extends CharacterBody2D

class_name PlayerController

@onready var animation_tree:AnimationTree =$"../AnimationTree"
@onready var sprite__J: Sprite2D = $"../AnimationPlayer.texture"

direction = Input.get_axis("go_left","go_right")

if direction == 1 :
		sprite__J.flip_h=false
elif direction ==-1:
		sprite__J.flip_h= true

When I run for testing purpose I get thie error message…

Invalid assignment of property or key 'flip_h' with value of type 'bool' on a base object of type 'null instance'.

I dont. know how to fix it…

$"../AnimationPlayer.texture" is not a valid node path, and you can’t get a .texture from an AnimationPlayer and if you did it wouldn’t be a Sprite2D type, it would be a Texture2D.

ok, I understood.
I updated the code, but as obviously, i am getting the problem about the definion of Sprite2D var which is null;
I try to be more precise showing the code:

@export var player_controller: PlayerController

var spritePl: Sprite2D

if player_controller.direction == 1:
      spritePl.flip_h = false
elif player_controller.direction == -1:
      spritePl.flip_h = true

I am receiving the following message:
Invalid assignment of property or key ‘flip_h’ with value of type ‘bool’ on a base object of type ‘Nil’.
And it is obvious as I didn’t set any value for the spritePl variable; my doubt is what sprite should I indicate considering I have an AnimationTree with some animations defined?? :open_mouth:

You haven’t shown your scene tree so we don’t know where or what the sprite’s parent is. Sharing a screenshot of your scene tree with where this script is attached and the sprite 2d you want to flip would be very helpful.

The sprite should be a direct child of the player, where $Sprite2D would work.

i am going to show screenshots about my godot solution.

Main scene tree:

Player scene tree:

and which node is your script attached to? Which sprite2d node are you trying to get?

so, the script attached to Player node is:

extends CharacterBody2D

class_name PlayerController

const SPEED = 150.0
@onready var animation_tree:AnimationTree =$"../AnimationTree"
@onready var sprite__J: Sprite2D = $Sprite2D

@export var HP =100.0
@export var JUMP_VELOCITY = -800.0
@export var jump_mult = 0.90
@export var falling_mult = 0.90
@export var gravity = 72
@export var falling_mul = 30

@export var sprite: Sprite2D

@export var electrified= false

var is_jumping = false
var speed_mult = 30.0
var gravity_sys = ProjectSettings.get_setting("physics/2d/default_gravity")
var direction = 0
var attacking = false


		
func damage(type: String):
	print('Damage caused by '+type)
	match type:
		"electricity":
			print('AAA')
			electrified=true
	
func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity.y += gravity_sys*delta
		
	if Input.is_action_pressed("Jump") and is_on_floor() :
		if(Glob.electricBlock == false):
			velocity.y =jump_mult*JUMP_VELOCITY
					
	direction = Input.get_axis("go_left","go_right")
	if  direction:
		velocity.x =direction*SPEED
	else:
		velocity.x = move_toward(velocity.x,0, SPEED)
	
		
	## manage direction

	if direction == 1 and Glob.electricBlock == false:
		sprite__J.flip_h=false
	elif direction ==-1 and Glob.electricBlock == false:
		sprite__J.flip_h= true
		
	
	move_and_slide()

I believe the Sprite2d node I should aim to is the one I assigned to the @export var sprite.

Then sprite__J should work with path $Sprite2D, your animation_tree has a incorrect path with $"../AnimationTree".

What error do you recieve when running the game with this script? If it’s the same

Invalid assignment of property or key ‘flip_h’ with value of type ‘bool’ on a base object of type ‘Nil’

Then add print(get_path()) and post the results.

Hi,
honestly I have gone in confusion…maybe It is better I start from zero…