How to change the XFade on a transition node in script? - animation

I'm currently learning Godot and my textbook seems to be a bit out of date as it still uses the deprecated AnimationTreePlayer. So I've had to figure out AnimationTree on my own. The exercise for this lesson talks about changing the XFade for the transition node to a random value when the player presses the "up" key but I cannot for the life of me figure out how to do it. I see in the documentation that AnimationNodeTransition has a set_cross_fade_time(value) method but how do I get to it? How do I even access the tranisition node in the script? I've tried things like $AnimationTree/Transition and $AnimationTree["parameters/Transition"] but nothing I've tried works.
My script is currently on the root node and the node tree looks like this:
Sprite [script is here]
AnimationPlayer
AnimationTree

Let us say you have your AnimationTree with the AnimationPlayer set on the anim_player property. And the tree_root of the AnimationTree is an AnimationNodeBlendTree, where - among other nodes - you have an AnimationNodeTransition.
As you are aware, we can get some "paramters" of the AnimationTree, they should appear in the Inspector Panel. And there you should find this one:
$AnimationTree.get("parameters/Transition/current")
Where "Transition" is the name of the node in the AnimationNodeBlendTree. But there isn't a parameter for the xfade_time.
Instead we will get the root of the AnimationTree (in other words, the AnimationNodeBlendTree) like this:
var blend_tree := $AnimationTree.tree_root as AnimationNodeBlendTree
Then we can get the nodes like this:
var blend_tree := $AnimationTree.tree_root as AnimationNodeBlendTree
var node := blend_tree.get("nodes/NodeName/node")
By the way, if you change "/node" to "/position" you get a Vector2 with the position of the node on the editor.
So, let us say we want a node called "Transition", which is our AnimationNodeTransition. We do this:
var blend_tree := $AnimationTree.tree_root as AnimationNodeBlendTree
var transition := blend_tree.get("nodes/Transition/node") as AnimationNodeTransition
And finally we can access xfade_time. Set a random value you said? This should do:
var blend_tree := $AnimationTree.tree_root as AnimationNodeBlendTree
var transition := blend_tree.get("nodes/Transition/node") as AnimationNodeTransition
transition.xfade_time = rand_range(0.0, 120.0)
Or as a one line:
$AnimationTree.tree_root.get("nodes/Transition/node").xfade_time = rand_range(0.0, 120.0)
Be aware that the value of xfade_time is the number of seconds for the transition. So setting 120 give you a two minutes transition.

Related

Invalid set index 'texture' (on base: 'null instance')

