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

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

Related

How do I require certain instance variables be provided at object creation?

Let's say I have a type of object in my game called oCharacter. All characters must have names, so I want to provide one when I construct the object. I can do that by using the _variables argument of instance_create_layer:
instance_create_layer(0, 0, "Instances", oCharacter, { name: "George" });
I could even make sure that I don't forget to do this by making a "constructor" function for characters and only instantiating them using that:
function character_create(_x, _y, _name) {
return instance_create_layer(_x, _y, "Instances", oCharacter, { name: _name });
}
But this approach has two problems.
The first is that I or another developer might forget about this convention and instantiate a character directly using instance_create_layer, forgetting to pass a name and setting up a runtime error further down the road.
The second (related) issue is that Feather doesn't know about this convention, so my Feather window is full of error messages about references to instance variables that aren't declared in the Create event - but I don't see how I can declare these variables in the Create event, as I'm expecting their value to be provided by the creator.
Is there some way of doing this that addresses these issues?
The first problem is just about setting rules about the code conventions within your team, if your team does not know about these conventions you want them to follow, then you should tell it them in a meeting.
For the second problem: Maybe you could create an empty/nullable variable in the Create Event? I'm afraid I'm not familiar with Feather
Personally I would do two things for this.
Create development standards for the team and put them in something like a Word document, wiki page, onenote, whatever makes the most sense for your team.
I would use a function to create the instance of the object (like you're doing there), and have some simple validation checks inside of the create event itself that will cancel it's creation (something like a guard clause) and output a debug message with a reminder.
It's not the most elegant solution but that should do the trick (assuming you haven't found something else by now haha)

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

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.

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

Reloading keyboard shortcut definitions in Pharo

