Firing at mouse position (SOLVED)

Can someone help me know how to fire bullets at mouse position?
I tried oneroom (britzl) but I am unable to break it
I tried the war battles tutorial - I am able to fire the bullets at the direction player is facing
Just want to fire bullets at the position of mouse click
Thanks in advance

Am a neophyte in Defold, and LUA for that matter but until someone with more experience ways in:

I am making a few assumptions here:

  • You have a game object that is the thing emitting (firing) the bullets.
  • You have a game object for the bullet itself.
  • You have a game object factory for creating the bullets.
  • That you are not doing this with the physics engine.

So, assuming the above I would image the following would work:

  1. Create logic in game object firing the bullet, in the on_Message function, to catch the mouse click message. See the Message Passing manual if you are not sure how to do that.
  2. Take the position (vector3) of the firing object from the position of the mouse click. This give you ‘distance’ between the firer and the mouse click.
  3. Call vmath.normalize on the above vector. This maintains the direction its pointing to but reduces the distance to 1, instead of the entire distance to the mouse click.
  4. Spawn a bullet from your bullet object factory and pass the normalized vector above to it as an attribute. See the factory manual if you are unsure how to do this.
  5. In the update function of the bullet, multiply the normalized vector by the speed you want the bullet to travel at, the multiply it by the delta time (the dt parameter on the update function). Add the result of this to the current position of the bullet to get the new position.

Done. :slight_smile:

4 Likes

Great answer @Kastarian!

I have an example with top down movement and bullets fired in the current direction the game object is firing. This example can complement the answer above:

1 Like

Thanks for the reply
I am still not able to get the result
This is how far I got
I created a player game object that can move
A bullet game object - (sprite, script)
Then a bullet factory
In the main collection - player game object - (sprite, bulletfactory, script)

Below is the script for player script

function init(self)                                 
msg.post(".", "acquire_input_focus")            

self.moving = false                             
self.input = vmath.vector3()                    
              
self.speed = 200                            

self.firing = false  
self.direction = vmath.vector3()

end

function final(self)                                
msg.post(".", "release_input_focus")            
end

function update(self, dt)                           
if self.moving then
	local pos = go.get_position()               
	pos = pos + self.dir * self.speed * dt      
	go.set_position(pos)                        
end

self.input.x = 0                                
self.input.y = 0
self.moving = false

if self.firing then
	local p = go.get_position()
	factory.create("#bulletfactory", p + vmath.vector3(25, 25, 0))    
	
end

self.firing = false
end

function on_input(self, action_id, action)          
if action_id == hash("up") then
	self.input.y = 1                            
elseif action_id == hash("down") then
	self.input.y = -1
elseif action_id == hash("left") then
	self.input.x = -1
elseif action_id == hash("right") then
	self.input.x = 1
elseif action_id == hash("fire") and action.pressed then
	self.firing = true
	local pos = go.get_position()
	
	local clickpos = vmath.vector3(action.x, action.y, 0)
	self.direction = vmath.normalize(pos - clickpos)
	

	
 end


if vmath.length(self.input) > 0 then
	self.moving = true                        
	self.dir = vmath.normalize(self.input)      
end
end


function on_message(self, message_id, message, sender)

end

After this, I am stumped
It seems like I can’t send a message to the bullet game object - It is spawned from a bulletfactory

Another question
What is the default position of the spawning bullets?
Say for example I want to spawn a bullet from the gun of a player character
Do I need to find the spawn location changing the values of spawn location through trial and error or is there any easy way?

Also how can I take the screenshot of the game?
Is there any shortcut in defold?

Can you please help?

What kind of message would you like to send to the bullet? You send a message like this:

local bullet = factory.create("#bulletfactory")
msg.post(bullet, "my_message")

If you don’t pass in a position to factory.create() the spawned game object will get the same position as the game object with the factory component.

You can put the factory in a game object and position that game object at the muzzle of your weapon.

If you’re on desktop I guess you can use the operating system provided ways of taking screenshots.

Or you can install an extension, grab a screenshot and write the image to disk:

3 Likes

I want to send the direction vector to the bullet script - (direction from player position to click position)
How can I send it?
I tried this but its not working
msg.post(bullet, “trigger”, way)
(‘way’ is the direction vector)

And I calculated the direction vector like this - (in player script)

           ..........
           elseif action_id == hash("fire") and action.pressed then
       self.firing = true
       local pos = go.get_position()
	
       local clickpos = vmath.vector3(action.x, action.y, 0)
       self.direction = vmath.normalize(pos - clickpos)
            way = self.direction
	end
   ........

