Why this error message appear?: invalid get index 'game_started' (on base: 'Node') - game-engine

can you please help me, I have this script:
extends KinematicBody2D
var motion = Vector2(0, 300)
var sensitivity = 13
onready var player = get_node("../Player")
onready var enemy = get_node("../Enemy")
func _ready():
randomize()
reset_ball()
func _physics_process(delta):
if not get_parent().game_started:
return
if is_on_wall():
motion.x *= -1
if is_on_floor():
touch_someone(player)
if is_on_ceiling():
touch_someone(enemy)
move_and_slide(motion, Vector2(0, -1))
func touch_someone(node):
motion.y *= -1
motion.x = (position.x - node.position.x) * sensitivity
func reset_ball():
motion.x = rand_range(-300, 300)
nd when I run the game this error message appears
invalid get index 'game_started' (on base: 'Node').
This is the error

The error is telling you that there isn't a game_started defined in the parent node. There is a parent node, but it does not have a property game_started defined.
You probably intended it to be a property, but you forgot to define it, defined it somewhere else, or you did define it in the correct place, but instanced the node under the wrong parent. However, it is also possible you made it a method and simply forgot (). I don't know which is the case.
Regardless, in Godot, a common design pattern is to access down and signal up the scene tree. In this case, you are trying to access up the scene tree. This is problematic because the scene can't ensure where it will be instanced.
I'll give you a few approaches to solve this problem:
Check if game_started exists.
The change that will have a smaller impact on your architecture is to check if the parent node has game_started before trying to read it. Which looks something like this:
var parent = get_parent
if !"game_started" in parent or !parent.game_started:
return
However please notice that even if this gets rid of the error, it is not fixing the source of the problem. Since game_started is not defined in the parent anyway.
Furthermore, _physics_process is still getting called. There are ways to don't even have the call, which is better for performance. Will come back to that.
Let the parent access the child.
What you want to accomplish is to enable and disable _physics_process based on the value of game_started. There is a way to enable and disable _physics_process in the engine: set_physics_process.
Presumably there is some other code somewhere that sets game_started on the parent, in that moment it could call set_physics_process on the child to disable or enable _physics_process accordingly.
You may even use a property (with setget) to this effect.
For example:
var game_started:bool setget set_game_started
func set_game_started(new_value:bool) -> void:
if game_started == new_value:
return
for child in get_children():
child.set_physics_process(new_value)
game_started = new_value
With this, your script does not have to check game_started. One drawback is that the code only uses set_physics_process on the direct children. We could write a recursive version, however, we can do better!
Use pause.
As you can see in pausing games, you can use get_tree().paused to get or set if the game is paused. Which will stop _physics_process (among other methods) depending on the pause_mode.
Thus, you can have the parent update get_tree().paused...
Assuming, you also want a pause, you may follow this pattern:
var game_started:bool setget set_game_started
var game_paused:bool setget set_game_paused
func set_game_started(new_value:bool) -> void:
game_started = new_value
update_pause()
func set_game_paused(new_value:bool) -> void:
game_paused = new_value
update_pause()
func update_pause() -> void:
get_tree().paused = !game_started or game_paused
Then, for the nodes that should still work when the game is paused or not started, you can se pause_mode = PAUSE_MODE_PROCESS so they don't get _physics_process et.al. disabled. Then they can check game_started and game_paused to distinguish if the game is paused or not started.
A drawback is that this will affect nodes everywhere… If only game_started and game_paused could be available everywhere… Well, we can do that too!
Use an autoload.
Make an autoload (via project settings) of a scene with a node that has game_started et.al. So that it is available from everywhere. Then you can access it from everywhere.
You can do this combined with the paused as explained above. Which is what I would recommend.
Alternatively. Since you can access it from everywhere, you you could simply access it instead of the parent:
if !autoload_name.game_started:
return
This is the exception to the access down and signal up rule. Since the autoload is available everywhere and it does not depend on where or how the scene was instanced.
I remind you, is that paused and set_physics_process will avoid the call to _physics_process, and thus are more performant than checking this way.