Invalid set index 'texture' (on base: 'null instance') with value of type 'StreamTexture'.
extends Panel
var ItemClass = preload("res://Item.tscn")
var item = "res://Blue Jeans.png"
func _ready():
if randi() % 2 == 0:
item = ItemClass.instance()
add_child(item)
extends TextureRect
func _ready():
if randi() % 2 == 0:
$TextureRect.texture = load("res://Blue Jeans.png")
else:
$TextureRect.texture = load("res://Brown Boots.png")
I followed the exact tutorial on YT https://www.youtube.com/watch?v=FHYb63ppHmk
but it seems to debug differently.
This line:
$TextureRect.texture = load("res://Blue Jeans.png")`
Loads a png as a StreamTexture using load, and tries to set it to the texture property of whatever $TextureRect is.
But the error says that there is no texture property on a null instance. Thus, the problem is that $TextureRect is a null instance.
So what does the expression $TextureRect do? It is equivalent to get_node("TextureRect"). In other words it is trying to get a child node called "TextureRect". And it is getting null…
Does the node on which the script is attached have a child node called "TextureRect"? You didn't share how the scene tree looks like, but I suspect it does not.
The script you shared says extends TextureRect, thus the script would be attached to a TextureRect. However, that is not what they do in the tutorial. In the tutorial the script is attached to a Node2D that has the TextureRect as child. You can see that at 4:10 on the tutorial video.
If you want to set the texture of the node on which the script is attached, set texture directly:
texture = load("res://Blue Jeans.png")`
Or if you rather be explicit, use self:
self.texture = load("res://Blue Jeans.png")`
On the other hand, if you are trying to follow the tutorial, then put the script on a node that has the TextureRect as a child (called "TextureRect"), and there $TextureRect would work.

Scroll to selected row in GtkListBox

I'm a bit out of ideas here. I want a very simple thing: to be able to select a given GtkListBox row programmatically and then scroll the list box (which is wrapped in a ScrolledWindow and a Viewport).
Selecting a row is trivial (my code is Go & gotk3, but that's not so important):
listBox.SelectRow(row)
But scrolling to the row proved to be a real challenge. Whatever I tried, I failed:
I tried to focus the row, but it helped nothing
I tried to figure out the row's Y-coordinate using gtk_widget_translate_coordinates(), but it returns -1 for any row
Perhaps I can find out which row is at the top and the bottom of the list box and use that to scroll the ScrolledWindow but I can't figure out how to do that.
Update: I've tried what's proposed here: Manually scroll to a child in a Gtk.ScrolledWindow, but it didn't work as still no scrolling occurred:
listbox.SelectRow(rowToSelect)
listbox.SetFocusVAdjustment(listbox.GetAdjustment())
if rowToSelect != nil {
rowToSelect.GrabFocus()
}
I also tried the same with rowToSelect's child using the code below, to no avail:
if c, err := rowToSelect.GetChild(); err == nil {
c.GrabFocus()
}
I've finally nailed it thanks to the hint by Emmanuel Touzery. I didn't have to go as far as to use timers, but the problem was indeed that at the moment of filling of the list box the row hasn't been realised yet so no coordinate translation could possibly happen.
What I did is scheduled the scrolling using GLib's idle_add(), which makes it happen later downstream, and that seemed to have worked perfectly: see this commit for details.
In short, it all boils down to the following code:
func ListBoxScrollToSelected(listBox *gtk.ListBox) {
// If there's selection
if row := listBox.GetSelectedRow(); row != nil {
// Convert the row's Y coordinate into the list box's coordinate
if _, y, _ := row.TranslateCoordinates(listBox, 0, 0); y >= 0 {
// Scroll the vertical adjustment to center the row in the viewport
if adj := listBox.GetAdjustment(); adj != nil {
_, rowHeight := row.GetPreferredHeight()
adj.SetValue(float64(y) - (adj.GetPageSize()-float64(rowHeight))/2)
}
}
}
}
The above function has to be called using the glib.IdleAdd() and not in the code that fills the list box.
So, I had the same issue but managed to make it work in my case. I think there are good chances my solution will work for you too.
Since the grab_focus method didn't work, I started implementing a workaround solution using listbox_get_row_at_y. Highly unsatisfying, but hopefully it was going to work. And.. it didn't work, because get_row_at_y would always return null, for all the y values I'd feed it. And I knew the listbox wasn't empty. So that made me realize I was trying to focus a row that I had just been adding to the listbox.. The row wasn't realized yet, it couldn't be focused because it wasn't ready for that yet.
So I changed my code to fill the listbox, wait a 100ms timeout, and only then call grab_focus. And that worked!
I'm actually using a library which is wrapping the timeout call for me, but I think you could use g_timeout_add in 'raw' gtk for that purpose.
Note that this means that calling grab_focus on a listbox that was already filled beforehand and the items realized on screen should work directly. If that's your situation then this won't help you.

Terminal dashboard in golang using "termui"

I am working on drawing graphs on the terminal itself from inside a go code.I found this (https://github.com/gizak/termui) in golang. And used this(https://github.com/gizak/termui/blob/master/_example/gauge.go) to draw graph in my code.
Problem is this , as we can see in the code( https://github.com/gizak/termui/blob/master/_example/gauge.go ), they are passing g0,g1,g2,g3 all together in the end "termui.Render(g0, g1, g2, g3, g4)".
In my case I don't know how many gauges to draw before hand so I used a list to store gauge objects and then tried to pass list to render.
termui.Render(chartList...)
But it creates only one gauge.
This is how I am appending elements in the list.
for i := 0; i < 5; i++ {
g0 := termui.NewGauge()
g0.Percent = i
g0.Width = 50
g0.Height = 3
g0.BorderLabel = "Slim Gauge"
chartList = append(chartList, g0)
}
what I am getting is a gauge for i=4 only. when I am doing termui.Render(chartList...)
Am I doing something wrong?
PS - I have modified question based on the answer I got in this question.
Here is a good read on Variadic Functions
Take a look at the function signature of Render, https://github.com/gizak/termui/blob/master/render.go#L161
func Render(bs ...Bufferer) {
All you need to do is
termui.Render(chatList...)
assuming chartList is a []Bufferer
Edit
You are only seeing one because they are stacking on top of one-another. To see this add
g0.Height = 3
g0.Y = i * g0.Height // <-- add this line
g0.BorderLabel = "Slim Gauge"
From a quick review of the project, it appears there are ways for auto-arranging that have to do with creating rows (and probably columns). So you might want to explore that, or you will need to manually position your elements.

Highlight output path (decision tree) in d3 tree

Here i'm working on Decision tree using d3 tree example: Search collapse tree. In this example, user can search the node and the path from root to selected node will be highlighted. But in my case, when user enters, the nodes that connects to the output node, the path from the root node to the output node should be highlighted. Just like shown in the image:
I need to work the tree just like shown in the image but my logic seems not working. Please check out my FIDDLE. To get the outputh path, i added a method named as "searchPath" that works on click function of "Find output path" button. (In fiddle, the click function is not working, dont know why. In normal html page it works):
function searchPath(){
var searchText = $("#newpath").val();
//alert(searchText)
var textspl = searchText.split(",");
var path="";
for(var i=0;i<textspl.length;i++){
var paths= searchTree(treejson2,textspl[i],[]);
fullpath.push(paths[Object.keys(paths).length-1]);
}
console.log("finally : ");
console.log(fullpath);
d3.selectAll("circle").filter(function(d) {
console.log("circle name "+d.name);
});
//return fullpath;
}
To select the circle and link element based on the path, i added "id" attributes to those element. For circle, i give id as d.name and for link i give id as d.source.name+":"+d.target.name", so as to easily identify the source node and target node of a particular link.
But now i'm stuck with the code, i'm not getting any idea or logic to go forward.

selecting by attribute ala select(["name=Myriel"])

i am missing something basic about d3 selection. using the basic d3 force layout example, i want to select a particular node, say Myriel and make it fixed. following previous hints like this and this, it seems myrielNode = d3.select(["name=Myriel"]) should do it but does not? i've also tried filter() based strategies, ... what am i doing wrong, please?
var myrielDomNode = d3.select('[name="Myriel"]');
var myrielDatum = myrielDomNode.datum();
myrielDatum.fixed = true;
This of course assumes a DOM node exists that has an attribute name="Myriel" and is bound to data such that datum() is an object controlled by the force layout.
Update
Turns out that name was not an attribute of the DOM node, but rather an attribute of the data. In this case, finding the Myriel node becomes a find operation (via filter) on the data array:
myrielNode = nodes.filter(function(d) { return d.name == 'Myriel'; })[0]
You probably want
d3.select('[name="Myriell"]');

Resources