This is a project that I have been working on for a while.
Here's the situation:
The code completes the end goal. It's meant to simulate the location of a ball suspended in air by four cables, and should be controlled by a simple gamepad. The code does this, so it accomplishes the goal in the most basic definition.
Here's the problem:
The ball only moves in one point when the "LT" button is pressed, which it is supposed to do. However, after this one movement, the ball doesn't move until the button is pressed again, even if the "LT" button is held. The same thing applies for the "RT" button to move the ball away. (Although the joystick's trackball doesn't exactly act like the inward-outward problem, I consider this to be the same problem.) As I said, the most basic definition of this program's goal has been accomplished. However, the true spirit of the goal is coming up just short.
Here's my question:
How should I get the ball to move as long as the "LT/RT" buttons are pressed and/or the trackball is being moved?
The code:
#Import modules
from tkinter import *
import pygame
#Initialize joystick
pygame.joystick.init()
if pygame.joystick.get_count() == 0:
print('No joystick detected')
else:
joystick = pygame.joystick.Joystick(0)
joystick.init()
###
# Interpret Joystick inputs
###
class Find_Joystick:
def __init__(self, root):
self.root = root
## initialize pygame and joystick
pygame.init()
if(pygame.joystick.get_count() < 1):
# no joysticks found
print("Please connect a joystick.\n")
self.quit()
else:
# create a new joystick object from
# ---the first joystick in the list of joysticks
joystick = pygame.joystick.Joystick(0)
# tell pygame to record joystick events
joystick.init()
## bind the event I'm defining to a callback function
## start looking for events
self.root.after(0, self.find_events)
def find_events(self):
## check everything in the queue of pygame events
events = pygame.event.get()
joystick = pygame.joystick.Joystick(0)
axisX = joystick.get_axis(2)
axisY = joystick.get_axis(3)
LT = joystick.get_button(6)
RT = joystick.get_button(7)
for event in events:
# event type for pressing any of the joystick buttons down
if event.type == pygame.JOYBUTTONDOWN:
if LT == 1:
self.root.event_generate('<<LT>>')
if RT == 1:
self.root.event_generate('<<RT>>')
if event.type == pygame.JOYAXISMOTION:
#Move left
if axisX < 0:
self.root.event_generate('<<Left>>')
#Move right
if axisX > 0:
self.root.event_generate('<<Right>>')
#Move upwards
if axisY < -0.008:
self.root.event_generate('<<Up>>')
#Move downwards
if axisY > -0.008:
self.root.event_generate('<<Down>>')
## return to check for more events in a moment
self.root.after(20, self.find_events)
def main():
#################
### Setup Window
#################
###
#Build All Components
###
#Window 1
root = Tk()
app = Find_Joystick(root)
frame = Canvas(root, width=1000, height = 1000)
frame.pack()
#Ball
global ball
global ballBox1
global ballBox2
ballBox1 = [495, 245]
ballBox2 = [505, 255]
ball = frame.create_oval(ballBox1, ballBox2, outline = 'red', fill = 'red')
ballCenter = [500, 250]
ballCoords = [50, 50, 50]
global ballLine1
global ballLine2
global ballLine3
global ballLine4
ballLine1 = frame.create_line((300, 150), ballCenter, fill = 'red')
ballLine2 = frame.create_line((400, 100), ballCenter, fill = 'red')
ballLine3 = frame.create_line((600, 150), ballCenter, fill = 'red')
ballLine4 = frame.create_line((700, 100), ballCenter, fill = 'red')
ballLines = (ballLine1, ballLine2, ballLine3, ballLine4)
#Cube
cubeFront = frame.create_rectangle([300, 150], [600, 400], width = 4.0, outline = 'blue') #Front Face
cubeBack = frame.create_rectangle([400, 100], [700, 350], outline = 'blue') #Back Face
leftEdgeTop = frame.create_line([400, 100], [300, 150], width = 4.0, fill = 'blue') #Top Left Edge
leftEdgeBottom = frame.create_line([300, 400], [400, 350], fill = 'blue') #Bottom Left Edge
rightEdgeTop = frame.create_line([700, 100], [600, 150], width = 4.0, fill = 'blue') #Top Right Edge
rightEdgeBottom = frame.create_line([600, 400], [700, 350], width = 4.0, fill = 'blue') #Bottom Right Edge
backEdgeTop = frame.create_line([400,100],[700,100], width = 4.0, fill = 'blue') #Top Back Edge
backEdgeRight = frame.create_line([700, 100], [700, 350], width = 4.0, fill = 'blue') #Right Back Edge
###
# Position Chart
###
#Box
positionBox = frame.create_rectangle([450, 475], [550, 550])
positionBoxLine1 = frame.create_line([500, 475], [500, 550])
positionBoxLine2 = frame.create_line([450, 500], [550, 500])
positionBoxLine3 = frame.create_line([450, 525], [550, 525])
positionBoxTextX = frame.create_text([475, 487.5], font = ('Arial', 14), text = 'X')
positionBoxTextY = frame.create_text([475, 512.5], font = ('Arial', 14), text = 'Y')
positionBoxTextZ = frame.create_text([475, 537.5], font = ('Arial', 14), text = 'Z')
global positionBoxCoordsX
global positionBoxCoordsY
global positionBoxCoordsZ
positionBoxCoordsX = frame.create_text([525, 487.5], font = ('Arial', 14), text = ballCoords[0])
positionBoxCoordsY = frame.create_text([525, 512.5], font = ('Arial', 14), text = ballCoords[1])
positionBoxCoordsZ = frame.create_text([525, 537.5], font = ('Arial', 14), text = ballCoords[2])
positionCoords = [positionBoxCoordsX, positionBoxCoordsY, positionBoxCoordsZ]
##################
### Move the Ball
##################
###
# Redrawing Function
###
#Redraw the object for it's position
def redrawObjects():
global ballLine1
global ballLine2
global ballLine3
global ballLine4
global positionBoxCoordsX
global positionBoxCoordsY
global positionBoxCoordsZ
global ball
frame.delete(ballLine1)
frame.delete(ballLine2)
frame.delete(ballLine3)
frame.delete(ballLine4)
frame.delete(ball)
frame.delete(positionBoxCoordsX)
frame.delete(positionBoxCoordsY)
frame.delete(positionBoxCoordsZ)
ballLine1 = frame.create_line((300, 150), ballCenter, fill = 'red')
ballLine2 = frame.create_line((400, 100), ballCenter, fill = 'red')
ballLine3 = frame.create_line((600, 150), ballCenter, fill = 'red')
ballLine4 = frame.create_line((700, 100), ballCenter, fill = 'red')
ball = frame.create_oval(ballBox1, ballBox2, outline = 'red', fill = 'red')
positionBoxCoordsX = frame.create_text([525, 487.5], font = ('Arial', 14), text = ballCoords[0])
positionBoxCoordsY = frame.create_text([525, 512.5], font = ('Arial', 14), text = ballCoords[1])
positionBoxCoordsZ = frame.create_text([525, 537.5], font = ('Arial', 14), text = ballCoords[2])
###
# Define each movement function
###
#Indicate that the window is selected
def callback(event):
frame.focus_set()
#Ball moves left
def moveLeftFunc(event):
if ballCoords[0] > 0:
global ballBox1
global ballBox2
ballBox1[0] -= 3
ballBox2[0] -= 3
ballCenter[0] -= 3
ballCoords[0] -= 1
redrawObjects()
#Ball moves right
def moveRightFunc(event):
if ballCoords[0] < 100:
global ballBox1
global ballBox2
ballBox1[0] += 3
ballBox2[0] += 3
ballCenter[0] += 3
ballCoords[0] += 1
redrawObjects()
#Ball moves up
def moveUpFunc(event):
if ballCoords[1] < 100:
global ballBox1
global ballBox2
ballBox1[1] -= 2.5
ballBox2[1] -= 2.5
ballCenter[1] -= 2.5
ballCoords[1] += 1
redrawObjects()
#Ball moves down
def moveDownFunc(event):
if ballCoords[1] > 0:
global ballBox1
global ballBox2
ballBox1[1] += 2.5
ballBox2[1] += 2.5
ballCenter[1] += 2.5
ballCoords[1] -= 1
redrawObjects()
#Ball moves inward
def moveInFunc(event):
if ballCoords[2] > 0:
global ballBox1
global ballBox2
ballBox1[0] -= 1
ballBox1[1] += 0.5
ballBox2[0] -= 1
ballBox2[1] += 0.5
ballCenter[0] -= 1
ballCenter[1] += 0.5
ballCoords[2] -= 1
redrawObjects()
#Ball moves outwards
def moveOutFunc(event):
if ballCoords[2] < 100:
global ballBox1
global ballBox2
ballBox1[0] += 1
ballBox2[0] += 1
ballBox1[1] -= 0.5
ballBox2[1] -= 0.5
ballCenter[0] += 1
ballCenter[1] -= 0.5
ballCoords[2] += 1
redrawObjects()
###
# Bind keys to movement
###
#Initiate movement when window is clicked
frame.bind("<Button-1>", callback)
#Move ball left with "Left Arrow" Key
frame.bind('<Left>', moveLeftFunc)
#Move ball right with "Right Arrow" Key
frame.bind('<Right>', moveRightFunc)
#Move ball up with "Up Arrow" Key
frame.bind('<Up>', moveUpFunc)
#Move ball down with "Down Arrow" Key
frame.bind('<Down>', moveDownFunc)
#Move ball inwards with "Tab" Key
frame.bind('<Tab>', moveInFunc)
#Move ball outwards with "Return" Key
frame.bind("<\>", moveOutFunc)
#############
#I think this is where the problem is
#############
def find_events():
## check everything in the queue of pygame events
events = pygame.event.get()
joystick = pygame.joystick.Joystick(0)
axisX = joystick.get_axis(2)
axisY = joystick.get_axis(3)
LT = joystick.get_button(6)
RT = joystick.get_button(7)
for event in events:
# event type for pressing any of the joystick buttons down
if event.type == pygame.JOYBUTTONDOWN:
if LT == 1:
global ballBox1
global ballBox2
ballBox1[0] += 1
ballBox2[0] += 1
ballBox1[1] -= 0.5
ballBox2[1] -= 0.5
ballCenter[0] += 1
ballCenter[1] -= 0.5
ballCoords[2] += 1
if RT == 1:
#root.event_generate('<<RT>>')
global ballBox1
global ballBox2
ballBox1[0] -= 1
ballBox1[1] += 0.5
ballBox2[0] -= 1
ballBox2[1] += 0.5
ballCenter[0] -= 1
ballCenter[1] += 0.5
ballCoords[2] -= 1
if event.type == pygame.JOYAXISMOTION:
#Move left
if axisX < 0:
#root.event_generate('<<Left>>')
global ballBox1
global ballBox2
ballBox1[0] -= 3
ballBox2[0] -= 3
ballCenter[0] -= 3
ballCoords[0] -= 1
#Move right
if axisX > 0:
#root.event_generate('<<Right>>')
global ballBox1
global ballBox2
ballBox1[0] += 3
ballBox2[0] += 3
ballCenter[0] += 3
ballCoords[0] += 1
#Move upwards
if axisY < -0.008:
#root.event_generate('<<Up>>')
global ballBox1
global ballBox2
ballBox1[0] -= 1
ballBox1[1] += 0.5
ballBox2[0] -= 1
ballBox2[1] += 0.5
ballCenter[0] -= 1
ballCenter[1] += 0.5
ballCoords[2] -= 1
#Move downwards
if axisY > -0.008:
#root.event_generate('<<Down>>')
global ballBox1
global ballBox2
ballBox1[1] += 2.5
ballBox2[1] += 2.5
ballCenter[1] += 2.5
ballCoords[1] -= 1
#Move In
root.bind('<<LT>>', moveInFunc)
#Move Out
root.bind('<<RT>>', moveOutFunc)
#Move Left
root.bind('<<Left>>', moveLeftFunc)
#Move Right
root.bind('<<Right>>', moveRightFunc)
#Move Up
root.bind('<<Up>>', moveUpFunc)
#Move Down
root.bind('<<Down>>', moveDownFunc)
#Main loop
root.mainloop()
if __name__ == '__main__':
main()
Sorry for the really long code. I highlighted the area that I think is where the problem is, but I included the entire code because (as most code is) the entire program is heavily interconnected, and I wanted you guys to be able to test the program yourselves.