Rotation and direction problem

Hello, i’m actually working on a kind of “puzzle-adventure” game, in the second part of my game, the player can lunch a projectile. My problem is that the direction of the projectile doesn’t match the direction the player is facing when he’s rotation in radian is between pie/2 and pie.

here’s the code of my projectile:

function init(self)
	self.t = 2 --temps de vie
	self.explode = 0 --exploser ou pas
	self.enter = 0 --contact
	self.velocity = vmath.vector3(0, 0, 0)
end

function update(self, dt)
	self.t = self.t - dt
	self.rot = go.get_rotation() --enregistrer l'angle de rotation en quaternion
	self.rad = 2 * math.acos(self.rot.z) -- convertir l'angle en radian afin de pouvoir appliquer la trigo pour mettre le mouvement en correspondance avec l'angle

	if self.t < -(8/12) then --animation explosion finis, suppression
		go.delete()
	elseif self.t <= 0 and self.explode == 0 then --distance max atteinte ou contact, animation explosion
		msg.post("#sprite", "play_animation", {id = hash("explosion4")})
		self.explode = 1
	elseif self.t < 2-(8/12) and self.explode == 0 then --animation de charge finis, boule de feu lancer
		go.set_position(go.get_position() + self.velocity)
		self.velocity.y = math.cos(self.rad) * 10 --calculer le module du vecteur y de l'angle
		self.velocity.x = math.sin(self.rad) * 10 --calcule le module du vecteur x de l'angle
	end
end

function on_message(self, message_id, message, sender)
	if message_id == hash ("contact_point_response") then
		if message.group == hash("wall") or message.group == hash("enemie") or message.group == hash("player2") then
			if self.enter == 0 then
				self.t = 0.1 --contact, declenche explosion prématuré
				self.enter = 1
			end
		end
	end
end

and here’s the update function for the code of the player :

function update(self, dt)
	self.wall_contact = false
	self.correction = vmath.vector3()

--mouvement / rotation
	if self.moving then
		self.pos = go.get_position()
		self.pos = self.pos + self.dir * self.speed * dt
		go.set_position(self.pos)
	else
		msg.post("#sprite", "play_animation", {id = hash("player1_1")})
	end
	self.rot = math.atan2(self.dir.y, self.dir.x) + math.pi/2 --calculer l'angle en fonction de la direction du mouvement
	go.set_rotation(vmath.quat_rotation_z(self.rot)) --affecter l'angle à la rotation du joueur
	
	self.input.x = 0
	self.input.y = 0
	self.moving = false

	--power
	if self.shoot == 1 then
		if self.shooted == 0 then
			factory.create("#power", go.get_position(), go.get_rotation())
			self.moving = false
			self.t = 1
			self.shooted = 1
		elseif self.shooted == 1 then --une boule tirer donc attendre 1s
			if self.t < 0 then
				self.shooted = 0 --1s ecoule donc possibilité de retirer une boule
				self.shoot = 0
			else
				self.t = self.t - dt
			end
		end
	end
end

Thanks !

I think you should be able to replace this code:

    elseif self.t < 2-(8/12) and self.explode == 0 then --animation de charge finis, boule de feu lancer
        go.set_position(go.get_position() + self.velocity)
        self.velocity.y = math.cos(self.rad) * 10 --calculer le module du vecteur y de l'angle
        self.velocity.x = math.sin(self.rad) * 10 --calcule le module du vecteur x de l'angle
    end

with something like this:

    elseif self.t < 2-(8/12) and self.explode == 0 then --animation de charge finis, boule de feu lancer
        self.velocity = vmath.rotate(go.get_rotation(), vmath.vector3(10,0,0))
        go.set_position(go.get_position() + self.velocity)
    end

(I haven’t had time to test it myself, let me know how it goes!)

4 Likes

I think this line is the root of the confusion:

self.rad = 2 * math.acos(self.rot.z)

A quaternion is represented by a vector part (x,y,z) and an angle part (w). The vector part may be zero (the unit quaternion is (0,0,0,1)). And the sum of all elements squared is 1.

Simply taking the vector part’s z component and using it as an angle doesn’t work. Using the “w” part should give better results, since in this example we’re rotating around Z, but I would go with @sven’s suggestion since it is easier to read and understand.

Here’s an excellent introductory presentation about quaternions.

8 Likes

Yeah but when i first tried i used math.acos(self.rot.w) but it didn’t worked at all (i had probably done other mistake) so i tried to change and with “z” instead of “w” it worked better (exept for the issue i had here). Thanks for the link it will help me a lot !

I’ve replaced my code with the one @sven send me and it work without any problem. I didn’t know there was a vmath.rotate function that do this that’s why i tried with some trigo, now that i know that, it will be a lot easier for me !

2 Likes