Android Python Tkinter custom joystick not resetting

52 Views Asked by At

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.

0

There are 0 best solutions below