Related

Struggling with a list geofenceList in Kotlin

I tracked my problem down to adding to my geofenceList.
this is a global variable
lateinit var geofenceList: MutableList<Geofence>
In onCreate I add to the list:
val latitude = -26.082586
val longitude = 27.777242
val radius = 10f
geofenceList.add(Geofence.Builder()
.setRequestId("Toets")
.setCircularRegion(latitude,longitude,radius)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setTransitionTypes(Geofence.GEOFENCE_TRANSITION_ENTER)
.build())
Every time I run the app the app closes as soon as it opens.
I tried changing it to a normal variable but I am not certain how to do it and keep it a global variable, and a List would be more useful.
I just realized what your issue is: You never initialize your list. When you follow the advice in my comment, you should find a NullPointerException and here's how to fix it:
Firstly, try to avoid lateinit if possible. The compiler actually tries to find this problem for you and by using lateinit, you basically tell the compiler to shut up - even though the mistake is still there. INstead, you need to initialize your variable like so:
var geofenceList: MutableList<Geofence> = mutableListOf()
You could make it even shorter by removing the explicit type declaration:
var geofenceList = mutableListOf<Geofence>()

How can I detect mouse input on an Area2D node in Godot (viewport and shape_idx error)?

After testing out a few other engines I've settled into Godot for my game development learning process and have really appreciated the conciseness of GDScript, the node/inheritance structure, and the way observer events are covered by signals. I've been building knowledge through various tutorials and by reading through the documentation.
Somehow I'm struggling to solve the very fundamental task of detecting a mouseclick on a sprite. (Well, on a sprite's parent node, either a Node2D or an Area2D.)
My process has been this:
Create an Area2D node (called logo) with a Sprite child and a CollisionShape2D child
Assign a texture to the Sprite node, and change the x and y extent values of the CollisionShape2D node to match the size of the Sprite's texture
Connect the _on_logo_input_event(viewport, event, shape_idx) signal to the Area2D node's script (called logo.gd)
Use the following code:
func _on_logo_input_event(viewport, event, shape_idx):
if (event is InputEventMouseButton && event.pressed):
print("Logo clicked")
When I run the game I get nothing in the output after clicking, and see these errors:
The argument 'viewport' is never used in the function '_on_logo_input_event'. If this is intended, prefix it with an underscore: '_viewport'
The argument 'shape_idx' is never used in the function '_on_logo_input_event'. If this is intended, prefix it with an underscore: '_shape_idx'
I don't know how to address the parameters in this signal's function - My Area2D node is set to Pickable, and the logo Area2D node is a direct child to the game_window Node2D in the main scene. I can't figure out what is going wrong here, whether it's some project setting I need to change or an inspector attribute I need to set. Is there a better way to feed an input signal for a mouse click into a script?
I don't want to clutter stackoverflow with such a simple question but I've tried to do my due diligence and haven't been able to find this error message on any forums. I'd appreciate any help, thanks.
If the CollisionLayer of your Area2D is not empty, and input_pickable is on, then it is capable to get input. Either by connecting the input_event signal or by overriding _input_event.
If that is not working, the likely cause is that there is some Control/UI element that is stopping mouse events. They have a property called mouse_filter, which is set to Stop by default. You will need to find which Control is intercepting the input, and set its mouse_filter to Ignore.
By the way, these:
The argument 'viewport' is never used in the function '_on_logo_input_event'. If this is intended, prefix it with an underscore: '_viewport'
The argument 'shape_idx' is never used in the function '_on_logo_input_event'. If this is intended, prefix it with an underscore: '_shape_idx'
These are warnings. They are not the source of the problem. They tell what they say on the tin: you have some parameter that you are not using, and you can prefix its name with an underscore as a way to suppress the warning.
I would also recommend checking out this video:
https://www.youtube.com/watch?v=iSpWZzL2i1o
The main modification that he makes from what you have done is make a separate click event in Project > Project Settings > Input Map that maps to a left click. He can then reference that in the _on_Area2D_input_event.
extends Node2D
var selected = false
func _ready():
pass
func _on_Area2D_input_event(viewport, event, shape_idx):
if Input.is_action_just_pressed("click"):
selected = true
func _physics_process(delta):
if selected:
global_position = lerp(global_position, get_global_mouse_position(), 25 * delta)
func _input(event):
if event is InputEventMouseButton:
if event.button_index == BUTTON_LEFT and not event.pressed:
selected = false

