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:
- 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.
- 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.
- 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.
- 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.
- 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.
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:
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:
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.
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.
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
No worries!
Weâre happy to help!