How to detect if a custom shape has been clicked in godot? - godot

Is it possible to check if a custom shape has been clicked. For instance, how would I check if a piano key, which is not a regular shape, has been clicked. I would assume that you would make an area 2D and make a Collision Polygon 2D, which has your shape, as a child, Then you would send a signal to a script if their was input, and the script would check if it was a click and respond accordingly. I tried this but it is not working. Below is my code. Any help is much appreciated!
func _on_Collision_input_event(viewport, event, shape_idx):
if event is InputEventMouseButton:
if event.is_pressed:
$"RadioCPressed".show()
print("Object Clicked")
else:
$"RadioCPressed".hide()

You have a typo, it should be event.is_pressed() not event.is_pressed. It must be giving you an error on run time.
Assuming it is not giving you an error, it probably means the method is not running at all (You can use a print or breakpoint at the start of the method to confirm). Also, double check you connected the signal. And make sure the Area has input_pickable set to true.
Something else you need to consider if whether or not there is something else getting the input. A common case is that people will use a ColorRect or TextureRect for background, and leave it with mouse_filter set to Stop (which is the default). Even if it is in the background, you need to set mouse_filter to Ignore, because Controls take priority over other nodes for input. See Using InputEvent.

Related

What is the ideal way to change the value of a progress bar with on-screen button press (Godot)

