Yep, unique nodes are definitely a more modern solution to this issue. I can't remember whether or not they existed when I recorded this video. Technology marches on!
Wow that is so complex for such a simple concept. What if you create all the images instead of textures that then have to be rendered as an image? Seems like this adds a step by having a texture have to render and then be assigned. Not sure if this optimizes anything but it seems like it removes a step and removes having to render after the fact. I'm fairly new to this so I could be way off here... just seemed like an extra unnecessary step.
@@gamegems7658 i did watch part 1 but it was with viewports and it seems like you could accomplish this without viewports but closer related to this. I was looking into decals for instance. I am trying to find a better way to accomplish this.
I assume(d) you didn't watch Part I because I literally spend the first *half* of that video explaining why I'm using the architecture that I'm using and the *first* thing you did was ask me why I'm doing it. It's very common for people to skip around my videos, miss something crucial, and then complain in the comments that I didn't cover it. So, apologies for being terse. I do, however, suggest that you watch Part I again and if you still don't understand the goal of this experiment, then post your questions and I will answer them. In short, though, I am using Viewports to generate textures because I am using Godot's UI nodes to create the card layouts instead of Photoshop or the like, and I'm doing *that* because I want to be able to dynamically render the card data from Resource files without having to bake that data into images.
@@gamegems7658 yes. That is literally the same thing i am trying to do but i wanted a mire resource friendly solution than viewports. Im considering writing my own.
The obvious alternative is to simply generate all of the card images in Photoshop or to go 2D, but depending on what you're trying to accomplish, that may or may not be ideal, either. All workflows have tradeoffs.
@@gamegems7658 it has to be 3D and I can generate all of them. But there are so many cards in the database it would take forever to load them all, so I’m trying to load them as the cards are drawn from the deck. And have the database update which card was drawn and what its effects are. I’m also pretty new to Godot. I used JavaScript mostly before.
I agree, and although it's not super-clear here my prototype is also generating the textures on the fly as the cards are spawned from the deck, because viewports can't "pre-render" textures. This has the added benefit, as you pointed out, of a card only being rendered and cached if it's actually being used in the current game. You *never* want to try and load/render every card in your database at once.
Not without heavy reworking, given that it's... for Godot and relies on Godot-specific features. But yes, you could probably cache Unity Viewport textures in a similar fashion and communicate their updating with delegates.
I fully agree with the documentation. I'm trying to implement a top down map in a viewport where I can also change scenes to get a different type of view, and the docs have been no help at all.
It's gotten better. Actually makes sense now, although I do prefer Unity's "tell this camera to render to this texture" functionality. Anyway what you're trying to do is pretty simple, just put the scenes you want to render into the viewport and use a ViewportContainer if you're trying to put it on your UI.
Fantastic tutorial. It conveys the bare minimum of information for understanding, then leaves. Nothing about syntax, or any of the detailed stuff I can find in the documentation, just the raw structure, basic workflow, and general design pointers. Thank you so much for making this!
i know this is an old video, but i get an indentifier error at 07:00 in the video at line 9 (identifier "sfxVolumeSlider" not declared in current scope.) and for the life of me i cant solve it edit and fix: turns out im just ad idiot, at the very start of the video (00:25) it shows how the sliders are connected to the script
Also it's a good idea to download and read through the github projects, they're often easier to parse whereas the videos are just an overview of the solution.
Thank you for this video, I went through the documentation and didn't quite grasp the explanation but this helped me figure out what I was misunderstanding right away. I'm writing a visible checkpoint system where the on-body contact is supposed to update all other nodes of the same type to not be the primary one. A message bus is the perfect solution for getting them to all acknowledge their status without talking to each other.
Great stuff, really like your channel. The special treatment of Button0 really bothers me. Why did you do it this way? Why not just clear/instantiate/wire everything all at once?
For the purposes of a tutorial, it's slightly easier than having to deal with creating and loading an external prefab, although I have seen it done in at least one professional project. It's not really something I do anymore myself.
Feels more complicated than necessary? I am grateful for this bc I learned a lot, however, couldn't actually get this working? I gave up after 400th error on the set_value. But learned a lot and now have a great math lesson for my students!
If you're talking about the volume calculations, yes; Godot actually encapsulates this in a pair of methods called linear_to_db and db_to_linear, which I didn't know about when I wrote the code featured in this video.
On my experience, I tried to program my automated tool for this with the hearbeast technique but creating the map world using csg premade shapes and then merge into one mesh it's way performant that using that mesh blocks where you hide the faces based on the block tile location, I was even using the SurfaceTool to merge the map block meshes into one. Actually I don't know why the steps csg -> single mesh (optional collisions) way is much faster, especially in the editor as a tool. I have a low-mid range pc, so I can easily notice it.
It's because CSG meshes have a load of extra functionality to facilitate the whole CSG-ness of it all. They're meant for rough prototyping of levels and quick, temporary mesh generation, which is why I use standard MeshInstance nodes instead. And while I didn't want to criticize his approach, one thing Heartbeast definitely does wrong in his video is to hide the overlapping faces rather than delete them with queue_free(). They'll never be seen, so why include the overhead of processing them? I'm guessing that when you merge the CSG nodes they turn into a MeshInstance, so the overhead of monitoring for mesh overlap no longer applies, hence the performance increase. I've never benchmarked it myself, though.
Will I be able to access a node's properties as if I've exported it normally? Or does this only provide the path to the node? e.g.: @export some_label_node: NodePath func _ready() -> void: some_label_node.text = "subscribe to Game Gems" Would that work? I'm trying to see the difference between @export some_label_node: NodePath and @export some_label_node: Label
You'd still need to call get_node() on the exported node path in order to access the node. In Godot 4, the vast majority of the time you'll probably want to export the node directly, but there are times when the path is preferred. You'll most likely know them when you see them.
I once extended the `GridMap` node to add some auto-tiling functionality to it comparable to that from the `TileMap` node. I never published it anywhere because I wanted to polish it a bit before doing so. As of writing this is about two years ago and I never really continued working on it, although I'd like to. … What a shame. 😅 However, it worked pretty good already (not perfectly though). But I'd never ever say this is the best solution for building things like 3D mazes because as you said, there's not **the** solution for a given problem. "Many roads lead to Rome", as we say in Germany. Good video. 😘👍
I wrote this algorithm back when I was learning Unity in like 2015 just to see if it would work, and then ported it to Godot once I switched to that engine full-time. I didn't know about GridMesh nodes back then, which I would definitely use for a more detailed map.
Thank you so much for this. It was exactly what I needed and perfectly explained at a great pace. Immediate subscribe! Do you happen to know if this can be used in HTML5 exports?
Technically yes, but since the texture is dynamically generated, the normal map would need to be as well. Pre-generated normal maps would require pre-generated textures, which defeats the purpose of this process.
I defintely see the usefulness of this, but I'm also having difficulty wrapping my head around where the implementation, and where the functions go ^^; . Time for ore research.
The Message Bus itself is literally just an autoloaded Godot script, and you connect to its signals just as you would any other. It's done this way so that it doesn't *matter* where the functions go.
nevermind, im dumb and figured it out, but now im getting a message that says variable w is not defined in the durrent scope even though im pretty sure it is
Buddy if you don't know how to program or even understand the basics of a programming or scripting language, don't just try to hack together some shit from a bunch of tutorials. You're asking questions any twelve-year-old who spent 10 hours learning could answer.
@jayroi1814 brother chill out, not only was it my first time ever using godot but also I figured it out incredibly fast, you ever think to not just hate on everything you see?
I'm trying to hold out and figure this out cause it seems like some simple mistake on my end but i compared the text from my scripts to yours and they are completely identical but i cant get choicesDialog.choices = ["Do the thing", "Do the other thing"] to show up in the container. Zero error codes. A single button with nothing in it shows up and disappears when i click on it and that's it.
Double-check your code against the Github project, and failing that, put a breakpoint in the choices' setter function and/or the function that initializes the dialog and see what it's doing.
Yes, it makes more sense conceptually to keep it separate. The scene is primarily for managing the UI so I didn't want to add a very complex set of nodes to it. You could easily attach the story to the scene and not have any ill effects. It might even work out better for you since you can then access the root of the tree with get_tree().get_root() if you need to.
Signals are like radio broadcasts, but you have to "tune in" (IE, connect) to them for it to matter. Either analogy works. Just know that signals will only be processed by nodes that are connected and listening for them.
Woah thats one of the older versions of windows, isn't it? I can tell because the window borders look like... well, windows. That was back when the UI design for the OS was actually good.
Sorry, complete beginner here. I'm using 4.2.1 and when I try to update the text and textures in the set function (I've assigned the resource via the editor), I get an error: "Invalid get index "card_name" (on base: 'Nil')." Probably it has something to do with load order. My script works, when I put it in the _ready() function.
Hard to say without looking at your code. Two things I can think of would be that if you're copying my code directly, I'm using camel case, not snake case, to define and access the variables in the resource. IE, "cardData", not "card_data". Also, you may have forgotten to assign the loaded resource to the local variable data prior to attempting to access it. Finally, note that I'm using get_node directly within the setter; if you're using the dollar sign notation (eg. $node_name assigned with the @onready annotation), then yes, it will fail in the setter because the nodes haven't been initialized yet. That setter runs before the node has been added to the tree, so you have to manually access the nodes.
@@gamegems7658 Thanks for the elaborate answer. Sadly, none of that was causing the error. I can't tell you exactly what it was, but I think it's just trying to load the @onready vars for name, text and texture before they are assigned. I've added code to wait for them and now it just works: if not cardName: await self.ready
@@gamegems7658 Thank you for the elaborate answer. I don't know what it was. Changing the case didn't work. What do you mean by "assign the lodad resource to the local variable prior to attempting to access it"? Currently, I grab the art for example like this: @onready var cardArt: TextureRect = $Front/SubViewport/Card_Template/CardArt I haven't tried manually accessing the node but I might. For now, I just put "await self.ready" in the setter function and that worked. It's probably not the best solution but for now it works.
That's your problem. The setter for the cardData variable runs before _ready()/@onready is called, which means that when the setter attempts to put the relevant data into those nodes, they haven't been assigned yet. Waiting until _ready is... ready is one way to solve the problem, but I think it would be better if you learned the order of operations for node initialization so that this, and other errors like it, don't come up in the future.
I am actually doing this exact thing for a 2d card game, reason being i need to run full card shaders on my cards so I need to turn the entire card into a single texture. As far as I know only possible with viewports. The main worry is performance since I have worked with viewports in 3.x and it did have performance issues. I assume having say 20 of them active at the same time would not work, but since the cards are somewhat static you could just render it once and store the result as an image. Then just refresh whenever something on the card changes. One downside here is that you can no longer have shaders just on the card art which is within the viewport, but was thinking it might be possible to get around that with a SDF in the shader that defines the area of the art and only letting your shader run on that area. Either way, would be very interested in hearing if you did any performance research on this and had any results?
That's about right, once I hit around twenty viewports onscreen my framerate took a nosedive. As you noted, the trick is to render the viewport to a texture and use that image as the card instead. Some mild tradeoffs, but usually necessary.
Thanks you, this is really cool! I'm a beginner so this was really helpful, but I have a question: is there a way to make it so that certain options are only available under certain circumstances? Say if you're making a text adventure and you want to make it so you can only choose the "use torch" choice if you picked up the torch many storynodes prior, for example. Or, since you mentioned a visual novel, having small sections of text in a storynode print out or not based on external variables such as affection points with the character, without having to make completely separate storynodes that share 99% of the text. I'm new to Godot and coding in general so apologies if these are stupid questions. Cheers, loving all your tutorials!
Yes, these things are all possible, I've done most of them in my expanded engine. I'll be doing a deep dive on it once I post the two videos on dungeon generation that I've got in the queue, stay tuned!
one real use case off the top of my head is used by the Godot engine itself for collision and visibility layers, the layers you set are stored as bit flags and you need to do bitwise operations to check specific layers in code