Wrap the player around the game window

Hi,

I am trying to implement a simple Asteroids game and a bit stuck with the implementation of the situation when a ship flies off the screen and it should then fly in to the screen but from the opposite location. Here is the screen shot which shows the ship off screen exit area and where I expect it to fly in. It seems like when I move horizontally it’s easy to just have some condition in update like if pos.x < 0 let say - set pos.x to screen.width x - but this only works with horizontal 90 degrees move when I start flying diagonally I need to calculate x and y depending from the x and y of the ship exist area. Basically I am following this tutorial and trying to re-implement the same with Defold https://www.youtube.com/watch?v=VIc8Kon5PFw&feature=youtu.be&t=623 and here is Game Maker function to do it GameMaker Manual

Is there any Defold example how to achieve the same results?

here is the code

go.property("angular_velocity", 1)
go.property("linear_velocity", 50)

function init(self)
	msg.post(".", "acquire_input_focus")
	self.input = vmath.vector3()
	self.rotate = 0 -- direction of rotation (0 = no rotation, 1 = left, -1 = right)
	self.accelerating = false
	self.accelerate_impulse = 0
end

function update(self, dt)
	-- handle rotation from key input left/right
	local rotation = go.get_rotation()
	if self.rotate ~= 0 then
		rotation = rotation * vmath.quat_rotation_z(self.angular_velocity * self.rotate * dt)
		go.set_rotation(rotation)
	end

	-- move in direction of rotation
	local pos = go.get_position()
	if self.accelerate_impulse > 0 and not self.offscreen then
		local distance = self.linear_velocity * dt * self.accelerate_impulse
		local direction = vmath.rotate(rotation, vmath.vector3(0, distance, 0))
		pos = pos + direction
		go.set_position(pos)
	end

	-- keep moving while holing acceleration button
	if self.accelerating then
		self.accelerate_impulse = self.accelerate_impulse + 0.02
	else
		if self.accelerate_impulse > 0 then
			self.accelerate_impulse = self.accelerate_impulse - 0.003
		end
	end

	-- when off the screen show in opposite side
	if pos.y < -31 or pos.x < -31 or pos.x > 516 or pos.y > 516 then
		self.offscreen = true
	else
		self.offscreen = false
	end
	
	if pos.x < -31 then
		go.set_position(vmath.vector3(516, pos.y, 0))
	elseif pos.x > 516 then
		go.set_position(vmath.vector3(-31, pos.y, 0))
	end

	if pos.y < -31 then
		go.set_position(vmath.vector3(pos.x, 516, 0))
	elseif pos.y > 516 then
		go.set_position(vmath.vector3(pos.x, -31, 0))
	end
end

function on_input(self, action_id, action)
	if action_id == hash("up") then
		if action.released then
			self.accelerating = false
		else
			self.accelerating = true
		end
	end

	if action_id == hash("left") then
		self.rotate = action.released and 0 or 1
	elseif action_id == hash("right") then
		self.rotate = action.released and 0 or -1
	end
end

the screen size 500x500 that’s why there are magical 516 nunbers and the ship sprite is 32 px

Just to clarify. If you fly out on the left hand side (by the blue line), with a down-left velocity, you expect the ship to appear top right (at the blue rectangle)?

1 Like

Is it something like this you want?

(Move the logo/player with the arrow keys. :slight_smile: )

8 Likes

how did you get this thing on the forum?

Yep, exactly

1 Like

yes, and it has exactly the same problem I have :slight_smile: try to move diagonally it re-spawning in the wrong location

2 Likes

Alright, according to the youtube video it seems to behave in the same way as my example above, which is also what I would expect from an astroid game. :slight_smile:

Could you explain in more detail how you want the “wrapping” to work?

4 Likes

Then you need to calculate the exit position based on the current trajectory. It’s a linear algebra problem but should be easy to work out.

The exit position, the enter position and the closest screen corner (top left in your image) forms a triangle. You know one side (the left, or the y position in your image). The top side is the x position and is easily calculated by multiplying the left side (y) with the velocity ratio between x and y velocities.

3 Likes

Thanks @sicher I guess you mean calculate entry position, since my exit position is where I point and move the ship. My math skills are depressing but I’ll give it a try :slight_smile:

“wrapping” is definitely a confusing word here but this is how they call this process in Game Maker :slight_smile: Ok, here is another image to demonstrate. Basically the logic in your example and in my code works fine when the player moving horizontally or vertically 90/180 degrees and leaving the screen, then the ship will re-appear in the opposite window side so “if ship position.x is 0 then set the ship position to window.width” - this logic however does not work when you start moving your ship diagonally and diagonally leave the screen, just play with your example and you will see that the entry position after you leaving the screen by moving diagonally will not be correct with the current implementation. So as @sicher suggested the entry point should be calculated by using linear algebra methods.

btw I’ve just tested Game Maker’s function form video “move_wrap” it has the same “issue” with diagonal exit/entry means it is not so magical as I was thinking and does not solve the problem I’ve explained above. So @sven you’re right your example and my code works like in video but it does not work as I explained above.