Why is the math of my stacking game not working? - python

This is my first pygame project, and it's a stacking game. I made the game with the idea of any piece not touching the base is chopped off, and it goes on until your piece gets too small or if you reach the top of the screen. The problem with my game here, is that it works if you only stack pieces to the right. However, it falls apart if you start stacking to the left. I checked the math many times already, but it doesn't work still. It calculates the part that is chopped off by taking the base x position of the piece on the bottom, and then subtracting or adding the x position of the piece on top.
import pygame
import time
pygame.init()
win=pygame.display.set_mode((800,800))
pygame.display.set_caption("Stacking Game")
length=200 #The length of you CURRENT piece, the one that is moving
base=0 #X pos of the PREVIOUS stacked piece
x=0 #X pos of current piece
y=750 #y pos of current piece
blocks=0 #How many blocks have been stacked
difference=0
speed=5
direction=1
running=1
lengthbase=0 #Length of the PREVIOUS stacked piece
while (running==1):
pygame.time.delay(10)
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
if direction==1:
if x>800-length:
direction=0
else:
x+=speed
else:
if direction==0:
if x<0:
direction=1
else:
x-=speed
pygame.draw.rect(win,(0),(0,0,800,y+50)) #Blacks out the screen from the current piece to the top, leaving previously stacked pieces
pygame.draw.rect(win,(255,0,0),(x,y,length,50))
if blocks==16: #16 is the maximum number of blocks on the screen
pygame.quit()
print("You win!")
if event.type==pygame.KEYDOWN and event.key==pygame.K_SPACE:
if blocks==0: #Since the math is all based off the previous piece's length and position, this inserts the information of the first piece. We now know the position and length of the first stacked piece
base=x
lengthbase=200
else:
if x>base and x<(base+lengthbase): #The current piece should always be the same size and the previous piece, so it can either be stacked perfectly, to the right, or to the left. This calulates data when it is stacked to the right.
difference=(x+length)-(base+lengthbase)
length=length-difference
pygame.draw.rect(win,(0),(0,0,800,y+50))
pygame.draw.rect(win,(255,0,0),(x,y,length,50)) #Draws the new piece at the same position as the current piece, but with the new length
else:
if (x+length)>base and (x+length)<(base+lengthbase): #Calculates if the piece is stacked to the left.
difference=base-x
length=length-difference
pygame.draw.rect(win,(0),(0,0,800,y+50))
pygame.draw.rect(win,(255,0,0),(x+difference,y,length,50)) #If it was drawn on x, the stacked piece and the one below it would not be aligned. It has to move a distance of difference
else:
pygame.quit()
print("You lost.")
base=x #The stacked piece then becomes the bases for the next piece
lengthbase=length
speed+=1
blocks+=1
y-=50
time.sleep(0.5)
pygame.display.update()

You have to evaluate if the ranges [x1, x1+w1] and [x2, x2+w2] are overlapping.
Not overlapping:
x1 x1+w1
+----+
+----+
x2 x2+w2
x1 x1+w1
+----+
+----+
x2 x2+w2
Overlapping
x1 x1+w1
+--------------+
+----+
x2 x2+w2
x1 x1+w1
+----+
+---------------+
x2 x2+w2
x1 x1+w1
+---------+
+----------+
x2 x2+w2
x1 x1+w1
+----------+
+----------+
x2 x2+w2
This mean, that the ranges are overlapping if
x1 < x2+w2 and x2 < x1+w1
You don't need 2 separate cases for left and right. Just evaluate whether the areas overlap. Calculate the beginning and the end of the common area with min and max:
if x < base + lengthbase and base < x + length:
start = max(x, base)
end = min(x+length, base+lengthbase)
x = start
length = end - start
pygame.draw.rect(win,(0),(0,0,800,y+50))
pygame.draw.rect(win,(255,0,0),(x,y,length,50))
else:
pygame.quit()
print("You lost.")
This can be further simplified:
start = max(x, base)
end = min(x+length, base+lengthbase)
if start < end:
x, length = start, end - start
pygame.draw.rect(win,(0),(0,0,800,y+50))
pygame.draw.rect(win,(255,0,0),(x,y,length,50))
else:
# [...]
Side note: You've to handle the events in the event loop, rather than after the event loop:
while running==1:
pygame.time.delay(10)
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
if event.type==pygame.KEYDOWN and event.key==pygame.K_SPACE:
if blocks==0:
base=x
lengthbase=200
else:
start = max(x, base)
end = min(x+length, base+lengthbase)
if start < end:
x, length = start, end - start
pygame.draw.rect(win,(0),(0,0,800,y+50))
pygame.draw.rect(win,(255,0,0),(x,y,length,50))
else:
pygame.quit()
print("You lost.")
base, lengthbase = x, length
speed += 1
blocks += 1
y -= 50
time.sleep(0.5)

