Easiest way to do it would be to add a huge collision sphere to the player set to overlap all, add a begin overlap event for it, and check if overlapped actor has a tag like “metal” which you would assign to any detectable actors. If it finds something. add it to an array variable, and check the distance periodically (either in tick or a timer event and play sounds/display any ui info based on distance to actor.
Check out my posts and example project in this topic about making a geiger counter. Could repurpose code and change the tags a bit to turn it into a metal detector.
I’ve tried to do your method but since i’m new to blueprint i didn’t suceed but here’s where i am now.
I’ve made a system that every second look for the nearest object in my scene with the tag “Metal” and i’ve made that if the distance is less than my variable it’s playing a specific sound so if the player is far it’s play one sound and near the object an another and if the player is on the object an another one.
But my problem now it’s my “Set timer by event” influence my sound also and every second the sound play again and superpose and i don’t know how to fix that.
get all actors of class is bit expensive, how often do you update that check? or how does it work? just scan with detector then only whats in range you get all actors?
The “Set timer by event” update it every 1 seconds and it supposed to take all actor “BP_MetalObject” and calculate which one is the closest every 1 seconds.
I’ve done this in the player blueprint since i don’t have a detector yet
So there is couple of aspect that we should take care of and make some decisions around it.
Detector
-Gets some tagged actors around, a collision sphere
–OnBeginOverlap->IF(Tags Match or Class) -> AddToArray (CurentMetalsAroundMe)
–OnEndOverlap->IF(Tags Match or Class)-> RemoveFromArray(CurentMetalsAroundMe)
So we know the actors now around us, you can set a size to collision, set maybe overllap all as channell in begin play and good to have that once with update overlaps ticket since on begin play if you already overlapping a metal you can know about it.
Feedback To Player
-There coulld be couple of use cases, where many metals around and maybe single metal. When its single its good however on multiple ones i am pretty sure it will get messy with the audio.
-In that terms just to start doing it nicely i will recommend selecting the most relevant one (will explalin this later)
Current distance 99999 for default and gets lower in callcuation if there is a metal around, when If(CurentMetalsAroundMe.Length > 0 is false you can set back to 9999 somenumber.
Now you have the ClosestMetal. When this turns valid simply you can run a timer of your choice 0.5 and set volume/pitch of your audio according to current distance again using same vector distance method, you can lerp volume pitch etc 0.5 1.5
Design Wise
I recommend going with a single source of focus since mulltiple sources can be sometimes not understandablle for players. If there is more than one the closest one is focused.
If you prefer geiger type of counter you can just prefer tick operation with distance check and kick a sound timer rate for that distance.
I suggest still using some ui, diegetic, haptic feedback in the detection since some players can be hearing disabled, deficient, playing without sound, llistening to music.
Maybe start with first event of collision: OnOverlapBegin/End and get actors around you correctly then let us know if you get stuck, we help.
I’ve tried but failed all the code need to be in my BP_MetalObject or my character ?
The variable “CurentMetalsAroundMe” is an Actor in array ? I’m not so familiar with types of variables.
Same for the rest of the variables i’m not sure of what types i need.
The code i tried doesn’t seems to work and don’t detect the BP metal near me.
For the design side and feedback my goal is to have multiple metal object bur far from each other so no overlap and maybe a radar in UI if the player can’t play with sound.
A sphere trace would be optimal for gathering objects. You can filter out by class and set the source of the sphere to be the end of the metal detector.
Instead of looping through the array and checking each distance, you can feed the array to a Find Nearest Actor node, and it will return the closest one and its distance.
Also, as in teh screen, I would suggest using Get Actors With Tag instead of class. Then you can just tag new bp actors later instead of redoing the code to filter for extra classes.
Using overlap event to test would probably be better too. Getting all actors could be expensive since it will be checking every object on the map.
As for the code being on the player or not. You could make a new component class blueprint and add the component to player(click make new BP like making an actor, but chose component for the base/parent class). With a component, you can also change its tick rate to, say 1s and fire the check in component’s tick event instead of mucking with timers.
In my level created some stuff like a static mesh or actor or your metall bp whatever.. on their detaills added an actor tag as MetalSource . Now whatever i tag with this name it can be detected
Now extended my logic a step further.. deleted debug prints and make over tick . loop actors and get distance and compare them if something matches added to CurrentClosestMetalActor variable. OnComplete created a custom event and named as CalculateSignal..
Converted CurrentClosestMetalActor to validate get and print out its name just to debug
Now onto making a nice audio feedback. Since i did this much i will make a Geiger type of audio feedback simulllation. Now actually added a distance mapped to 0.1 to 10 value as 'GeigerCoefficient`
I made a new function as play sound made a timelline 1sec. check if its playing, play timelline so we can be sure that it kicks random, created a lloop with the coefficient to randomize kicks of alpha particle added some randomization to dellaly and to rate. Used this sound Freesound - Walkie-talkie end of transmission by LukaCafuka mixed with
additonallly started audio loop here but you can change as you llike, and delays, fake sounds can be alllso simullalted using unrealls audio system however this is the raw logic / a quick proto, you can play and push further for sure.
Areas of improvement
Instead of a quick compare rule on distance , distances can be sort and prioritized.
Instead of loopiong audio an audio script can run without the timelines and delays.
Mulltiple actors can be prioritized but sound design wise lllowest sounds can be omitted or llower volume, ofcourse a nice audio design and good format sounds can be tweaked.
Make a blueprint - actor , name it treasure. Add a cube. Compile and save. Drag that BP into the map and hide it where you want the treasure to be. Inside the treasure bp event graph. Get a ref to the player. Off the event tick, use a get distance to from you to the player. Store its float output as a variable. Name it playerdistance. After that you should be able to use several branches (with that float value) and float in range nodes to calculate when that player is getting close or further away from the buried treasure. And set up logic according to those branches. Closer? beep faster Further beep slower.
The speed of the beeps will probably involve using Set Timer by event(s). Get the timer handles for each one. Each “zone” will have a different timer. And each timer will have a different timing to simulate the faster beeps or slower beeps. At each true branch or zone you will clear and invalidate timer by handle for all the other timers not for that zone. Add custom events for each timer to connect to the timers and drive the logic “play sound at location”? for your beep sample.
The more “stages” or zones this has the smoother it should operate.
Thanks a lot for all the explications i’ve learned a lot ! I’ve been doing your method and i’ve got everything working until the Timeline part, i’m not used to this node and don’t understand what you dit in there.
I’ve got an error from Unreal saying that my Geiger Effect Timeline variable is empty.
I’ve started thinking of timelines like a self contained source. You hit it once with a single pulse and out of its output comes a fast firing exec like an Event Tick based on the time it is set for and that seems handy for moving things. But that isn’t even their typical use, just how I have been using them lately, to actually use them like they intended is to have values that change over time based on the time it is all set for. Like key frames and video editing or animation.
Results are much nicer as below, have this feelling of Geiger randomized patterns.
Let me know if you can get it work or additional questions around it. There could me more problems to tackle interms of interaction design, sound direction, signs and feedback, gameplay design subjects.
Okay thanks a lot i manage it to make it work ! It does sound like a Geiger detector but not like a metal detector would, i’ve tried to change the values but it still doesn’t sound right.
I need like a soft beep noticing that it’s detecting even if nothing is close and when the player get closer to the object like in it’s range the beep goes faster until the player is on the object and the beep go crazy.
I’ve tried several things but i can’t manage to have the right logic to do what i want.. I don’t really understand which part make the sound go crazy when i get closer
The rest of the function is same, changed the variable name in CalculatedSignal() as sound variable and make it range between 0 - 1. Also fix a bug related to when no actors found currentmetal is set to none.
Let us know if you need a specific ui or something else, however on the video u show its a simple line compass . https://www.youtube.com/watch?v=lYTLWBiHXgw start with something like this and do basis, when you stuck feel free to ask.