How to implement this missile function?

I am making a shooting game using defold.
and trying to create a missile function for my role, the missile can track a nearest enemy and try to hit it.

the question is : how to locate the nearest enemy from lots of enemies ?does it have a easy way to do it?

you can see my game in this link Lonely Shooter

thanks!

If I right understand you need collect all enimies coordinates and found nearest for player. I mean when you create enemy store it coordinates in LUA table with uniq ID(Factory create uniqID) and find nearest. Or you can store only nearest. Changing every time when spawn new enemy.

thanks for the idea.
but there is a problem ,the enemies was moving ,and different types of enemy have different speed and angle towards the player. and also the enemy can be destoryed .

so if i want to got an accurate result ,i have to update the enemies table very frequent,I think maybe the cost has a little high.

but it`s still a good solution, thanks for your advice, i will try to implement it.

This shouldn’t be a problem, even on mobile, unless you have many hundred game objects. Iterating the table once per frame should be ok. But do you have to do it every frame? Perhaps you could spread the calculation over many frames using a coroutine? And once a missile is spawned should it change target or is the target fixed?

I think the missile should have a fixed target.
in the hardest mode of the game ,the enemy may over one hundred.
you are right ,I don`t have to refresh the table every frame but every 5 or 10 frame is ok.

Here’s the way I do it.

  • I use this Entity Manager Module to keep track of my enemies.
  • Add a sphere trigger collision object to the missile for its detection radius, so it doesn’t have to check all enemies everywhere. Set the collision groups and masks so it only is triggered by enemies.
  • When something enters the trigger, add it to a table of possible targets.
  • When something exits the trigger OR I get the “entity destroyed” message from the module, remove that object from the targets list.
  • Every update(), loop through the targets list, check the position to each target, and use the closest one.

Basically I’m assuming that the physics system is more efficient than using Lua to check everything.

Usually I have my enemies or missiles choose a target only at specific times, instead of every update, so I don’t worry about performance. But you could save a lot of go.get_position() calls if you stored the position of each object in a module.

2 Likes

Hi ross

Thanks for you advice. I have tried your codes in my game.
There is some problem,

because my game is a fast pace game , so the enemy may destroyed at a very short time, but at that time the missile was get an entity from the manager ,it turns out the instance was null.

Didnt read all answers and just the first lines of questions… but there is an idea :slight_smile:

Finding the nearest enemy could be using

  • a table containing all enemies and then “parse” it
    or
  • using the raycast-function and “scan” the area. Thats the way I use in my game.

Hmm, well that’s not good, that’s exactly what it’s supposed to prevent. The game objects shouldn’t get deleted until after the messages are sent. You’re calling "entman.spawn(msg.url().path, entman.enemies) on init and “entman.destroy(msg.url().path, entman.enemies)” on final in your enemy script?

Oh, hmm. I guess if you’re spawning or destroying more enemies in one frame than the message dispatch limit then it might fail. Or is it possible you’re spawning and deleting an enemy in the same frame? I will do some stress tests later to see if I can break it myself.


[Update] Well, I did a test, spawning and deleting 1000 objects every frame and doing go.get_position() in the “entity destroyed” message to make sure the ID was valid. That worked fine, so I don’t think the speed of your game is an issue. Maybe I didn’t explain how to use it well enough? Can you share the parts of your code where you use it?

I’ll try to come up with a good example for the module and see if I can add some error checking.

hi ross
thanks for help ,i would love to share some parts of my code to you ,maybe you can help me to find out the problem.

part 1
I used the whole code you shared on github, and i add a custom function to get a random target .

function M.getAnRandomEnt(group)
	local num = M.getCount(group)
	local randomNum = math.abs(math.random(1,num))
	local count = 1
	for k,v in pairs(ent[group]) do
		if count == randomNum then
			--print(num,randomNum,count)
			return k
		else
			count = count + 1
		end
	end
end

part 2
how i use the function at a missile init()
i usually got some error when a missile created ,and try to get the target position, it will report a error that the instance not found.

function init(self)
	self.refreshTime = 1
	self.t = 0
	self.speed = 500
	
	M.subscribe(msg.url("#"),M.enemies)
	if M.getCount(M.enemies) > 0 then
		print("INSTANCE EXIST!!!!!!")
		self.target = M.getAnRandomEnt(M.enemies)
		if self.target == null then
			go.delete()
		else			
			self.targetPos = go.get_position(self.target)
		end
	else
		print("NO INSTANCE")
	end
end

and the error output is below.
code line 25 is self.targetPos = go.get_position(self.target)

DEBUG:SCRIPT: INSTANCE EXIST!!!!!!
DEBUG:SCRIPT: INSTANCE EXIST!!!!!!
ERROR:SCRIPT: /scripts/missile.script:25: Instance l not found
stack traceback:
	[C]: in function 'get_position'
	/scripts/missile.script:25: in function </scripts/missile.script:10>
	[C]: in function 'create'
	/scripts/go_role.script:102: in function </scripts/go_role.script:79>
ERROR:GAMEOBJECT: Could not initialize when spawning /main/missile.goc.
ERROR:GAMEOBJECT: Could not spawn an instance of prototype /main/missile.goc.

[UPDATE]
I think i may found the problem from.
Because I create my own function for use, but I did not realize that the key-value “l” is also a value.
So when the Entity Manager is empty ,the M.getCount will not 0.
That `s why the debug log shows instance l not found ,I ignored the l letter .
Now I need to do more test to confirm it.but if you can help me to check my code to find out is there any other problem, it still help me.
thanks!

2 Likes

Ahhh, yeah, that “l” value being in the same table is a problem. That’s bad design on my part. M.getCount() should work unless you somehow call M.spawn() or M.destroy() in an invalid way, it just reads the value of “l”. Other than the “l” key thing, I don’t see any issues with your code.

Sorry for all the trouble! I’ll take this as good feedback and rework the module so it has some error checks and doesn’t have that “l” key. The getRandomEnt function is a good idea too.


[Update] Here’s a new version of the module. entity_manager.lua (5.2 KB)

It should be fully compatible with code that uses the older version. I put the entity counts in a separate table, so you don’t have to worry about that “l” value, and I added a few error checks. I couldn’t find a perfect way to check if something is a URL and give a clear error message, but at least it will throw some sort of error if you give it the wrong thing. I also added in your getRandomEnt function, with an added check if count > 0, because math.random(1, 0) will fail and give an error.

1 Like

Nice work! Pal.

Your new code is better than mine, I will update it to my game, thanks for all your helps.

2 Likes

hey pal

i was interested about the raycast function,where can i retrieve the documents about this?
thanks!

Hey @solariyoung

You can find raycasts at the manuals/api here

2 Likes