Related

Issue with Multiple condition if statement Python

I'm writing a program that moves my mouse (using pyautogui lib) if it has not been moved in x amount of seconds. I take the X,Y coordinates twice once at the start and then again after the time delay, then compare both X and Y values against the previous one. I've having issues with my if statement which in theory should do the above but after testing it out it doesn't work as expected. Can anyone suggest any edits I can a make to fix this simple issue.
Here's my code:
#!/usr/bin/env python3
import pyautogui
import time
currentMouseX, currentMouseY = pyautogui.position() #Grabs X,Y mouse position
print("position X1 is", currentMouseX)
print("position Y1 is", currentMouseY)
X1 = currentMouseX
Y1 = currentMouseY
time.sleep(3)
currentMouseX2, currentMouseY2 = pyautogui.position() #Grabs second X,Y position after 3 seconds
X2 = currentMouseX
Y2 = currentMouseY
print("position X2 is", currentMouseX2)
print("position Y2 is", currentMouseY2)
**if ((X1 == X2) and (Y1 == Y2)):
print ("!!! MOVE MOUSE !!!")
else:
print("Mouse does not need to be moved")**
FYI: I've left the if statement very simple as I'd like it working before I continue with the program. Any help is very much appreciated.
Note: Saying that your code does not work as expected makes no sense unless you explain what it is supposed to do ALONG WITH WHAT IT IS ACTUALLY DOING.
Having said that, looking at your code I assume your problem is that you always get the result "!!! MOVE MOUSE !!!", even if you did move your mouse.
If you look at your code carfully you will notice that X1 and X2 will always be the same, and Y1 and Y2 also, because you assign them using:
X1 = currentMouseX
Y1 = currentMouseY
and
X2 = currentMouseX
Y2 = currentMouseY
without overwriting currentMouseY. Instead, you load the second coordinates into currentMouseX2 and currentMouseY2.
In short your code uses way to many unnessecary assignments. Instead, do the following:
#!/usr/bin/env python3
import pyautogui
import time
prev = pyautogui.position() #Grabs X,Y mouse position
print("position X1 is", prev[0])
print("position Y1 is", prev[1])
time.sleep(3)
after = pyautogui.position() #Grabs second X,Y position after 3 seconds
print("position X2 is", after[0])
print("position Y2 is", after[1])
if (prev == after):
print ("!!! MOVE MOUSE !!!")
else:
print("Mouse does not need to be moved")
Rather than testing for equality, it might be better to test whether the difference is below some threshold value:
moveThresh = 4 # (or suitable small number)
XMove = X2 - X1
YMove = Y2 - Y1
if abs(XMove) < moveThresh and abs(YMove) < moveThresh:
# treat tiny moves as no move
print("The mouse is effectively stationary & the cat is bored")
else:
print("The mouse is moving & the cat is interested")
etc.
Unless you're hooking up some interesting hardware, I doubt you'll be moving the mouse - only the mouse pointer.

Why does my pygame code become painfully slow after a certain time? Is there a way to make it run faster?

