i have a inventory that uses draw
calls. i want to extend this w/o inheritance (because there is no need to use all code again), i just need to draw more items on another control.
how to do it now:
i would have to attach a script to my stash Control node (stash.gd), and give it a variable hover_box_vector
, and then update it with a signal, then use stash.gd's
own _draw()
to display it. (which is triggered from inventory.gd)
however, i feel it's really redundant. this hover_box_vector
already exists in my inventory.gd, re-using the variable in another script doesn't make sense, but you have to.. because you cannot do this from inventory.gd:
for items in items:
draw_texture("etc/etc") # < -- This works
for items in stash_items:
StashNode.call("draw_texture", item.img, Vector2(item.pos.x, item.pos.y)) # < -- This errors out
You will get:
Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.
Description: Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.
C Error: Method/Function Failed.
C Source: scene\2d\canvas_item.cpp:682
C Function: CanvasItem::draw_texture
which is not fair, and only makes the dev do more work :(. not only that, but it adds more unnecessary code
I don't know anything about internals of Godot engine or GDScript, but usually such a way of painting things on a screen ('immediate mode GUI') needs to be inside a callback method that should only be called by the platform at specific times.
One possible way of dealing with the problem could be abstract the drawing call as an action or a command and queue drawing requests from outside as a list of such actions, then process them on every _draw
call internally.
Why not make inventory.gd
have a draw_items()
function that performs the draw operations you want and then maintain a reference to an inventory instance in the stash.gd
script that calls inventory.draw_items()
in the _draw()
callback? Unless I'm misunderstanding what you need here.
inside my Stash.gd:
extends Control
var cell_select_img
var hover_box_vector = Vector2()
var ItemBackgroundColor = Color()
var rect = Rect2()
func _ready():
UI.Pages.Inventory_Draw.connect("draw_cell_box", self, "draw_cell_box")
UI.Pages.Inventory_Draw.connect("draw_item_bg", self, "draw_item_bg")
func draw_cell_box(cell_select_img2, hover_box_vector2): # re-assign these.. :( whyyy
cell_select_img = cell_select_img2
hover_box_vector = hover_box_vector2
update()
func draw_item_bg(rect2, ItemBackgroundColor2):
rect = rect2
ItemBackgroundColor = ItemBackgroundColor2
update()
func _draw():
draw_texture(cell_select_img, hover_box_vector)
draw_rect(rect, ItemBackgroundColor)
And inventory.gd
emit_signal("draw_cell_box", cell_select_img, hover_box_vector)
emit_signal("draw_item_bg", rect, ItemBackgroundColor)
When I could just use these 3 lines inside inventory.gd
:
StashNode.call("draw_texture", cell_select_img, hover_box_vector)
StashNode.call("draw_rect", rect, ItemBackgroundColor)
StashNode.update()
please let us call draw
methods from other nodes, it would help so much
@Dar13 hello, just tried that. however, you still get:
0:00:03:0789 - Drawing is only allowed inside NOTIFICATION_DRAW, _draw() function or 'draw' signal.`, even when using a callback
"even when using a callback"
lol they on to us now
You still need to do it inside _draw()
function, which was what @Dar13 meant. There's no reason not to do it in _draw()
with his suggestion in this case, since now you have all the references to the nodes that need to participate in the drawing process.
callback is in _draw() as dar13 said, still errors out
Where are those emit_signal
calls in inventory.gd
?
I more meant something like this:
inventory.gd
func draw_items(control):
control.call("draw_texture", your_texture)
control.call("draw_rect", your_color)
stash.gd
onready var inventory = load(<path to inventory.gd>).instance()
# or
onready var inventory = <somehow get inventory.gd instance>
func _draw():
inventory.draw_items(self)
Note: this is pseudo-code, don't go copy-pasting it haha
yield
can halt the processing until it is drawable.
StashNode.update()
yield(StashNode,"draw")
StashNode.draw_texture(cell_select_img, hover_box_vector)
StashNode.draw_rect(rect, ItemBackgroundColor)
IMO, Dar13's approach might be better.
@Noshyaar that's a really cool trick... it does work, but unfortunately it's drawn behind the control node :(
i will try Dar13's approach, can close this if you guys want thanks for all the help so far. appreciate it
Additional info for clarity:
Drawing is a special operation. You can only do it when requested by the engine. Trying to draw when it is not drawable won't make it appears on the screen. This is a limitation in most engines.
You can use OS.can_draw
to see if the system allows you to call draw functions or not.
@girng: When I was doing something like that, I had to put draw() operations on the last node in hierarchy so that they'd be drawn on top of the controls and not behind.
You can use
OS.can_draw
to see if the system allows you to call draw functions or not.
Damn, we forgot to move that one to Engine
...
You've got a "draw" signal too, which, once connected, allows you to draw in the selected node.
@groud yeah.. correct
func _ready():
skill_description.connect("draw", self, "hi")
func hi():
skill_description.call("draw_rect", Rect2(Vector2(0, 0), Vector2(skill_description.rect_size.x, 1)), border_color)
this works.. I thought I didn't need to do node.call
(thought it was just returned) when using a signal... it kept confusing me
sorry for wasting everyone's time, now looking back at this issue i'm cringing at my OP
Note that you don't need to use call
for it, and this would work as well:
```gdscript
func _ready():
skill_description.connect("draw", self, "hi")
func hi():
skill_description.draw_rect(Rect2(Vector2(0, 0), Vector2(skill_description.rect_size.x, 1)), border_color)
``
Most helpful comment
You've got a "draw" signal too, which, once connected, allows you to draw in the selected node.