Yes, I saw that as well. And it’s either self.dir or self.speed that is nil. Using print() to figure out which one is your next step. Once you know which variable it is you need to figure out why it’s nil. Could it be that you forgot to initialise it in the init() function as is done in the tutorial? Perhaps you have some error in your on_input() function? Do you see any error in the console, prior to the error message?
Hmm, it must be the init, I deleted it thinking, as later in the tutorial, the init isn’t present in the code example, then one of the other code functions replaces it or something like that. Later today I’ll put the init string back in and let you know what happens.
Yep, that’s surely it!
Okay, now the rockets don’t play the explosion animation, they move correctly, but when they reach the distance theryre supposed to explode, three just rotate and stay still. The error I’m now getting is error:gameobject: instance unknown could my be found when displaying message’ play_animation" sent from main:/instance1#rocket
Ok, so you’re sending a play_animation message to a sprite component on the rocket and the URL part of the msg.post() call doesn’t match what you’ve set in the editor for game object and component id. Read more about URLs in the manual and double check against the tutorial that you’ve named everything the same way.
Thanks, I figured it out, whilst changing the code for collisions, I forgot to put a hash in front of the sprite XD
Guess I’ll highjack this nice thread for all the small/beginner questions related to the War Battles tutorial, both text and video. Everybody is welcome to ask questions.
War Battles tutorial:
Text: https://www.defold.com/tutorials/war-battles/
Video: https://www.youtube.com/playlist?list=PLXsXu5srjNlz1HvCPytEVZggLqWBoF1pz
Github: https://github.com/defold/defold-examples/tree/master/war-battles
Has anyone else noticed that the game fires too many rockets at once? It seems as though I’m shooting at least two rockets per input. Any thoughts where I could look in my code? I know I’m firing at least two b/c my logic for when self.firing = true
looks like this:
if self.firing then
print("here\n")
local angle = math.atan2(self.dir.y, self.dir.x)
local rot = vmath.quat_rotation_z(angle)
local props = { dir = self.dir }
factory.create("#rocketfactory", nil, rot, props)
end
Check your input message that you should react the button fire with the message.pressed so that it will fire one per press or click. Or you can make a timer that controls the fire cooldown time, for example 0.5 tps.
Hey!
So, I finished the tutorial and now I’m trying to implement the suggestions it makes at the end, starting with the other animations for the player. The code I wrote works fine with the one-direction movements, playing the animation only once every time the player changes direction, but with the diagonal movements it seems like it’s trying to replay the animation at every frame. I don’t know how to fix it.
Also (and this also happens in the web version in this page), I can’t fire rockets while moving in two specific diagonal directions (down-right and up-left), and I have no idea how to fix that.
Please help me with these, and any feedback on the code that the tutorial didn’t tell me how to make is very appreciated.
function init(self)
msg.post(".", "acquire_input_focus")
self.moving = false
self.speed = 100
self.input = vmath.vector3()
self.dir = vmath.vector3(0, 1, 0)
self.firing = false
self.anim_updated = false
end
function final(self)
msg.post(".", "release_input_focus")
end
local function update_anim(self)
if self.dir.x > 0 then
if self.dir.y > 0 then
msg.post("#sprite", "play_animation", { id = hash("player_upright") } )
elseif self.dir.y < 0 then
msg.post("#sprite", "play_animation", { id = hash("player_downright") } )
elseif self.dir.y == 0 then
msg.post("#sprite", "play_animation", { id = hash("player_right") } )
end
elseif self.dir.x < 0 then
if self.dir.y > 0 then
msg.post("#sprite", "play_animation", { id = hash("player_upleft") } )
elseif self.dir.y < 0 then
msg.post("#sprite", "play_animation", { id = hash("player_downleft") } )
elseif self.dir.y == 0 then
msg.post("#sprite", "play_animation", { id = hash("player_left") } )
end
elseif self.dir.x == 0 then
if self.dir.y > 0 then
msg.post("#sprite", "play_animation", { id = hash("player_up") } )
elseif self.dir.y < 0 then
msg.post("#sprite", "play_animation", { id = hash("player_down") } )
end
end
self.anim_updated = true
end
function update(self, dt)
if self.moving then
local p = go.get_position()
p = p + self.dir * self.speed * dt
go.set_position(p)
end
if not self.anim_updated then
update_anim(self)
end
if self.firing then
local angle = math.atan2(self.dir.y, self.dir.x)
local rotation = vmath.quat_rotation_z(angle)
local props = { dir = self.dir }
factory.create("#rocketfactory", nil, rotation, props)
end
self.input = vmath.vector3()
self.moving = false
self.firing = false
end
function on_input(self, action_id, action)
if action_id == hash("up") then
self.input.y = 1
end
if action_id == hash("down") then
self.input.y = -1
end
if action_id == hash("left") then
self.input.x = -1
end
if action_id == hash("right") then
self.input.x = 1
end
if action_id == hash("fire") and action.pressed then
self.firing = true
end
if vmath.length_sqr(self.input) > 0 then
self.moving = true
local temp = vmath.normalize(self.input)
if self.dir ~= temp then
self.anim_updated = false
end
self.dir = temp
end
end
Hi,
Yes, that is what happens. Your main problem stems from the following:
When you press “up” and “left” at the same time, two separate calls are made to on_input()
each frame before update()
is called. On each call, a different component of the self.input
vector is set. So looking at the value of self.input
if you hold “up” and “left”, you would see:
DEBUG:SCRIPT: vmath.vector3(-1, 0, 0)
DEBUG:SCRIPT: vmath.vector3(-1, 1, 0)
-- new frame
DEBUG:SCRIPT: vmath.vector3(-1, 0, 0)
DEBUG:SCRIPT: vmath.vector3(-1, 1, 0)
-- new frame
DEBUG:SCRIPT: vmath.vector3(-1, 0, 0)
DEBUG:SCRIPT: vmath.vector3(-1, 1, 0)
-- new frame
DEBUG:SCRIPT: vmath.vector3(-1, 0, 0)
DEBUG:SCRIPT: vmath.vector3(-1, 1, 0)
-- new frame
DEBUG:SCRIPT: vmath.vector3(-1, 0, 0)
DEBUG:SCRIPT: vmath.vector3(-1, 1, 0)
...
Since self.dir
is updated each of these calls, the flag self.anim_updated
will be set to false each call too and you get your problem.
A way to solve this, and also simplify the code is to remove the flag setting in on_input()
and do a check right with the animation code. For instance (4-way movement, but the idea works with 8-way too):
local function update_anim(self)
local anim = hash("player_idle") -- default
if self.dir.x > 0 then
anim = hash("player_right")
elseif self.dir.x < 0 then
anim = hash("player_left")
elseif self.dir.y > 0 then
anim = hash("player_up")
elseif self.dir.y < 0 then
anim = hash("player_down")
end
if anim ~= self.current_anim then
msg.post("#sprite", "play_animation", { id = anim })
self.current_anim = anim
end
end
I could not reproduce this which makes me suspect that it may be an issue with your keyboard. Check this thread for more info: Input behavior multiple buttons pressed (SOLVED)
It may be solved by using different keys for movement. Try WASD?
That actually makes a lot of sense. I tried your code and it works just fine with the 8 directions too.
It does work with WASD for some reason. As said in the thread you sent, it’s probably about the keyboard.
Thank you so much! I didn’t think I would be answered so fast.
I think that since most games use WASD, they treat those keys specially when manufacturing.
Who knows, what’s going on with my viewport and how can I fix it?
I’m pretty sure I did nothing, just tried to follow the tutorial.
Looks like your content might be placed a bit off, in relation to the x/y axes – could you check to see if this might bee the case?
Thanks for the reply.
Indeed, the map has been placed on 0,0,0 position:
Even if I place it as you suggest, it still looks weird:
How can I know the size of the screen to place the map correctly? I see no frame or any other origin anchor.
What about the distance to the player eyes? Should I zoom the map and all my other sprites instead of set some viewport settings?
Should I move and zoom the map manually in the Editor every time when I change the map size? Aren’t there any virtual camera settings?
I’m trying to make the tanks chase the player and i have added a spherical collision object to the tanks connected to a box shaped collision object on the player. I’ve created a tanks.script that contains the following:
function init(self)
self.speed = 200
end
function update(self, dt)
local pos = go.get_position()
pos = pos + self.speed * dt
go.set_position(pos)
end
function on_message(self, message_id, message, sender)
if message_id == hash("colllision_response") then
end
end
and i dont know what to write under the if statement, i want to write something like pos = player.pos or similar to make the tank move towards the player but that doesnt seem to work and i dont really have enough knowledge i feel. Any help would be appreciated! =)
Here’s an example of movement towards a moving target: https://github.com/britzl/publicexamples/tree/master/examples/simple_ai
I’ve been looking at the example but i dont understand so much of it ;/ i’ve read zombie.script many times but i understand how i should write my code in the defold project to make the tanks move. I’ve failed at trying to make the tanks respawn also, aswell as making them select a random point to move towards. I feel like i just lack the knowledge and any help would be so apprecieted ! maybe you can try to add more explanations in the code for the example you linked or try to help with the things i’ve been trying to code? =)
You typically spawn new items using a factory. We have a manual describing how to work with factories:
You select a random point like this:
local random_x = math.random(1, 1000) -- random value between 1 and 1000
local random_y = math.random(100, 800) -- between 100 to 800
local random_point = vmath.vector3(random_x, random_y, 0)
The easiest way to move from one point to another is to start an animation:
local duration = 2 -- seconds
go.animate(".", "position", go.PLAYBACK_ONCE_FORWARD, random_point, go.EASING_LINEAR, duration)
Read more here: https://www.defold.com/manuals/animation/#_property_animation
You can also animate in the update() function, step by step, frame by frame, but if you can it is recommended to use go.animate().