#They all have their own scripts named
1 messages · Page 1 of 1 (latest)
also, let's do a thread
When you say "named the same", do you mean each enemy object has the same component attached to it?
for example, this is a Debris component
I have many objects with this Debris component on it.
I wouldn't thinking about the enemy having the "vampire.cs script" attached
The enemy has a Vampire component
which happens to be defined in a script file named vampire.cs
This is a tiny game there will only be this one enemy and its a vampire and then im moving on from this god forsaken game
Okay, so there's only one kind of enemy
So, you want to be able to find the closest enemy -- a game object with a Vampire component attached -- and reduce its health
Its also not entirely an enemy hence y i didnt call it enemy
Well first actually its the camper who wants to find the closest sleeping bag
Got it.
So, first, we want to find sleeping bags
you just want to get every single sleeping bag that exists, right?
Yes but the idea is i want a method thats modular so I can just call FindNearest(myreference, theirreference(object,class,script , whatever)
So i dont have to custom write all this crap each time i just want to find the nearest something
"script" isn't a kind of thing that actually exists in your game
scripts are just files that contain C# code
they do not exist anywhere in your scene
hence why I brought this up
But yes
you can definitely write a method that finds the closest object that has a certain component
FindObjectsOfType<SleepingBag>();
This will give you an array containing every SleepingBag component in the scene.
Components have a transform property, so you can find the Transform of the component (and thus its position).
Then you just need to pick the one that has the smallest distance to the point you asked about.
The method will look a bit like this
Now what if i want to find the nearest sleepingbag that has a field named "available" set to true
public static T FindClosest<T>(Vector3 position) where T : Component {
T[] options = Object.FindObjectsOfType<T>();
return options[0];
}
This method just picks the first one it finds.
But it's halfway there.
Ooh ok
The <T> means it's a generic method. It doesn't work with a specific type.
You tell it what type you want to use.
where T : Component forces the type to be a component
I understand generics ☺️
Ah, good.
You would add a second argument to the method. This argument is going to be a predicate.
a predicate is a method that returns true or false
public static T FindClosest<T>(Vector3 position, System.Func<T, bool> predicate) where T : Component {
T[] options = Object.FindObjectsOfType<T>();
foreach (var option in options) {
if (predicate(option))
return option;
}
return null;
}
System.Func<T, bool> is a function that takes a T and returns a bool
So, you could use it like this
FindClosest(transform.position, x => x.available)
While you're at it, you could replace the first argument with a function that returns a score. You'd just pick the result with the highest score.
Mixing in LINQ, you could do...
public static T FindBest<T>(System.Func<T, float> scorer, System.Func<T, bool> predicate) where T : Component {
T[] options = Object.FindObjectsOfType<T>();
return options.Where(predicate).OrderByDescending(scorer).FirstOrDefault();
}
You would use it like this
FindBest<SleepingBag>(bed => -Vector3.Distance(transform.position, bed.transform.position), bed => bed.available);
the first function returns the negative distance between you and the bed
so further beds get a more negative score
(feel free to ask about any part of this if it's unfamiliar)
This gets really useful when you make a more complex "score" function. You can combine many different criteria to pick where you go.
Just when i think im getting the hang of c# 😂 then someone blows my mind again
Well atleast i found my next bit of stuff to study
Functions that take other functions as arguments are great
You can wind up solving a lot of problems at once
Lambdas still take a while for my brain to parse i need to practise them more
sure thing :p it's a lot
When i see a lamba i still get an error 404 😂
You can use named functions if you want
So my whole plan is this:
public void Gimme() {
FindClosest<SleepingBag>(BagCloseness, BagUsable);
}
float BagCloseness(SleepingBag bag) {
return -Vector3.Distance(bag.transform.position, transform.position);
}
bool BagUsable(SleepingBag bag) {
return bag.available;
}
exact same outcome as this
public Dictionary<Az.State, dynamic> targetStateConditions = new Dictionary<Az.State, dynamic>()
But then also on the recieving end
The same but states
I've never used dynamic as a type parameter. scary.
So then when i look for the nearest objevt i look at the objects state dictionary
And see if my conditions ive added to my targetStateConditions
Are matched
This way i can simply set the target objectType and add or remove my conditions and find the nearest object related
To that
It allows me to dynamically check for variables in another object.
In a way i wouldnt be able to do if they were hardcoded fields
Thus the end goal is just to have a method i store in my shortcuts/dll class called FindNearest(targetObjectType, maxDistance, conditionsDictionary);
If you want to pass the type as an argument (e.g. typeof(SleepingBag)), you'll need to do reflection to read fields from the SleepingBag you find
because you won't know the type at compile time
IIRC, GameMaker's scripting language doesn't have static types
I would be careful about trying to force that same programming style into Unity and C#.
This might seem like overkill for this game but im actually setting it up for the real game im makig after this, the current game is just to set everything i need up and learn how the basics work
Oh nah the object type im refering to is already solved by what you showed me
FindObjectsOfType<>
Then i just use an enum setup in my shortcuts class to find the matching "field" in the targets dictionary
And check it against my conditions
===
I am reading through everything you wrote
To try and figure it out, thank you so much
For this answer
How are u able to access a variable from the bag
In the same way you are accesing the transform
Both of those methods accept a SleepingBag argument.
They aren't taking an object or Component or MonoBehaviour or something else that's vague
I can use them with FindClosest because they match the type parameter.
FindClosest itself has no clue that SleepingBag exists.
Perhaps you're asking about access modifiers, though
So SleepingBag isnt of GameObject type?
Correct.
Then what is its type
So through SleepingBag i have access to all its fields of all its scripts?
not "all of its scripts"
SleepingBag is a type. It's probably a class you defined
If you have an object of type SleepingBag, you can access any public members of SleepingBag
Ooh
public fields, methods, properties, types, ...
C# has no clue what's going on in your Unity scene.
Ok so i started off with this solution but it didnt work:
that's an important thing to understand
it doesn't matter if there's an object named SleepingBag, or if there's a SleepingBag attached to a game object, or if SleepingBag components are always attached to the same object as a Pillow component
the C# compiler has no clue about any of that
I cant find it now but the one solution i found online told me to create a object pool static HashSet then iterate through the HashSet to get the closest one but then I decided to put that in a Interface and let everyone just inherent from the interface to have that same pool and inheret that same function so i wouldnt have to add it to each object individually
They would be added to the pool in the OnEnable() method
But then the onEnable method didnt seem to run so i had to move it to Start()
Then i thought hey to hell with the whole interface let me just make a GameObject pool in my shortcuts class and pool all the objects in there
But then i didnt know how to access their fields
Which is how i ended up here
By type you mean the classname SleepingBag
Yeah
I just wanted to know if thats what u meant by type
So ur saying i should be iterating through instances of the class essentially
Which is what i did and I also did it with an Interface to group all the seperate objects classes together
You can use abstract classes and interfaces to create a hierarchy of types
The issue is i did all that but for some reason the OnEnable method in the Interface didnt add said class inherenting from the interface to the pool
If that worked everything else would have worked, finding the nearest, checkimg for certain fields to be certain values all of it
Thats what i had