I'm new to coding and Godot and I need help with changing the value of my progress bar from the script inside my button node. The error I get is 'get_node: (Node not found: "/root/ProgressBar" (absolute path attempted from "/root/Node2D/Button").)' I want every time the button is '_pressed()' to increment health by 10 which would change 'value' in ProgressBar to that value.
extends Button
var health= 0
func _ready():
pass
func _process(delta):
pass
func _pressed():
health += 10
print(health)
get_node("/root/ProgressBar").set_value(health)
The path /root/ProgressBar is unlikely to be correct. Usually, as a child of root, you would have the current scene, and as child of that something else (So the path could be something like /root/MySceneName/ProgressBar). And relative paths work too… Usually, we would solve this by means of figuring out the correct path…
But things have changed (For Godot 3.5 and newer). What you are going to do is open the script while the scene is open, and then drag - with CTRL pressed - the Control you want to access (i.e. the ProgressBar) on script, outside of any method (func).
By doing that Godot will generate a line of code that looks something like this:
onready var progress_bar: ProgressBar = $"Path/To/ProgressBar"
In other words, Godot will figure out the path you need, and set up a variable you can use. Godot will set the variable to the Node you dragged as part of the initialization of you script. Assuming all goes well.
You might get an error saying that the script is not used in the scene. Perhaps you have the wrong script open, or you use the script in multiple places and Godot got confused… Either way, close the script and open it from the scene, and it should work.
And, of course, you can use the variable to set its properties, for example:
progress_bar.value = health
You might also be interested in scene unique names. On the contextual menu of the Nodes in the Scene panel you can select "% Access As Scene Unique Name", this will allow you to access the Node with this syntax:
$"%ProgressBar"
Regardless of where it is in the scene tree. Except, be aware that the name must be unique for that scene (you won't be able to do that with two Nodes that have the same name).
This has the advantage that if later you change where the Node is in the scene tree (for example to add some Container to organize your Controls), you don't have to update the path to where you use it. Instead it should continue to work, as long as you don't change the name.
Let that be yet another reason to pick good Node names.
And yes, dragging the Node to the script also works with these.
The problem with your path is, that your missing the name of your main node in it.
So let's say your node tree looks like this:
MainNode
ProgressBar
Button
To get the ProgressBar from anywhere you would need to use get_node("/root/MainNode/ProgressBar")

Area2D Not Triggering Object in Godot

Here is my code: (just so you know I am a beginner and I just started this week, though I do have knowledge with other languages and game engines)
func _on_Area2D_area_entered(area):
get_parent().get_node("Level 1/Area2D/Flag").rotation_degrees += 1
What I was trying to accomplish was that the Player GameObject would see if its in the area of the Flag, and if it is, the flag would rotate.
I am not sure where the issue is. I think it is probably in the second line. I provided a screenshot below if I did the setup wrong. I have looked at the other close questions asked on the same topic, but they did not answer my question.
The "Player" GameObject is the one with the script that contains the detection if its in the area2D.
If you want to check if the Area2D is positioned correctly during runtime enable Debug -> Visible Collision Shapes.
If you want to check if _on_Area2D_area_entered is running, add breakpoints (or use print).
Did you get an error?
If there isn't a Node there, this expression will cause an error in runtime:
get_parent().get_node("Level 1/Area2D/Flag")
If you want to be able to check, you can use get_node_or_null and is_instance_valid.
Since you didn't mention any error, I'm going to guess the method is not running.
If the method is not running, the most likely culprit is that - I'm guessing given then name of the method - you connected the "area_entered" signal but intended to connect the "body_entered" signal.
The "area_entered" signal will trigger when another Area2D enters the Area2D. But I only see one Area2D in your scene tree. On the other hand the "body_entered" will trigger when a PhysicsBody2D (e.g StaticBody2D, KinematicBody2D, RigidBody2D) enters the Area2D. In either case you get what entered as a parameter of the method.
Other reasons why the Area2D might not be detecting what you want include no intersection of collision_layer and collision_mask and monitoring being disabled.
And to dismiss a couple possible misconceptions:
The "area_entered" and "body_entered" trigger when the Area2D or PhysicsBody2D respectively enter the Area2D, not every frame they are inside. So rotation_degrees += 1 is not a rotation animation.
You will get notifications of anything that trigger the signals, not just the object to which you connected it. You may have to further filter, e.g. if body == self:.
For people arriving here from search, I want to link a similar case: Enemy is not affected by bullets. And also my full explanation of how to set up physic nodes.

Redraw widgets with update

Let's say I have a button. In it's constructor I use variables to feed the values(before running I set some default values to these variables), so later they can be changed and within the program the look of the GUI can be modified. What I need is to update the widgets whenever I change these values.
For example I have some options to change a certain color, I press the button it calls a certain command defined in the constructor, changes the color variable and after that, it needs to be updated. Here it says the update() redraws widgets as needed. How do I tell it I need the widgets to be redrawn ?
http://effbot.org/tkinterbook/widget.htm
I might be mistaken on what the redrawing actually means. In any case I need it to update with the new values. I have a quite dumb solution for this, that is destroying everything and rebuilding it. I feel like there is a smarter way of doing things.
All widgets have a configure method which can be called to change any of its attributes. All you have to do is keep a reference to the widget(s), and call the method:
def update_the_widgets():
the_label.configure(background="red")
a_button = tk.Button(..., command=update_the_widgets)
the_label = tk.Label(..., background="green")
This is much easier if you use an object oriented style of coding. Otherwise these references need to be global variables.
When your GUI is properly coded you should almost never need to call update.

minimize and getting back the display

I want to minimize my app and after the timer end get it back.
I use code below.
To minimize application use following line of code:
Display.getDisplay (MIDLET_CLASS_NAME).setCurrent (null);
To get the screen back use the following:
Display.getDisplay (MIDLET_CLASS_NAME).setCurrent (myCanvas);
But when phone display is dismissed and going to clock mode my midlet display isn't shown until press any button.
any idea?
From your question it sounds that you expect setCurrent to somehow "force" device to immediately display your screen or maybe return only after screen gets visible.
This is not so, as clearly explained in the API documentation for Display.setCurrent:
Requests that a different Displayable object be made visible on the display. The change will typically not take effect immediately. It may be delayed so that it occurs between event delivery method calls, although it is not guaranteed to occur before the next event delivery method is called. The setCurrent method returns immediately, without waiting for the change to take place...
...if the application is in the background, passing a non-null reference to setCurrent may be interpreted by the application management software as a request that the application is requesting to be brought to the foreground... These are only requests, and there is no requirement that the application management software comply with these requests in a timely fashion if at all...
Consider redesigning your MIDlet to adjust to specified behavior.
If myCanvas is an instance of Canvas, one can use showNotify() events.
For a generic Displayable screen isShown() method checks if the it is actually visible on the display.
Sometimes it could even make sense to let user explicitly confirm return from background, like
display.setCurrent(new Alert("back to foreground", "dismiss to continue...",
null, AlertType.INFO), myCanvas);

PyQt QTreeWidget 'expanded' signal not being caught

I just started maintaining a set of embedded Python plugins for a Qt application. I'm also new to both PyQt and Python, so bear with me.
I have an implementation of a QTreeWidget in one dialog where the "expanded" signal is not being caught by the corresponding handler. I have another dialog where it works just fine.
In the problem dialog, I can verify that the connect was successful.
connected = wdg.connect(wdg.treeView_,SIGNAL("expanded(QTreeViewItem*)"), wdg.expanded)
evaluates to True. When I click on the child indicators to expand an item, the [+] signs change to a minus, but nothing else happens. Likewise, when I click on the [-], it toggles back to [+]. I have set the ChildIndicatorPolicy to initially set the indicator to SHOW in both cases.
In the dialog that works OK, when the user clicks on the plus sign, the 'expanded' handler is executed. Only the indicator toggles when it is clicked.
My handler code is simply:
def expanded(self, item):
logging.debug("In expanded handler")
I have a breakpoint at the logging call, but the statement is never reached.
I the failing dialog, I have another signal that's connected immediately before the one above, and it works just fine:
wdg.connect(wdg.treeView_,SIGNAL("currentItemChanged(QTreeWidgetItem*, QTreeWidgetItem*)"), wdg.itemChanged)
Is there anything that could prevent an expanded signal from firing or being caught? Another event perhaps? What should I be looking for? I realize that my nomenclature may be a bit off, and I welcome any correction in that regard as well.
The signal for a QTreeView expansion event is "expanded(QModelIndex)".
Alternatively, consider using the new style signal/slot syntax. I find it much easier than looking up the exact argument type for a particular signal.
wdg.treeView_.expanded.connect(wdg.expanded)
I found the problem. Despite the misleading name, the object is a QTreeWidge. When I replaced the name of the signal from "expanded" to "itemExpanded" and changed the parameter type to a QTreeWidgetItem*, everything worked.
wdg.connect(wdg.treeView_, SIGNAL("itemExpanded(QTreeWidgetItem*)"), wdg.expanded)

Resources