Is this the right way to do it?

And in the bullet script I gave this code

 function init()
speed = 200
water = false
direction = vmath.vector3()

end


function update(self, dt)
if water == true then
	local pos = go.get_position()
	direction.x = direction.x * way
	local input = direction * 100 * dt
	
	go.set_position(pos + input)
	direction = vmath.vector3()
end
end

function on_message(self, message_id, message, sender)
if message_id == hash("trigger") then
	water = true
	
end
end

This is the error I am getting
ERROR:SCRIPT: /main/bullet.script:19: attempt to perform arithmetic on global ‘way’ (a nil value)

Also when defining speed, why is that 'self.speed = 200 ’ is not working
It’s only working when I define ‘speed = 200’
What is difference between defining ‘speed = 200’ and ‘self.speed = 200’

And thank you very much for the help

You should read the Lua manual, specifically about self and the lifecycle functions:

Your init() function is missing a self:

function init(self)

When creating an instance from a factory, you can pass in properties directly.
This removes the need for passing an extra message to the object:

See the example in the doc.

2 Likes

Okay, finally I got the answer to my question
But one final problem
I passed the direction vector (from player position to click position) to the bullet game object
When I fire the first bullet, it is going as expected
Then when I fire the second bullet, it is also going as expected but the first bullet is changing its course following the second bullet in a parallel way
same happens when I fire additional bullets - when I fire say ‘nth’ bullet, the remaining n-1 bullets are changing their course parallel to the course of nth bullet
I, kind of, solved my problem by giving the bullet very high speed
But how can I solve it using the code?

AND thank you everyone for the help

Then when I fire the second bullet, it is also going as expected but the first bullet is changing its course following the second bullet in a parallel way

How do you store the direction? It sounds like it’s not a script property or a property on self?

Also, to reiterate my answer, it’s easier in this case to have a script property, and set it when spawning the object.

I am sorry but I don’t understand your question - bit new to coding in defold
But I am assuming it is a script property that I used
I’ll post the code for player and bullet object

Player code:

 way = vmath.vector3()

 function init(self)                              
msg.post(".", "acquire_input_focus")           

self.moving = false                            
self.input = vmath.vector3()                   
           
self.speed = 200                      

self.firing = false  
self.direction = vmath.vector3()

end

function final(self)                                
msg.post(".", "release_input_focus")          
 end

 function update(self, dt)                        
   if self.moving then
	local pos = go.get_position()               
	pos = pos + self.dir * self.speed * dt      
	go.set_position(pos)                       
end

self.input.x = 0                              
self.input.y = 0
self.moving = false

if self.firing then
	local p = go.get_position()
	
	local bullet = factory.create("#bulletfactory")    
	msg.post(bullet, "trigger", {theway = way})
end
   self.firing = false
end

 function on_input(self, action_id, action)        
if action_id == hash("up") then
	self.input.y = 1                           
elseif action_id == hash("down") then
	self.input.y = -1
elseif action_id == hash("left") then
	self.input.x = -1
elseif action_id == hash("right") then
	self.input.x = 1
elseif action_id == hash("fire") and action.pressed then
	self.firing = true
	local pos = go.get_position()
	
	local clickpos = vmath.vector3(action.x, action.y, 0)
	self.direction = vmath.normalize(clickpos - pos)
	way = self.direction
	end
if vmath.length(self.input) > 0 then
	self.moving = true                        
	self.dir = vmath.normalize(self.input)      
end
end

Bullet script:

function init(self)
speed = 200
water = false
endway = vmath.vector3()
end


 function update(self, dt)
    if water == true then
	local pos = go.get_position()
    local input = endway * 2000 * dt
	go.set_position(pos + input)
  end
   local pos = go.get_position()
   print(pos)
   if pos.x < 0 or pos.x > 960 or pos.y < 0 or pos.y > 640 then
   go.delete()
end
end

 
function on_message(self, message_id, message, sender)
     if message_id == hash("trigger") then
	water = true
	print(message.theway)
    endway = message.theway
	
  end
 end

Try this:

function init(self)
    self.speed = 200
    self.water = false
    self.endway = vmath.vector3()
end

If you don’t put the variables on the script instance (self), they’re shared between the instances, and you’ll overwrite the values each time.

Also, read up on script properties and how you use them.

2 Likes

Okay, now it works
I am really sorry that I am asking too many questions but some parts of the documentation are a bit complex for me to understand
Thank you

3 Likes

No worries!
We’re happy to help!

4 Likes