Is Kotlin synchronized() not locking basic types?

class Notification(val context: Context, title: String, message: String) {
private val channelID = "TestMessages"
companion object ID {
var s_notificationID = -1
}
init {
var notificationID = -1
synchronized(s_notificationID) {
if (++s_notificationID == 0)
createNotificationChannel()
notificationID = s_notificationID
}
The above is being called simultaneously from two threads. A breakpoint in createNotificationChannel() clearly showed that sometimes s_notificationID equals 1.
However, if I change
synchronized(s_notificationID)
to synchronized(ID)
then it seems to lock fine.
Is synchronized() not locking basic types? And if so, why does it compile?
A look at the generated JVM bytecode indicates that the ID example looks like
synchronized(ID) { ... }
which is what you'd expect. However, the s_notificationID example looks more like
synchronized(Integer.valueOf(s_notificationID)) { ... }
In Java, we can only synchronize on objects, not on primitives. Kotlin mostly removes this distinction, but it looks like you've found one place where the implementation still seeps through. Since s_notificationID is an int as far as the JVM is concerned (hence, not an object) but synchronized expects an object, Kotlin is "smart" enough to wrap the value in Integer.valueOf on demand. Unfortunately for you, that produces wildly inconsistent results, because
This method will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
So for small numbers, this is guaranteed to lock on some cached object in memory that you don't control. For large ones, it may be a fresh object (hence always unlocked) or it might again end up on a cached object out of your hands.
The lesson here, it seems, is: Don't synchronize on primitive types.
Silvio Mayolo explained why it is not a good idea to synchronize on primitives (actually, I think the compiler should warn about this). But I believe there is another problem with this code, probably the main one that makes your synchronized blocks work in parallel.
The problem is that you replace the value of s_notificationID. Even if it would be an object, not a primitive, your synchronized blocks would still run in parallel, because each call to synchronized uses a different object. This is why in Java we usually synchronize on this and not on a field that we need to modify.
TL;DR The lesson here, it seems, is: Don't synchronize on primitive types.
synchronized(i) where i is Int, is actually synchronized(Integer.valueOf(i)).
Only in the range -128 to 127 this value is guaranteed to be a cached value.
Another fact is that ++i cannot be looked at as a mutation of the "object" i, but rather as replacing i by a new "object" with the value i+1.
Thank you broot & Silvio Mayolo for the above.
Experiments I did prove the above.
In my original code I have removed the ++ from
++s_notificationID. Amazingly or not, the lock worked now.
Now with that change I changed var s_notificationID = -1 to be var s_notificationID = -1000. Even more amazing, now the lock again stopped working.
Still, I think this anomaly of basic types undermines the attempt of Kotlin to see basic types as objects, and I think this should have been mentioned clearly in Kotlin documentation.

gdscript global variable value not changing after get_tree().reload_current_scene()

I wanted the variable
first_playthrough
to become false so when the scene reloads, it won't show the text "Hello from Number Guesser" anymore. But it's still showing it.
Therefore, it's either: it never became false, or that it became false, but then went back to true.
The shortened version of the code:
extends Node
var first_playthrough = true
func _ready():
# this is here so it will show the message
first_playthrough_checker()
func first_playthrough_checker():
# problem here is that, the message below still shows even though i thought i set it to 'false' already.
if first_playthrough == true:
text_printer("Hello from Number Guesser!\n\n")
func _restart_game():
#I've tried everywhere else. Thought it would work here. i was wrong.
get_tree().reload_current_scene()
first_playthrough = false
One solution would be a persistent data storage.
But maybe for a simple game like this one, it isn't needed anymore?
What am i doing wrong here?
I'll post the whole script if needed.
Building on an answer from a different site where i posted the question as well.
After creating the singleton globals where first_playthrough is declared, i replaced all instances of the variable on the script into globals.first_playthrough.
So in the shortened version of the code, this looks like:
extends Node
# removed the declaration here already, since it's already declared in globals.gd
func _ready():
# this is here so it will show the message
first_playthrough_checker()
func first_playthrough_checker():
# message below doesn't show anymore after globals.first_playthrough becomes false.
if globals.first_playthrough:
text_printer("Hello from Number Guesser!\n\n")
func _restart_game():
#I haven't tested it but i suspect the line after reloading the scene will create a memory leak?
#So i changed globals.first_playthrough's value before reloading the scene instead.
globals.first_playthrough = false
get_tree().reload_current_scene()
The script works as intended now.
By learning to use singletons, i learned that:
Declaring a variable global to the class even in a single script
project doesn't make it actually global.
An object is only global if it is declared in the project as so.
I should keep in mind that I'm still using a framework.
With gdscript, I have 3 options to store persistent information. 2 of which are most recommended.
Singleton documentation link:
https://docs.godotengine.org/en/3.1/getting_started/step_by_step/singletons_autoload.html?highlight=autoload

Alternative to the try (?) operator suited to iterator mapping

In the process of learning Rust, I am getting acquainted with error propagation and the choice between unwrap and the ? operator. After writing some prototype code that only uses unwrap(), I would like to remove unwrap from reusable parts, where panicking on every error is inappropriate.
How would one avoid the use of unwrap in a closure, like in this example?
// todo is VecDeque<PathBuf>
let dir = fs::read_dir(&filename).unwrap();
todo.extend(dir.map(|dirent| dirent.unwrap().path()));
The first unwrap can be easily changed to ?, as long as the containing function returns Result<(), io::Error> or similar. However, the second unwrap, the one in dirent.unwrap().path(), cannot be changed to dirent?.path() because the closure must return a PathBuf, not a Result<PathBuf, io::Error>.
One option is to change extend to an explicit loop:
let dir = fs::read_dir(&filename)?;
for dirent in dir {
todo.push_back(dirent?.path());
}
But that feels wrong - the original extend was elegant and clearly reflected the intention of the code. (It might also have been more efficient than a sequence of push_backs.) How would an experienced Rust developer express error checking in such code?
How would one avoid the use of unwrap in a closure, like in this example?
Well, it really depends on what you wish to do upon failure.
should failure be reported to the user or be silent
if reported, should one failure be reported or all?
if a failure occur, should it interrupt processing?
For example, you could perfectly decide to silently ignore all failures and just skip the entries that fail. In this case, the Iterator::filter_map combined with Result::ok is exactly what you are asking for.
let dir = fs::read_dir(&filename)?;
let todos.extend(dir.filter_map(Result::ok));
The Iterator interface is full of goodies, it's definitely worth perusing when looking for tidier code.
Here is a solution based on filter_map suggested by Matthieu. It calls Result::map_err to ensure the error is "caught" and logged, sending it further to Result::ok and filter_map to remove it from iteration:
fn log_error(e: io::Error) {
eprintln!("{}", e);
}
(|| {
let dir = fs::read_dir(&filename)?;
todo.extend(dir
.filter_map(|res| res.map_err(log_error).ok()))
.map(|dirent| dirent.path()));
})().unwrap_or_else(log_error)