I'm developing an RTS game in Python using Pyglet library. The sprite rotates in range from -180 to 180 degree. The sprite can't properly rotate from -179 to 179, it rotates clockwise, all the way to 179 passing 0, instead of rotating counterclockwise and reach 179 in just 2 degrees.
from math import trunc, degrees, atan2
from pyglet.app import run
from pyglet.clock import schedule_interval
from pyglet.window import Window
from pyglet.graphics import Batch
from pyglet.sprite import Sprite
from pyglet.image.codecs.png import PNGImageDecoder
from pyglet.window import mouse
from pyglet.image import load
from pyglet.text import Label
from pyglet.canvas import Display
class MAIN(Window):
def __init__(self):
window_width = Display().get_default_screen().width // 2
window_height = Display().get_default_screen().height // 2
super().__init__(window_width, window_height)
self.batch = Batch()
self.sptiteWidth, self.spriteHeight = 100, 100
# SPRITE
image = load('img/sprite.png', decoder=PNGImageDecoder())
image.anchor_x, image.anchor_y = self.sptiteWidth // 2, self.spriteHeight // 2
self.sprite = Sprite(image, x = window_width // 2, y = window_height // 2, batch=self.batch)
self.angle = 0
self.rotate = False
# LABEL
self.label = Label(
color=(255, 255, 255),
font_name ='Times New Roman',
font_size = 22,
x = self.width // 2, y = self.height // 4,
anchor_x ='center', anchor_y ='center')
def update(self, dt):
self.label.text = f'MOUSE ANGLE: {self.angle} || SPRITE ANGLE: {self.sprite.rotation}'
if self.rotate:
rotationSpeed = 1
if self.sprite.rotation != self.angle:
if self.sprite.rotation < self.angle:
self.sprite.rotation += rotationSpeed
else:
self.sprite.rotation -= rotationSpeed
def on_mouse_press(self, x, y, button, modifiers):
if button == mouse.LEFT:
self.angle = trunc(degrees(atan2(x - self.sprite.x, y - self.sprite.y)))
# if self.angle < 0:
# self.angle += 360
self.rotate = True
def on_draw(self):
self.clear()
self.batch.draw()
self.label.draw()
if __name__ == "__main__":
fps = 60
main = MAIN()
schedule_interval(main.update, 1 / fps)
run()
If your intention is to just make your sprite spin in the direction that would get you to the target fastest, then the code is heavily logic-based. Thus, I'll refer to a diagram to help with explaining.
Here, since you are working with -180 to 180, you want to firstly figure out this:
To do this, we need to figure out whether the "difference" is less than 180, which would be the upper area (-180 to 180 zone). If it isn't, then that means that it would be faster to work on the bottom area (cross the -180 and 180 border).
Now, we don't actually know which angle is the left angle and which one is the right angle yet. To do this, we simply ask, which one is greater?
So then,
We also need to take into account that when we cross the -180 and 180 borderline, we need to convert depending on the direction we're going (-180 to 180, 180 to -180).
def update(self, dt):
self.label.text = f'MOUSE ANGLE: {self.angle} || SPRITE ANGLE: {self.sprite.rotation}'
if self.rotate:
rotationSpeed = 1
if self.sprite.rotation != self.angle:
#New code
if abs(self.sprite.rotation-self.angle) < 180:
if self.sprite.rotation > self.angle:
self.sprite.rotation -= rotationSpeed
else:
self.sprite.rotation += rotationSpeed
else:
if self.sprite.rotation > self.angle:
self.sprite.rotation += rotationSpeed
else:
self.sprite.rotation -= rotationSpeed
if self.sprite.rotation > 180: self.sprite.rotation = -180
if self.sprite.rotation < -180: self.sprite.rotation = 180
#Your old code
# if self.sprite.rotation < self.angle:
# self.sprite.rotation += rotationSpeed
# else:
# self.sprite.rotation -= rotationSpeed