I wrote a program to model a phenomenon called diffusion limited aggregation, using the random motion of squares in pygame. The idea is that there is a stem and every particle (square) that touches it sticks to it and becomes part of the stem.
The code seems to work, but after like 30 seconds to a minute it starts to slow down quite a bit. I cannot figure out why.
import pygame
import random
#changing the row number will change the size of the squares, and bassically the size of the invisible 'array'
width = 1000
rows = 500
d = width//rows
e = {}
squares = []
accreted = []
#note: all positions are noted in array-like notation (a matrix of dimensions rows x rows)
#to convert it back to normal notation, do (square.position[0] * d, square.position[1] * d)
class square:
def __init__(self, position):
self.position = (position)
#method to move a square in a random direction (no diagonal) (brownian motion)
def move(self):
a = random.randint(0, 3)
if a == 0:
new_posi = (self.position[0] + 1)
new_posj = (self.position[1])
elif a == 1:
new_posi = (self.position[0] - 1)
new_posj = (self.position[1])
elif a == 2:
new_posi = (self.position[0])
new_posj = (self.position[1] + 1)
else:
new_posi = (self.position[0])
new_posj = (self.position[1] - 1)
if new_posj<0 or new_posi<0 or new_posi>rows or new_posj>rows:
self.move()
else:
self.position = (new_posi, new_posj)
pygame.draw.rect(win, (255, 255, 255), [new_posi * d, new_posj * d, d, d])
def accrete(square):
accreted.append(square)
if square in squares:
squares.remove(square)
def redrawWindow(win):
win.fill((0, 0, 0))
pygame.draw.rect(win, (255, 255, 255), [stem.position[0] * d, stem.position[1] * d, d, d])
for square in squares:
square.move()
# here we make it so that every square that touches the stem stops moving, then a square that touches this square stops moving, etc.
for accret in accreted:
if square.position[1] == accret.position[1]+1 and square.position[0] == accret.position[0]:
accrete(square)
elif square.position[1] == accret.position[1]-1 and square.position[0] == accret.position[0]:
accrete(square)
elif square.position[1] == accret.position[1] and square.position[0] == accret.position[0]+1:
accrete(square)
elif square.position[1] == accret.position[1] and square.position[0] == accret.position[0]-1:
accrete(square)
for accret in accreted:
pygame.draw.rect(win, (255, 255, 255), [accret.position[0] * d, accret.position[1] * d, d, d])
pygame.display.update()
def main():
global win
win = pygame.display.set_mode((width, width))
clock = pygame.time.Clock()
while True:
# pygame.time.delay(5)
# clock.tick(64)
redrawWindow(win)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
#by changing the range here, we change how many squares are created
for i in range(5000):
e["accreted{0}".format(i)] = square((random.randint(0, rows), random.randint(0, rows)))
squares.append(e["accreted{0}".format(i)])
#a stem to start accretion from
stem = square((rows/2, rows/2))
accrete(stem)
main()
I've watched your simulation run for a while on my MacBook Pro. It seems that on my system, it takes quite a bit longer than a minute...maybe more like 5 or so...before it starts to quite obviously slow down. But it does nonetheless.
I think the problem is that you are building this "accreted" structure during your simulation, and due to this, the number of "accreted" squares (those stored in the accreted list) keeps increasing. For each iteration of your program, your code needs to compare the position of each live square against the position of each "accreted" square. So over time, the number of comparisons you have to do continues to grow.
You likely need to find a way to optimize your algorithm if you want to be able to maintain the update speed (the frame rate) as the sim progresses. You need to figure out how to be smarter about performing your comparisons to somehow avoid this geometric progression in iteration time that occurs as the structure you're building grows.
UPDATE AND POSSIBLE OPTIMIZATION: I see a pretty simple optimization that you could add to your code to greatly speed it up. What you can do is maintain a bounding box around your "accreted" squares. When you add a new square to that list, you increase the size of the bounding box, if necessary, so that it contains the new square. Now, when you first check for a collision between a live square and an the list of accreted squares, you can first check for if the live square is within the bounding box of the accreted squares (with a little extra margin as appropriate) before testing for a collision between that square and any one accreted squares. This would let you immediately rule out collisions between most of the live squares and the accreted squares with just one collision test for each live square. This should have the effect of allowing your code to stay about as fast in later rounds as it is in the early rounds, since most of the live squares will always be trivially rejected as collision candidates regardless who big the accreted structure gets.
UPDATE 2: What I describe is definitely what's going on with your code. I added a little code to count the number of collision tests you perform in each round of your sim. Here's the number of tests being performed at one second intervals, along with how long one iteration of your sim is taking, in seconds:
0 5000 0.023629821000000106
1 9998 0.023406135000000106
2 24980 0.03102543400000002
...
30 99680 0.07482247300000111
31 99680 0.08382184299999551
...
59 114563 0.08984024400000123
60 114563 0.087317634999998
The first iteration of your code does 5000 hit tests, as expected, and a single iteration of your sim takes about .023 seconds. After a minute, your sim is having to do more than 20 times as many tests per iteration, 114563, and now a single iteration is taking .087 seconds. This problem just keeps growing, and your code just keeps slowing down. (It's interesting to note that most of the "progress" of your sim up to one minute has occurred in the first 30 seconds. For this run, only 3 accretes occurred in the second 30 second interval.)
The first and probably best optimization is to keep a list of "forbidden" squares that will trigger the freeze of a particle instead of iterating over all positions in accreted multiple times.
So e.g. when we start with the first stem particle (or square, or whatever you call it), we also store the positions above, beneath, left and right of that particle's position in a set. It's important to use a set because looking up items in a set is much, much faster that using a list.
After moving a square, we now check if that square's new position is in this set. If it is, we add all adjacent positions to that set, also.
The next thing we can improve is the list of squares itself. Instead of removing a freezed square from the list, we create a new list every frame and add all squares that are not freezed this turn. (Your code is actually buggy by not making a copy of the list of squares and iterating over that copy while removing items from the original list) I'll use a deque since adding to it is slightly faster that a regular list.
Another bottleneck is the huge amount of random numbers you create each frame. random.randint() becomes painfully slow. We could create a list of random numbers at the start of the script and use that so we don't have to create new random numbers while running.
We could also change the drawing. Using pygame.draw.rect 5000 times is also quite slow. Let's create a surface and blit it with pygame's new batch function Surface.blits (I guess using pygame.surfarray to manipulate the screen surface directly would be even faster).
In the code below I also implemented the bounding box suggested by CryptoFool, because why not, but the biggest speed up is using a set as I described above.
With these changes, I get ~200 FPS without any slowdown over time:
import pygame
import numpy as np
import random
from collections import deque
def get_rand_factory():
length = 100000000
sample = np.random.randint(1, 5, length).tolist()
index = -1
def inner():
nonlocal index
index += 1
if index == length:
index = 0
return sample[index]
return inner
get_rand = get_rand_factory()
def move(x, y, rows):
dx, dy = x, y
a = get_rand()
if a == 1: dx += 1
elif a == 2: dx -= 1
elif a == 3: dy += 1
else: dy -= 1
if dx<0 or dy<0 or dx>rows or dy>rows:
return move(x, y, rows)
return dx, dy
def get_adjacent(x, y):
for dx, dy in (1, 0), (-1, 0), (0, 1), (0, -1):
yield x + dx, y + dy
def get_bounds(positions):
min_x, min_y, max_x, max_y = 9999, 9999, 0, 0
for x, y in positions:
min_x = min(min_x, x)
min_y = min(min_y, y)
max_x = max(max_x, x)
max_y = max(max_y, y)
return min_x, min_y, max_x, max_y
def main():
width = 1000
rows = 500
d = width//rows
squares = deque()
accreted = set()
adjacent_accreted = set()
win = pygame.display.set_mode((width, width))
clock = pygame.time.Clock()
for i in range(5000):
pos = (random.randint(0, rows), random.randint(0, rows))
squares.append(pos)
stem = (rows/2, rows/2)
accreted.add(stem)
adjacent_accreted.add(stem)
for adj in get_adjacent(*stem):
adjacent_accreted.add(adj)
rect_white = pygame.Surface((d, d))
rect_white.fill('white')
rect_blue = pygame.Surface((d, d))
rect_blue.fill((255, 0, 255))
bounds = get_bounds(adjacent_accreted)
min_x, min_y, max_x, max_y = bounds
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
return
win.fill((0, 0, 0))
new_state = deque()
for x, y in squares:
die = False
new_pos = move(x, y, rows)
if min_x <= new_pos[0] <= max_x and min_y <= new_pos[1] <= max_y:
if new_pos in adjacent_accreted:
accreted.add(new_pos)
adjacent_accreted.add(new_pos)
for adj in get_adjacent(*new_pos):
adjacent_accreted.add(adj)
die = True
bounds = get_bounds(adjacent_accreted)
min_x, min_y, max_x, max_y = bounds
if not die:
new_state.append(new_pos)
squares = new_state
win.blits(blit_sequence=((rect_blue, (pos[0]*d, pos[1]*d)) for pos in accreted))
win.blits(blit_sequence=((rect_white, (pos[0]*d, pos[1]*d)) for pos in squares))
pygame.draw.rect(win, (0, 255, 255), [bounds[0] * d, bounds[1] * d, (bounds[2]-bounds[0]) * d, (bounds[3]-bounds[1]) * d], 1)
pygame.display.update()
pygame.display.set_caption(f'{clock.get_fps():.2f} {len(squares)=} {len(accreted)=}')
clock.tick()
main()
Have a look at your code:
def accrete(square):
accreted.append(square)
if square in squares:
squares.remove(square)
squares is a list containing up to 5000 items. Searching for any content needs up to 5000 comparisons because there is no index and all items have to be checked until it is found in the list. Use a set instead if the entries are unique and the order does not care. A set in indexed and searching for an item runs very fast.

Smooth Jump over different FPS

I've created a game, but I have problems controlling the jump of the player. This code is a simplified version only showing the jump problem. Keep in mind that in the game itself the FPS may vary in mid jump. I've separated the jump code so it's the easier to identify, and also with the UP/DOWN arrows you can change the FPS to make tests.
Problem
The higher the FPS the smaller the jumps are, and the lower the FPS are the higher the jumps.
Expected Result
The jump reach the same height over many different FPS. Example: 30 and 120 FPS
Code
import pygame
Screen = pygame.display.set_mode((250,300))
Clock = pygame.time.Clock()
X = 50; Y = 250
FPS = 60; Current_FPS = FPS
Move = 480 / Current_FPS; Dir = "Up"
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
exit()
if pygame.key.get_pressed()[pygame.K_UP]: FPS += 10 / Current_FPS
elif pygame.key.get_pressed()[pygame.K_DOWN] and FPS > 2: FPS -= 10 / Current_FPS
pygame.display.set_caption("FPS: "+str(int(FPS)))
Screen.fill((255,255,255))
X += 120 / Current_FPS
#---------------- JUMP CODE ---------------------#
if Dir == "Up":
if Move <= 0.0: Dir = "Down"
else:
Move -= 10 / Current_FPS
Y -= Move
else:
#RESET \/
if Y >= 250:
Dir = "Up"
X = 50; Y = 250
Move = 480 / Current_FPS; Dir = "Up"
#RESET /\
else:
Move += 120 / Current_FPS
Y += Move
#--------------------------------------------------#
pygame.draw.circle(Screen,(0,0,0),(int(X),int(Y)),5)
pygame.display.update()
Current_FPS = 1000.0 / Clock.tick_busy_loop(FPS)
You should set your initial jump velocity to be independent of frame rate, i.e:
Move = 480
Note that when you update the velocity (or in your case, it looks, speed) you do need to divide by the frame rate, since you are essentially multiplying by the time interval: v ~ u + a*dt. The same applies when updating the position, so this should be Y += Move / Current_FPS.
There are a couple of other things worth mentioning. Why do you track the direction variable? Why not just have your variable Move be the velocity. That way you would just need: Y += Move / Current_FPS and have positive/negative values indicate the direction. Also, your gravity is currently a lot stronger on the way down than on the way up, but this could be entirely deliberate!

Pygame making an object chase the cursor

Been at this for the past few hours, trying to make a small program where an image chases the cursor around. So far I've managed to make it so that the image is directly on top of the cursor and follows it around that way. However what I need is for the image to actually "chase" the cursor, so it would need to initially be away from it then run after it until it's then on top of the mouse.
Basically hit a wall with whats going wrong and what to fix up, here's what I've gotten so far:
from __future__ import division
import pygame
import sys
import math
from pygame.locals import *
class Cat(object):
def __init__(self):
self.image = pygame.image.load('ball.png')
self.x = 1
self.y = 1
def draw(self, surface):
mosx = 0
mosy = 0
x,y = pygame.mouse.get_pos()
mosx = (x - self.x)
mosy = (y - self.y)
self.x = 0.9*self.x + mosx
self.y = 0.9*self.y + mosy
surface.blit(self.image, (self.x, self.y))
pygame.display.update()
pygame.init()
screen = pygame.display.set_mode((800,600))
cat = Cat()
Clock = pygame.time.Clock()
running = True
while running:
screen.fill((255,255,255))
cat.draw(screen)
for event in pygame.event.get():
if event.type == QUIT:
pygame.quit()
sys.exit()
pygame.display.update()
Clock.tick(40)
Probably not in the best shape of coding, been messing with this for just over 5 hours now. Any help is much appreciated! Thanks :)
Assuming you want the cat to move at a fixed speed, like X pixels per tick, you need to pick a new position X pixels toward the mouse cursor. (If you instead want the cat to move slower the closer it gets, you'd instead pick a position a certain % of the way between the current position and the mouse cursor. If you want it to move faster the closer it gets, you need to divide instead of multiply. And so on. But let's stick with the simple one first.)
Now, how do you move X pixels toward the mouse cursor? The usual way of describing this is: You find the unit vector in the direction from the current position to the cursor, then multiply it by X, and that gives you the steps to add. And you can reduce that to nothing fancier than a square root:
# Vector from me to cursor
dx = cursor_x - me_x
dy = cursor_y - me_y
# Unit vector in the same direction
distance = math.sqrt(dx*dx + dy*dy)
dx /= distance
dy /= distance
# speed-pixel vector in the same direction
dx *= speed
dy *= speed
# And now we move:
me_x += dx
me_y += dy
Note that me_x and me_y are going to be floating-point numbers, not integers. That's a good thing; when you move 2 pixels northeast per step, that's 1.414 pixels north and 1.414 pixels east. If you round that down to 1 pixel each step, you're going to end up moving 41% slower when going diagonally than when going vertically, which would look kind of silly.

