I made an asteroids game with Defold a long time ago. For the wrapping I made a separate script that I added to all the objects (though it would be a bit more efficient to use a module).
Wrapper Script Code
local wrap = require "main.framework.wrap_manager"
-- wrap_manager is a tiny module to store the half-sizes of the camera view. Gets set from the render script.
go.property("radius", 32)
function init(self)
self.extents = {x = wrap.halfx + self.radius, y = wrap.halfy + self.radius}
self.didWrap = false
end
function update(self, dt)
self.pos = go.get_position()
self.didWrap = false
if self.pos.x > self.extents.x then
self.pos.x = -self.extents.x
self.didWrap = true
elseif self.pos.x < -self.extents.x then
self.pos.x = self.extents.x
self.didWrap = true
end
if self.pos.y > self.extents.y then
self.pos.y = -self.extents.y
self.didWrap = true
elseif self.pos.y < -self.extents.y then
self.pos.y = self.extents.y
self.didWrap = true
end
if self.didWrap then go.set_position(self.pos) end
end
If you wrap things exactly at the edge of the window then it will be very obvious when they disappear from one side and reappear at the other, and it could mean if your ship is near the edge of the screen that an asteroid will suddenly appear right on top of you (or vice versa). So I decided to wrap things some distance outside of the screen edges. Since there was a fairly wide size difference between my objects (large asteroids, player ship, bullets, etc.), I decided to make that distance a different minimum for each object. So that’s what the “radius” property is on my wrapper script. Yes, this can theoretically cause some discrepancies, since a small bullet can wrap before a large asteroid, but for me it wasn’t noticeable and this method “felt” the best.
I do input I do it similarly to what you have, only I use 1 for pressed and 0 for released (instead of true/false), and on update I combine these into an input vector.
function init(self)
self.inputVec = vmath.vector3()
self.up, self.down, self.left, self.right = 0, 0, 0, 0
end
function on_update(self, dt)
self.inputVec.y = self.up - self.down
self.inputVec.x = self.right - self.left
end
The most easily understandable way to do your on_input function is probably like this:
Click to show code
function on_input(self, action_id, action)
if action.pressed then
if action_id == hash("up") then
self.up = 1
elseif action_id == hash("down") then
self.down = 1
elseif action_id == hash("left") then
self.left = 1
elseif action_id == hash("right") then
self.right = 1
end
elseif action.released then
if action_id == hash("up") then
self.up = 0
elseif action_id == hash("down") then
self.down = 0
elseif action_id == hash("left") then
self.left = 0
elseif action_id == hash("right") then
self.right = 0
end
end
end
If you’d rather your code be short, you can get a bit fancy and do something like this:
Click to show code
local inputMap = {
[hash("up")] = "up",
[hash("down")] = "down",
[hash("left")] = "left",
[hash("right")] = "right",
}
function on_input(self, action_id, action)
if action.pressed or action.released then -- I prefer to filter out the unnecessary actions every frame.
local mappedInputName = inputMap[action_id]
if mappedInputName then
self[mappedInputName] = action.value
end
end
end
The full version of your update and init should be something like this:
Click to show code
local FORWARD_VEC = vmath.vector3(0, 1, 0) -- Must match how your ship is designed in the editor.
local TURNSPEED = 4.6
local THRUST = 650
local DAMPING = 0.5
function init(self)
self.inputVec = vmath.vector3()
self.up, self.down, self.left, self.right = 0, 0, 0, 0
self.vel = vmath.vector3() -- Linear velocity.
self.forward = vmath.vector3(FORWARD_VEC) -- Forward vector.
end
function update(self, dt)
self.inputVec.y = self.up - self.down
self.inputVec.x = self.right - self.left
self.pos = go.get_position()
self.rot = go.get_rotation()
if self.inputVec.x ~= 0 then
local drot = vmath.quat_rotation_z(self.inputVec.x * -TURNSPEED * dt)
self.rot = self.rot * drot
go.set_rotation(self.rot)
end
self.forward = vmath.rotate(self.rot, FORWARD_VEC)
if self.inputVec.y ~= 0 then -- Use `> 0` instead if you only want forward thrust.
local accel = self.inputVec.y * THRUST * dt
self.vel.x = self.vel.x + self.forward.x * accel
self.vel.y = self.vel.y + self.forward.y * accel
else -- Not thrusting, apply damping to velocity.
self.vel.x = self.vel.x - self.vel.x * DAMPING * dt
self.vel.y = self.vel.y - self.vel.y * DAMPING * dt
end
go.set_position(self.pos + self.vel * dt)
end
NOTE: All this code is completely untested, so it might not actually work if you copy-paste it in.
“Pro” Tip: If you accelerate your turning speed from zero to full turn speed over the first 0.15 sec that you hold a turn button, then you’ll get way better fine control over your aiming with no noticeable drawbacks, and your game will control better than 99% of the space games out there.