My game will have consumables with wildly varying effects and combinations of effects. I don’t want to make a ton of different scripts for every individual item and item effects SEPERATE from the resource it’s coming from. Like, if I had an item that healed you but made you temporarily weaker, I wouldn’t want to make a class_name ConsumableItemThatMakesYouHealALotButHasTheSideEffectOfATemporaryStrengthDebuff class.
type resource, you know? So my idea is that every Item instead has an exported script. Inside that script there is defined behavior (I’ll define some basic functions in the base ConsumableItem so that I don’t have to rewrite them every time). Basically like attaching a built-in script for a node.
Here’s the thing though:
class_name ConsumableItem
extends InventoryItem
@export var item_behavior_script : GDScript
@export var discard_on_use : bool = true
func execute_consume_script() -> void:
# Return if there's no script
if !item_behavior_script :
push_warning("This Consumable Has No Behavior Attached to it")
return
#if !(item_behavior_script.has_method("consume")):
#push_warning("Consumable has no consume() function")
#return
var instance : GDScript = item_behavior_script.new()
instance.consume()
func consume() -> void: pass
IT DON’T WORK :((((. It keeps giving me the error “Invalid call. Nonexistent function ‘new’ in base ‘GDScript’.” I know what that means but I don’t know what to do! Just going item_behavior_script.consume() don’t work neither. (Oh and by the way every consumable item’s script will have a func consume() -> void: in it.)
You can just create a script that extends Resource.
Using an example, in my game, I have a base abstract class called Action, which inherits Resource.
This class only has a single virtual function called Execute, and I also pass it the Node that I want to work with, just in case.
Then, later down the line, you can create a new script that inherits the Action class, and overrides / implements it’s Execute function. Then you add the custom functionality you’d like to said function.
In your code somewhere else, you never have to specifically look for any of your specific item scripts, but instead, you know all of them will implement / inherit the Action class, so you can simply do: action.Execute(self), and it’ll call the function of your item, even without that piece of code knowing what your item is exactly.
Not necessarily what I’m looking for, if I’m understanding you correctly. I already have multiple classes that work like that. But since my items will be so varied, and are themeselves resources, I’d rather them have an @export of a GDScript, also with a built-in script so that every item resource is just one file.
Here’s how my class structure works:
Resource
InventoryItem (Contains stuff like item name, weight, description, yada yada)
ConsumableItem (Contains logic for consumption) ← Already inherits resource
As far as I can tell, you’re that I make a script for every item? Like separate from the resource? I’m not really sure. Besides, I tried what you were saying, and that didn’t really solve any of what I was doing. I really don’t want to bloat my file structure with both a script and a resource for every item.
(my print statements aren’t always very descriptive)
So far tried both with and without the extends GDScript. I don’t think the script itself is part of the issue, at least for the error it’s returning (I doubt it’ll work even after the error is solved, I’ll most likely need to do trial and error after that).
(I deleted the last one because I think I forgot to press reply for you)
It’s a GDScript with that in it. I have a resource stimpack.tres with an exported var of type GDScript. I pasted the contents of that exported variable.
so yeah it worked with a .gd. Which makes me very sad because I really wanted to have unique scripts in the resource itself instead of as a seperate file. Any idea of how to achieve that
also when i switch it to resource instead of GDScript it doesnt work because the @export property within the resource is
like in the inspector when you click on the box by an exported property and a popup window shows up and you press the GDScript button (like with other exported properties that inherit resource like LabelSettings or StyleBox)
The script you wrote when you extended GDScript is not the source code of the script object you created. It’s a scripted script object as it were. This might confuse you because script is a special kind of resource that can instantiate other kinds of objects (including script objects) and change their functionality.
To simplify and avoid confusion, you shouldn’t really be inheriting GDScript class ever. Just make custom resource objects that contain the code you need to execute.
Okay… what should I use then? Sorry if I explained it bad but I don’t think you understand what I’m trying to do. Yes I know I can make inherited resources (I do that for every other resource I have in the game, this is a special case). Here’s a cobbled together mockup I made in ms paint:
If I’m understanding what you’re saying, it’s that I should make scripts for every kind of item with extends Resource which I don’t want to do because A: it’s just a script, if I could just evaluate a string safely especially because it won’t really be more than one function and B: that means there’s now two files for every resource, which becomes a headache very quickly.
I was able to get what I was doing working by creating a separate .gd file. But for aforementioned reasons that’s not ideal.
TL;DR: No a script extending Resource won’t work because that would be a whole seperate file for just a few lines at most of code.
(btw that pink purple background thing is pretty cool looking)
That could work for what I’m trying to do, it’s a different approach from what I was thinking but I might not have a choice
here’s kind of what I’m trying to do if that helps.
I think if I go with your approach I’ll have an array of resources that have an @exported resource of type ConsumableItemEffect and a value to pass it so that each effect is an individual thing. That seems pretty cumbersome to me but I’ll do it if I must.
What you’re saying makes no sense. You want to have a script but you don’t want to have a script.
Your item script thing can be an instance of a resource that just hosts that script function. You can reuse/assign that same instance any number of times. You’ll need a different resource class only if you need to host different code/function.
I didn’t look closely at what @tibaverus is suggesting but I think it’s pretty much the same thing.
that means there’s now two files for every resource, which becomes a headache very quickly.hat means there’s now two files for every resource, which becomes a headache very quickly.
Why do you think it becomes a headache? Nested resources are completely normal.
Would you rather copy-paste the same source code string whenever you need it? That’s the real headache. What do you do when you need to make changes to the code? Copy-paste again to everywhere it’s used?
Looking at your initial question, your script works if you remove the typing of instance (which is wrong in this case.) I just tested it out with a print statement and it worked fine.
And if you want to validate the type and gain intellisense, you can you an iscondition like this:
var instance: item_behavior_script.new()
if instance is ConsumableItem:
instance.consume()
You could also consider using a static function which doesn’t require an instance to run if you only care about the function and not the instance. I’m not sure what you’d have to do to verify what the script is in this case.
Of course, this all works if you change it to a Resource as well. If you change it to a Resource, instead of a dropdown of every script you have you can get a dropdown of only a certain type of resource that you specify via class_name by doing something like this:
@export var consumable_resource: ConsumableResource
This behaves a little bit differently as it’s an instance not the script itself. So there’s a bit of a tradeoff depending on what you’re looking for.
Yes, I’m hosting different code/functions for every ConsumableItem resource. I didn’t know this, but Script inherits Resource, mb. Also yeah I worded that pretty terribly.
ConsumableItem inherits a base class of InventoryItem, which inherits Resource, and they are defined by scripts. All the properties are set using an export variable so I can access them easier through the editor. ConsumableItem has a function that is called by either the player or another actor (enemies and npcs will also be able to use items). That function is going to call a script, which is an @exported script. This is one small script with one function that executes custom behavior. ConsumableItem has code for most of the behaviors (so I don’t have to repeat code), the added script just defines which of those functions to call. The consume() function is meant to be overwritten by the added script (maybe I should use a signal instead? Might be easier).
So in the file system I make resources (not scripts) inheriting ConsumableItem. This is where the consumables properties will be set, it just needs custom behavior. In the editor there’s an @exported variable you can set. When clicking on it there’s that dropdown where you can quick load a file or create one right then, and then instead of creating a WHOLE other .gd file to host a tiny amount of code, I’d rather just have it built-in to the resource, similar to how when in the inspector clicking on LabelSettings, it’s more efficient to make the changes to that built-in resource within the resource itself. Saving separate LabelSettings resources as a separate .tres files would be such a pain in the neck (and totally unnecessary) unless you intended on using that specific LabelSettings on a ton of different labels (which is different than what I’m doing, since no two items will have the same effect).
What I was trying to do was working fine when I saved the teeny-tiny scripts as their own .gd files, which, like I said, is double the necessary files.
Yeah, that’s what I’m doing
No, that’s the opposite of what I’m trying to do.
Sorry if I over-explained, but I fear if I made it any shorter I would have missed an important detail. Thanks for bearing with me