I've been playing around with keyboard shortcuts in Pharo 7.0. I wanted to modify the binding for #jumpToNextKeywordOfIt in the Smalltalk editor and so I got the following change in the definition of buildShortcutsOn method:
(aBuilder shortcut: #jumpToNextKeywordOfIt)
category: RubSmalltalkEditor name
default: $y meta shift
do: [ :target | target editor jumpToNextKeywordOfIt: true ]
description: 'Jump to next keyword'.
My first thought was that just saving this definition should immediately take effect, but it was not the case. Then I thought, perhaps since this is part of a method definition, then calling this method on the editor class would do the trick. Now, the method takes an argument aBuilder and I don't really know what that is. So two questions arise:
Is this the proper way to apply keybinding changes to a running editor?
What is aBuilder in this context and how does one get it?
Let me give you some hints on how to find the solution (as this might be more valuable than giving the solution at once)
The problem is what's aBuilder right? Well, from the expression
(aBuilder shortcut: #jumpToNextKeywordOfIt)
we deduce that aBuilder is someone that responds to #shortcut:. Cmd+m and you will get 9 implementors of #shortcut:. One of them, KMBuilder has an interesting name. Moreover, its implementation of shortcut: is
shortcut: aKeymapName
^KMKeymapBuilder
for: aKeymapName
platform: platform
meaning that it will answer with an instance of KMKeymapBuilder. Browse this class and verify that it understands the next message from your expression:
category: RubSmalltalkEditor name
default: $y meta shift
do: [ :target | target editor jumpToNextKeywordOfIt: true ]
description: 'Jump to next keyword'.
It does! So this must be it! To check this, we still need an instance of KMBuilder. Browse the class, go to the class side and find the unary message #keymap.
This means that we can obtain aBuilder by evaluating
KMBuilder keymap
I love unary messages. Specially when they are on the class side!
Now go to the implementor of the method you already tweaked #buildShortcutsOn:. It is implemented in the class side and we can now evaluate:
RubTextEditor buildShortcutsOn: KMBuilder keymap
To make sure that it works, go now to the desired handler #jumpToNextKeywordOfIt: and insert a halt in it. This is in the same class, instance side.
Now lets press Cmd+Shift+y and see if we get the halt... Bingo! I mean, Halt!

VueJS: Why Trigger 'Input' Event Within 'Input' Event Handler?

I'm learning VueJS. I'm figuring out their currency validation example code.
Vue.component('currency-input', {
template: `
<span>
$
<input
ref="input"
v-bind:value="value"
v-on:input="updateValue($event.target.value)">
</span>
`,
props: ['value'],
methods: {
// Instead of updating the value directly, this
// method is used to format and place constraints
// on the input's value
updateValue: function (value) {
var formattedValue = value
// Remove whitespace on either side
.trim()
// Shorten to 2 decimal places
.slice(
0,
value.indexOf('.') === -1
? value.length
: value.indexOf('.') + 3
)
// If the value was not already normalized,
// manually override it to conform
if (formattedValue !== value) {
this.$refs.input.value = formattedValue
}
// Emit the number value through the input event
this.$emit('input', Number(formattedValue))
}
}
})
The $emit call at the bottom of the updateValue function, triggers an input event.
When I comment it out, the real time currency validation no longer works. So I realize it has a purpose.
But why trigger an input event inside an input event?
You'd think the input event would fire again, causing the updateValue handler to fire again, causing a stack overflow due to recursive calls.
I understand VueJS's much simpler $emit example code. It's just like Jquery's trigger function.
vm.$on('test', function (msg) {
console.log(msg)
})
vm.$emit('test', 'hi')
// -> "hi"
But in the currency validation example, I do not understand why $emit is used the way it's used, and why it works the way it works.
Can somebody explain?
The Emit call here is to allow you to hook into the event in parent contexts. The Input event is also used by the v-model directive to handle two way binding with components.
v-model='model' is essentially v-bind:value='model' v-on:input='model = $event.target.value' with some added bits to make it play nice. When you remove the this.$emit('input', Number(formattedValue)) You're removing the mechanism that updates the value outside the component.
EDIT: #Jay careful what you wish for sometimes
All elements in HTML have a series of native handlers for the common events; resize, load, unload, etc. These handle what to do when the page changes it's rendering and can be disabled or added onto, since the introduction of JavaScript browsers have used an event pump system that allows multiple functions to be attached to any event which run in sequence when the event is raised. An example being how you can have 3 functions run on resize to handle edge cases such as minimum/maximum size, screen orientation etc.
Form elements generally implement their own base event functions: keydown, keyup, mousedown, mouseup. These base functions invoke events to make our lives easier as developers, these being: input, blur, focus. Some have specialized events as in select elements implementing change, form tags implementing submit.
Input tags on focus capture keyboard input and display the text input cursor to indicate that it's ready to receive input. It adds in handlers for the tab keycode which finds the next available input and shifts focus to that element. The event pump style function system is great here as it allows you to bind to focus and do things like change the background color or border when the input is focused without having to implement the code for capturing input or displaying the cursor yourself.
Input tags also raise the input event when you type in them indicating that the input has changed, telling the browser to change the value and update the display so that the functionality expected by the user is consistent.
In the currency-input example we are adding the updateValue function to work with the native function and process the input value of the event, in the updateValue function we modify the string representation of the value and need someplace to put it. You could simply add a data property to hold the value and bind the input's value property to the data property allowing the currency-input to internally handle the display of the result but that would lock the value behind a private accessor and you would be unable to modify or retrieve the value of the resulting currency formatted value.
Using this.$emit('input', Number(formattedValue)) the updateValue function is acting similar to the native input tag by raising an event that can be captured by the parent context and worked with. You can store it in a value, use it as the basis for a function, or even ignore it completely though that may not help much. This allows you to keep track of the value of the input and modify it as needed or send it to the server, display it, etc.
It also ties into a few directives most pertinently v-model which is syntactic sugar to allow for a value property binding and an input event binding to a data property inside the current context. By providing a value prop and emitting an input event a custom element can act similar to a native form element in the systems of a Vue application. An extremely attractive feature when you want to package and distribute or reuse components.
It's a lot nicer to go:
...
<currency-input v-model='dollarValue'></currency-input>
<input v-model='dollarValue'>
...
Than to have to add in value and input bindings everywhere ergo:
...
<currency-input v-bind:value='dollarValue' v-on:input='updateDollarValue($event.target.value)'></currency-input>
<input v-bind:value='dollarValue' v-on:input='updateDollarValue($event.target.value)'>
...
Now that my weird rambling is done, I hope this helped with understanding some of the patterns and reasoning behind the currency-input example.