I coded a joystick in tkinter on py android phone and I noticed that it doesnt reset if you dont slow down until youre hand is still and then release the canvas.
I noticed that if not released correctly the joystick slows down and then stops without reseting. Also the self.joyactive variable of the joystick doesnt change in this state. It seems like the canvas doesnt detect the release so I think the problem is in the CanvasOnRelease(self) function
Here is my code:
from tkinter import *
import time as t
from math import *
class Game:
def __init__(self):
self.root = Tk()
self.load()
self.joystick()
self.player()
self.root.mainloop()
def load(self):
self.joyactive = False
self.joymiddlepartX = 0
self.joymiddlepartY = 0
self.ring_dict = {}
self.screenX = self.root.winfo_screenwidth()
self.screenY = self.root.winfo_screenheight()
self.text = Label(self.root, text="screenX: {} screenY: {}".format(self.screenX, self.screenY), fg='white', bg='black')
self.text.pack()
self.canvas = Canvas(self.root, width=self.screenX, height=self.screenY, bg='black')
self.canvas.pack()
self.canvas.bind('<ButtonPress>', self.CanvasOnTouch)
self.canvas.bind('<ButtonRelease-1>', self.CanvasOnRelease)
self.canvas.bind('<Motion>', self.CanvasOnMotion)
self.root.after(1000, self.void)
def void(self):
self.text.configure(text='X: {}, Y: {}, Active: {}'.format(self.joymiddlepartX, self.joymiddlepartY, self.joyactive))
self.root.after(1, self.void)
def joystick(self):
self.joysize = 100
self.joyspace = 150
self.joyposX = self.screenX * 100 / self.screenX
self.joyposY = self.screenY * 1600 / self.screenY
self.joyedgewidth = 10
self.joydiameter = self.joyspace * 2 + self.joysize
self.joyextraspace = 10
self.joymaxX = self.joysize/2 + self.joyspace + self.joyextraspace
self.joymaxY = self.joymaxX
self.joyrestingpos = [self.joyposX + self.joydiameter / 2 - self.joysize / 4, self.joyposY + self.joydiameter / 2 - self.joysize / 4]
self.edge = self.canvas.create_oval(self.joyposX, self.joyposY, self.joyposX + self.joydiameter, self.joyposY + self.joydiameter, width=self.joyedgewidth, outline='white')
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize / 2, self.joyrestingpos[1] - self.joysize / 2, self.joyrestingpos[0] + self.joysize, self.joyrestingpos[1] + self.joysize, fill='white', width=10)
self.joystickCode()
def joystickCode(self):
self.joyXoffset = self.joyposX + self.joyspace + self.joysize/2
self.joyYoffset = self.joyposY + self.joyspace + self.joysize/2
self.squareroot = sqrt((self.joyrestingpos[0] - (self.joyrestingpos[0] - self.joysize/2 + self.joymiddlepartX - self.joyXoffset + self.joysize / 2))**2 + (self.joyrestingpos[1] - (self.joyrestingpos[1] - self.joysize / 2 - (self.joyYoffset - self.joymiddlepartY) + self.joysize / 2))**2)
self.joyaddedsize = self.joysize/2 + self.joyspace + self.joyextraspace
if not self.squareroot > self.joyaddedsize:
if self.joyactive == True:
self.joyXoffset = self.joyposX + self.joyspace + self.joysize/2
self.joyYoffset = self.joyposY + self.joyspace + self.joysize/2
self.canvas.delete(self.middlepart)
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize/2 + self.joymiddlepartX - self.joyXoffset, self.joyrestingpos[1] - self.joysize / 2 - (self.joyYoffset - self.joymiddlepartY), self.joyrestingpos[0] + self.joysize + self.joymiddlepartX - self.joyXoffset, self.joyrestingpos[1] + self.joysize - (self.joyYoffset - self.joymiddlepartY), fill='white', width=10)
else:
self.joymiddlepartX = 0
self.joymiddlepartY = 0
self.moveX = 0
self.moveY = 0
self.canvas.delete(self.middlepart)
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize / 2, self.joyrestingpos[1] - self.joysize / 2, self.joyrestingpos[0] + self.joysize, self.joyrestingpos[1] + self.joysize, fill='white', width=10)
self.joyXoffset = self.joyposX + self.joyspace + self.joysize/2
self.joyYoffset = self.joyposY + self.joyspace + self.joysize/2
self.squareroot = sqrt((self.joyrestingpos[0] - (self.joyrestingpos[0] - self.joysize/2 + self.joymiddlepartX - self.joyXoffset + self.joysize / 2))**2 + (self.joyrestingpos[1] - (self.joyrestingpos[1] - self.joysize / 2 - (self.joyYoffset - self.joymiddlepartY) + self.joysize / 2))**2)
self.joyaddedsize = self.joysize/2 + self.joyspace + self.joyextraspace
#self.text.configure(text=self.squareroot)
if self.squareroot > self.joyaddedsize:
#self.text.configure(text='HALT STOP')
self.angleX = self.joymiddlepartX - self.joyrestingpos[0] - self.joysize/4
self.angleY = self.joymiddlepartY - self.joyrestingpos[1] - self.joysize/4
self.angle = degrees(atan2(self.angleY, self.angleX))
#self.text.configure(text="Angle: {:.2f}".format(self.angle))
self.validposY = sin(radians(self.angle))*self.joyaddedsize
self.validposX = cos(radians(self.angle))*self.joyaddedsize
#self.text.configure(text=self.validposX)
self.joymiddlepartX = self.joyrestingpos[0] + self.joysize/4 + self.validposX
self.joymiddlepartY = self.joyrestingpos[1] + self.joysize/4 + self.validposY
else:
self.angleX = self.joymiddlepartX - self.joyrestingpos[0] - self.joysize/4
self.angleY = self.joymiddlepartY - self.joyrestingpos[1] - self.joysize/4
self.angle = degrees(atan2(self.angleY, self.angleX))
for self.item in self.ring_dict.values():
self.canvas.delete(self.item)
if self.joyactive:
self.joyextrarings = 4
self.joyeringwidth = 25
for self.i in range(-1, self.joyextrarings):
if self.i == -1:
self.i = 0.1
elif self.i == 0:
self.i = 0.33
self.joyeringsize = self.joysize/self.joyextrarings*self.i
self.mpc = self.canvas.coords(self.middlepart)
self.offsetX = self.joyposX + self.joydiameter / 2 - self.joyeringsize / 4
self.offsetY = self.joyposY + self.joydiameter / 2 - self.joyeringsize / 4
self.mpc[0] -= self.offsetX
self.mpc[1] -= self.offsetY
self.mpc[2] -= self.offsetX
self.mpc[3] -= self.offsetY
self.x1 = self.mpc[0]/self.joyextrarings*self.i+self.offsetX
self.y1 = self.mpc[1]/self.joyextrarings*self.i+self.offsetY
self.x2 = self.mpc[2]/self.joyextrarings*self.i+self.offsetX
self.y2 = self.mpc[3]/self.joyextrarings*self.i+self.offsetY
self.width = self.joyeringwidth/self.joyextrarings*self.i
self.ring_dict[self.i] = self.canvas.create_oval(self.x1, self.y1, self.x2, self.y2, outline='red', width=self.width)
self.canvas.tag_raise(self.middlepart)
if self.joyactive:
self.moveX = cos(radians(self.angle))*self.squareroot/self.joymaxX
self.moveY = sin(radians(self.angle))*self.squareroot/self.joymaxY
#self.text.configure(text='X: {}, Y: {}'.format(self.moveX, self.moveY))
#self.text.configure(text='A: {}, X: {}, Y: {}'.format(self.joyactive, self.joymiddlepartX, self.joymiddlepartY))
self.root.after(1, self.joystickCode)
def CanvasOnTouch(self, event):
self.joyactive = True
#self.text.configure(text=self.joyactive)
def CanvasOnRelease(self, event):
self.joyactive = False
#self.text.configure(text=self.joyactive)
def CanvasOnMotion(self, event):
if self.joyactive:
self.joymiddlepartX = event.x
self.joymiddlepartY = event.y #self.joyrestingpos[1]+self.joysize/4
#self.text.configure(text=event.y)
else:
self.joyactive = False
def player(self):
self.maxspeed = 5
self.size = 100
self.posX = self.screenX/2
self.posY = self.screenY/2
self.player = self.canvas.create_rectangle(self.posX-self.size/2, self.posY-self.size/2, self.posX+self.size/2, self.posY+self.size/2, fill='white')
self.root.after(1, self.playerCode)
def playerCode(self):
self.posX += self.maxspeed*self.moveX
self.posY += self.maxspeed*self.moveY
self.canvas.delete(self.player)
self.player = self.canvas.create_rectangle(self.posX-self.size/2, self.posY-self.size/2, self.posX+self.size/2, self.posY+self.size/2, fill='blue')
self.root.after(1, self.playerCode)
game = Game()
Here is the main part WITHOUT functions that can run it. I just removed every part where I didnt thought the problem is:
from tkinter import *
import time as t
from math import *
class Game:
def __init__(self):
self.root = Tk()
self.joystick()
self.root.mainloop()
def joystick(self):
#Define the joystick
self.joyactive = False
self.joymiddlepartX = 0
self.joymiddlepartY = 0
self.joysize = 100
self.joyspace = 150
self.joyposX = self.screenX * 100 / self.screenX
self.joyposY = self.screenY * 1600 / self.screenY
self.joyedgewidth = 10
self.joydiameter = self.joyspace * 2 + self.joysize
self.joyextraspace = 10
self.joymaxX = self.joysize/2 + self.joyspace + self.joyextraspace
self.joymaxY = self.joymaxX
self.joyrestingpos = [self.joyposX + self.joydiameter / 2 - self.joysize / 4, self.joyposY + self.joydiameter / 2 - self.joysize / 4]
#drawing the 2 main parts
self.edge = self.canvas.create_oval(self.joyposX, self.joyposY, self.joyposX + self.joydiameter, self.joyposY + self.joydiameter, width=self.joyedgewidth, outline='white')
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize / 2, self.joyrestingpos[1] - self.joysize / 2, self.joyrestingpos[0] + self.joysize, self.joyrestingpos[1] + self.joysize, fill='white', width=10)
#starting the code
self.joystickCode()
def joystickCode(self):
self.joyXoffset = self.joyposX + self.joyspace + self.joysize/2
self.joyYoffset = self.joyposY + self.joyspace + self.joysize/2
self.squareroot = sqrt((self.joyrestingpos[0] - (self.joyrestingpos[0] - self.joysize/2 + self.joymiddlepartX - self.joyXoffset + self.joysize / 2))**2 + (self.joyrestingpos[1] - (self.joyrestingpos[1] - self.joysize / 2 - (self.joyYoffset - self.joymiddlepartY) + self.joysize / 2))**2)
self.joyaddedsize = self.joysize/2 + self.joyspace + self.joyextraspace
if not self.squareroot > self.joyaddedsize:
if self.joyactive == True:
self.joyXoffset = self.joyposX + self.joyspace + self.joysize/2
self.joyYoffset = self.joyposY + self.joyspace + self.joysize/2
self.canvas.delete(self.middlepart)
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize/2 + self.joymiddlepartX - self.joyXoffset, self.joyrestingpos[1] - self.joysize / 2 - (self.joyYoffset - self.joymiddlepartY), self.joyrestingpos[0] + self.joysize + self.joymiddlepartX - self.joyXoffset, self.joyrestingpos[1] + self.joysize - (self.joyYoffset - self.joymiddlepartY), fill='white', width=10)
else:
self.joymiddlepartX = 0
self.joymiddlepartY = 0
self.canvas.delete(self.middlepart)
self.middlepart = self.canvas.create_oval(self.joyrestingpos[0] - self.joysize / 2, self.joyrestingpos[1] - self.joysize / 2, self.joyrestingpos[0] + self.joysize, self.joyrestingpos[1] + self.joysize, fill='white', width=10)
self.root.after(1, self.joystickCode)
def CanvasOnRelease(self, event):
self.joyactive = False
def CanvasOnMotion(self, event):
if self.joyactive:
self.joymiddlepartX = event.x
self.joymiddlepartY = event.y #self.joyrestingpos[1]+self.joysize/4 for move only on x
game = Game()
I tried to search for an option for the canvas to not smooth the movement and I asked ChatGPT for help.
I expect that it resets everytime when I released the canvas.