Dual Keyboards/Joysticks in pygame [duplicate]

I am trying to create a project that I have made before but apart from this time I am going to be using a play-station one remote I was given for free from my school. The problem that when I move the joystick upwards and downwards it shows the same coordinates.(If you do not understand what I mean then look at the picture below). Then also I am not sure what I wold need to put into the if statement so that it checks if the joystick is upwards or downwards. I am also having trouble thinking on how you would check if the joystick is going in no direction.
I have already tried using an if statement where if the joystick is more than one number and less than another one (the first number being in the top half of the joystick and the other number meaning that it is in the bottom half of the joystick it will move downwards. The current if statement does not give off any errors but does not work. I have tried an if statement to check if it is in the middle but I am not too sure about it.
joystick_count = pygame.joystick.get_count()
if joystick_count == 0:
# No joysticks!
print("Error, I didn't find any joysticks.")
else:
# Use joystick #0 and initialize it
joystick = pygame.joystick.Joystick(0)
joystick.init()
if pygame.joystick.Joystick(0).get_axis(0) >= -0.0 and pygame.joystick.Joystick(0).get_axis(0) <= 0.0:
player_one.speed_y = 5
elif pygame.joystick.Joystick(0).get_axis(0) > -0.1 and pygame.joystick.Joystick(0).get_axis(0) < -0.9:
player_one.speed_y = -5
elif pygame.joystick(0).get_axis(0) == 0.0:
player_one.speed_y = -5
#The first if statement checks if the joystick is up and the second one
#checks if the joystick is downwards
# the middle one checks if the if statement is in the middle (not too sure)
#player one and two speed is what gets added on each time
The actual results that are that the sprite does not move when the joystick is moved downwards.
Joystick axis
First ensure that you have a joystick, by getting the number of joysticks by pygame.joystick.get_count(). Initialize the joystick by pygame.joystick.Joystick.init:
joystick = None
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
Once a joystick is initialized, ist axis value can be get by pygame.joystick.Joystick.get_axis. The value returned by this function is in range [-1, 1]. -1 for the maximum negative tilt and +1 for the maximum positive tilt.
Note, each analog stick of a gamepad or joystick has 2 axis, one for the horizontal direction and 1 for the vertical direction. Since the amount of the value returned by get_axis() depends on the tilting of the analog stick you should multiply the speed by the value.
Further you should ignore values near 0 for the dead center, because of the inaccuracy of the hardware. This can be don by a simple check using the built in function abs(x) e.g. abs(axisval) > 0.1:
if joystick:
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
player_one.speed_x = 5 * axis_x
if abs(axis_y) > 0.1:
player_one.speed_y = 5 * axis_y
See the following simple demo app:
import pygame
pygame.init()
size = (800,600)
screen = pygame.display.set_mode(size)
clock = pygame.time.Clock()
pos = [size[0]/2, size[1]/2]
speed = 5
joystick = None
done = False
while not done:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key==pygame.K_RETURN:
done = True
if joystick:
axis_x, axis_y = (joystick.get_axis(0), joystick.get_axis(1))
if abs(axis_x) > 0.1:
pos[0] += speed * axis_x
if abs(axis_y) > 0.1:
pos[1] += speed * axis_y
else:
if pygame.joystick.get_count() > 0:
joystick = pygame.joystick.Joystick(0)
joystick.init()
print("joystick initialized")
screen.fill((0, 0, 255))
pygame.draw.rect(screen, (255,255,255), (*pos, 10, 10))
pygame.display.flip()

Categories

Resources