Kivy: How To Limit Simultaneous Touches to One? - python

I am using Kivy 1.9.1 and Python 3.5.2. My application breaks when more than one touch event is fired before the first has finished processing. I'm looking for some way to either restrict the number of touch events at a given time to one (something like the max_pointers attribute in the HTML5 engine Phaser) or to filter the touch events and only process the first. As far as I'm aware, the touch event doesn't hold this information about itself.
I don't believe the specifics of my code are relevant, but better safe than sorry:
def on_touch_down(self, touch):
x, y = touch.x, touch.y
x -= self.img_board.pos[0]
y -= self.img_board.pos[1]
if not (0 <= x <= self.img_board.size[0] and
0 <= y <= self.img_board.size[1]):
touch.ud['piece'] = None
return
file = int(x / self.square_size)
rank = int(y / self.square_size)
self.select((file, rank))
piece = Board.instance.at_square(self.selected)
touch.ud['piece'] = piece
if piece:
self.canvas.remove(piece.rect)
self.canvas.after.add(piece.rect)
def on_touch_move(self, touch):
piece = touch.ud['piece']
if piece:
if Board.instance.to_move == piece.color:
piece.rect.pos = (touch.x - piece.rect.size[0]/2,
touch.y - piece.rect.size[1]/2)
def on_touch_up(self, touch):
piece = touch.ud['piece']
if piece:
self.canvas.after.remove(piece.rect)
self.canvas.add(piece.rect)
if Board.instance.to_move != piece.color:
return
x, y = touch.x, touch.y
x -= self.img_board.pos[0]
y -= self.img_board.pos[1]
if not (0 <= x <= self.img_board.size[0] and
0 <= y <= self.img_board.size[1]):
self.update_geometry()
return
dest = Board.an_from_tup( (int(x / self.square_size),
int(y / self.square_size)) )
if dest in piece.get_valid_moves():
Board.instance.move(piece.position,dest)
self.select(dest)
self.update_geometry()

I was able to implement this by creating a TouchHandler widget:
class TouchHandler(Widget):
""" Non-display widget to handle touch order """
instance = None
def __init__(self):
super().__init__()
TouchHandler.instance = self
self.active = None
Then overriding Window's on_motion method prior to calling MyApp().run():
if __name__ == '__main__':
# Ignore new touches before first touch has resolved
TouchHandler()
def on_motion(self, etype, me):
if 'pos' in me.profile:
if etype == 'begin':
if not TouchHandler.instance.active:
TouchHandler.instance.active = me
Window.bind(on_motion=on_motion)
Window.size = (500,500)
MyApp().run()
For this to work, you need to manage your touch events very carefully and reset TouchHandler.instance.active to None when you're done with the touch in the on_touch_up method for any widget that will use the touch:
def on_touch_up(self, touch):
if touch != TouchHandler.instance.active:
return True # Signals Kivy to kill the event
piece = touch.ud['piece']
if piece:
# ...
self.update_geometry()
TouchHandler.instance.active = None

This is an answer, but I'm kind of afraid of it, I'm pretty sure it's bad programming practice but:
I created a global variable with touch_counter = 0, then in on_touch_down I referenced the global variable and then += 1 it, and in on_touch_up I -= 1 it. In on_touch_move I check if the touch_counter == 1 and then performed what I wanted it to do with only one touch.
This works with multitouch_sim, I realize this might mess up with actually multitouch devices, but so far so good.

Related

Python 3 Turtle - Simultaneous Press

So I followed the instructions here on how to take two inputs at the same time to execute a different function than either key press individually.
My code doesn't want to work but only the function that requires two key presses ('w', 'a'): upLeft and I can't figure out why. I tested my function in the provided solution and it worked. I can't seem to see any tangible differences between what I have here and what is provided in the link.
import turtle
import time
# Draw initial screen
wn = turtle.Screen()
wn.title("Cool Game Bro")
wn.bgcolor("grey")
wn.setup(width=800, height=600)
wn.tracer(0)
# main player character
character = turtle.Turtle()
character.speed(0)
character.shape("circle")
character.color("yellow")
character.penup()
character.goto(0, 0)
def process_events():
events = tuple(sorted(key_events))
if events and events in key_event_handlers:
(key_event_handlers[events])()
key_events.clear()
wn.ontimer(process_events, 200)
def Up():
key_events.add('w')
def Left():
key_events.add('a')
def Down():
key_events.add('s')
def Right():
key_events.add('d')
def charUp():
y = character.ycor()
y += 10
character.sety(y)
def charLeft():
x = character.xcor()
x -= 10
character.setx(x)
def charRight():
x = character.xcor()
x += 10
character.setx(x)
def charDown():
y = character.ycor()
y -= 10
character.sety(y)
def upLeft():
y = character.ycor()
y+=10
character.sety(y)
x = character.xcor()
x -=10
character.setx(x)
key_event_handlers = { \
('w',): charUp,\
('a',): charLeft,\
('d',): charRight,\
('s',): charDown,\
('w', 'a'): upLeft,\
}
key_events = set()
wn.onkeypress(Up, 'w')
wn.onkeypress(Left, 'a')
wn.onkeypress(Right, 'd')
wn.onkeypress(Down, 's')
wn.listen()
process_events()
while True:
wn.update()
Appreciate the help!
A set stores things alphabetically. Use
('a','w'): upLeft
and it will work fine.
BTW1, you could have learned this if you had just added print(events) in your process_events function, as I did.
BTW2, you don't need backslashes in your definition. Anything contained in parens, square brackets, or curly brackets can automatically be continued onto another line.

my code is not seeing a class variable (object)? when calling a different function within the same class

i am currently creating a python program using pygame. And am currently writing a class that ticks to see if any objects is in range.
this is the call within the program loop, it wants me to pass through the classname which i shouldnt have to do..... right?
self.AuraDetection([cat.pos, mouse.pos], cat, mouse)
Below is the function, the self.counter variable is not being recognised, even if the initlization of the variable is within the class INIT function.
def AuraDetection(self, animals, cat, mouse):
if abs(animals[0][0] - animals[1][0]) <= 150 and abs(animals[0][1] - animals[1][1]) <= 150 and self.counter == 0:
cat.StateChange()
self.counter = 1
Here is the init function
def __init__(self):
super(self)
screen = pg.display.get_surface()
self.width = 800
self.height = 600
self.fps = 60
self.counter = 0
all of these are within the same class.
https://github.com/freercurse/Boids/blob/master/main.py
here is a link to all of the code within this file, if you want a whole look

cx_Freeze Build of Tkinter Application Extremely Buggy

I recently created a small game using tkinter (python version 3.6.1) and froze it using cx_Freeze. The game has four buttons: an undo button, a restart button, a "find legal moves" button, and a "find best move button". The "find best move" button uses a shelve database to find the best move for the first three turns and a recursive function that traverses the move tree on the fly for the fourth turn and up. My code disables the buttons when they should not be used.
I made sure to include the necessary DLLs in the setup script and I was able to run the executable without errors. However, three of the buttons are disabled until the fourth turn (when the recursive function begins to be used) and the application is extremely buggy in many other ways. However, it works perfectly when I run the unfrozen version.
I honestly don't know what code snippets I would need to provide to you guys, as this issue has me utterly at a loss. The only clue I have is that the pyc files in the build differ in size from the unfrozen app. I know this is rather vague, but I do not know what specifics would be useful to give. Any help, if possible, would be greatly appreciated.
"Find best move" method:
def _find_best_move(self):
"""Finds best move possible for current game."""
if len(self.game.moves) <= 3:
with shelve.open("paths") as db:
best_paths = db[str(self.game.moves)]
best_path = choice(best_paths)
else:
self.path_finder(self.game)
best_path = self.path_finder.best_path
best_move = best_path[len(self.game.moves)]
best_move = (__class__._add_offset(best_move[0]), best_move[1])
return best_move
Updates Button State:
def update_gui(self):
"""Updates GUI to reflect current game conditions."""
legal_moves = self.game.find_legal_moves()
if self.game.moves:
self.undo_btn["state"] = "!disabled"
self.restart_btn["state"] = "!disabled"
self.best_move_btn["state"] = "!disabled"
else:
self.undo_btn["state"] = "disabled"
self.restart_btn["state"] = "disabled"
if legal_moves:
self.show_moves_btn["state"] = "!disabled"
else:
self.show_moves_btn["state"] = "disabled"
if legal_moves and self.game.moves:
self.best_move_btn["state"] = "!disabled"
else:
self.best_move_btn["state"] = "disabled"
My __init__ file:
initpath = os.path.dirname(__file__)
os.chdir(os.path.join(initpath, "data"))
PathFinder class (traverses move tree on the fly):
class PathFinder:
"""Provides methods to find move paths that meet various criteria.
Designed to be called after the player makes a move.
"""
_game = None
best_path = None
best_score = None
def __call__(self, game):
"""Call self as function."""
if not game:
self._game = DummyGame()
elif not isinstance(game, DummyGame):
self._game = DummyGame(game)
else:
self._game = game
moves = self._game.moves
self.possible_paths = dict.fromkeys(range(1,9))
root = Node(moves[-1])
self._find_paths(root)
self._find_paths.cache_clear()
found_scores = [score for score in self.possible_paths.keys() if
self.possible_paths[score]]
self.best_score = min(found_scores)
self.best_path = self.possible_paths[self.best_score]
#lru_cache(None)
def _find_paths(self, node):
"""Finds possible paths and records them in 'possible_paths'."""
legal_moves = self._game.find_legal_moves()
if not legal_moves:
score = self._game.peg_count
if not self.possible_paths[score]:
self.possible_paths[score] = self._game.moves.copy()
else:
children = []
for peg in legal_moves:
for move in legal_moves[peg]:
children.append(Node((peg, move)))
for child in children:
self._game.move(*child.data)
self._find_paths(child)
try:
self._game.undo()
except IndexError:
pass
Peg class:
class Peg(RawPen):
"""A specialized 'RawPen' that represents a peg."""
def __init__(self, start_point, graphics):
"""Initialize self. See help(type(self)) for accurate signature."""
self.graphics = graphics
self.possible_moves = []
super().__init__(self.graphics.canvas, "circle", _CFG["undobuffersize"],
True)
self.pen(pendown=False, speed=0, outline=2, fillcolor="red",
pencolor="black", stretchfactor=(1.25,1.25))
self.start_point = start_point
self.goto(start_point)
self.ondrag(self._remove)
self.onrelease(self._place)
def _remove(self, x, y):
"""Removes peg from hole if it has moves."""
if self.possible_moves:
self.goto(x,y)
def _place(self, x, y):
"""Places peg in peg hole if legal."""
if self.possible_moves:
target_holes = [tuple(map(add, self.start_point, move)) for move in
self.possible_moves]
distances = [self.distance(hole) for hole in target_holes]
hole_distances = dict(zip(distances, target_holes))
nearest_hole = hole_distances[min(hole_distances)]
if self.distance(nearest_hole) <= 0.45:
self.goto(nearest_hole)
peg = self.graphics._subtract_offset(self.start_point)
move = tuple(map(sub, self.pos(), self.start_point))
move = tuple(map(int, move))
self.graphics.game.move(peg, move)
self.start_point = self.pos()
else:
self.goto(self.start_point)
The frozen application is going to have a different value for __value__ then the unfrozen application. You will have to deal with that accordingly! This is a common issue that bites a lot of people. Anything that assumes that the module is found in the file system is going to stop working properly when frozen. The other gotcha is dynamic importing of modules.
The documentation covers this and other topics that will hopefully help you out!

How to save buildings at specific coordinates in python?

So I do know how to save the class's x,y coordinates but I don't know how to save buildings at the coordinates my player has been at. I'll attempt to make this more clear.
I'm making a text-based. To move your player you either type left,right,up,or down. It will therefore change your x and y accordingly.
Ex: To move up it adds 1 to the y value of the player class. player.yPos += 1 . However if the player goes to the point 0,1 and then 0,2 but moves back down to 0,1 and there was a building at the point 0,1 how do I make sure it's still there when the player goes back? I've been thinking I'll have to store all of the player's x,y movements in to a list. I don't know how to make the positions of that list equal the object that will be there though. If this doesn't make sense I can attempt rewording.
P.S. Please use the most simple logical explanation possible. Generally when I read something on stackoverflow I want to jump off of a cliff with how involved it is. (Basically, dumb it down for me please!)
class player:
Cnuts = 0
statPoints = 0
pStrength = 0
pConstitution = 0
pQuickness = 0
pIntelligence = 0
pStamina = 0
playerName = ''
Weapon = 0
Armour = 0
Shield = 0
inventory = []
xPos = 0
yPos = 0
#Building Code
class Entity:
id = 0
xPos = 0
yPos = 0
name = ''
description = ''
def __init__(self, id, xLocation, yLocation, name, description):
self.xLocation = xLocation
self.yLocation = yLocation
self.id = id
self.name = name
self.description = description
class Structure(Entity):
pass
I haven't decided what goes in to the Structure/Building class because I don't know what else it needs other than what Entity already has. I have another class for monsters that also inherits from Entity which is why I have it.
#Map code
isExploring = True
def Map():
while isExploring == True:
pInput = input('What direction would you like to go?')
if pInput == 'Up':
player.yPos += 1
elif pInput == 'Down':
player.yPos -= 1
elif pInput == 'Left':
player.xPos -= 1
elif pInput == 'Right':
player.xPos += 1
elif pInput == 'Diagonal Left':
player.xPos
player.yPos
elif pInput == 'Diagonal Right':
pass
elif pInput == 'Down Diag Left':
pass
elif pInput == 'Down Diag Right':
pass
Thanks for the help in advance!
I don't see code for a building, but I'm guessing the building will eventually inherit from Entity (Player should also inherit this class). An entity object has self.xLocation and self.yLocation, so this makes it a bit easier to implement a location aware player. So what you do is that the class you make for building has to implement the __hash__ method, so something like this.
class Building(Entity):
def __hash__(self):
return hash(tuple(self.xLocatioin, self.yLocation))
def __eq__(self, other):
return isinstance(other, Building) and hash(self) == hash(other)
The function is called __hash__ because python recognizes this special keyword as meaning that the building object can be placed in a dictionary. So whenever you try to place a Building object in a set or use it as a key for a dictionary, python will automatically call it's __hash__ method, and use that value to determine the position in which to place the object in the set/dictionary. Implementing hash usually means implementing __eq__ which is another magic function that python automatically calls when you compare 2 objects using the == operator.
The player class will then store each building it has visited in a set, which can then be queried to determine if a building has been visited before
class Player(Entity):
def __init__(self, *args):
super.__init__(self, args)
self.visited = set()
self.currLocation = tuple(self.xLocatioin, self.yLocation)
def visit(self, entity):
if not beenHere(entity):
self.visited.add(entity)
self.currLocation = tuple(entity.xLocatioin, entity.yLocation)
def beenHere(self, entity):
return entity in self.visited
And there you have it, now the player object can determine which building it has visited before or not

Object not behaving correctly

I'm using Livewires and pygame and one of my objects in the game that gives you extra lives is being mistaken as an asteroid object, and when the extra lives objects collides with the player it returns the 'Extra lives object has no attribute handle_caught' error message, so can I please have some help.
class Extralives(games.Sprite):
global lives
image = games.load_image('lives.png', transparent = True)
speed = 2
def __init__(self,x,y = 10):
""" Initialize a asteroid object. """
super(Extralives, self).__init__(image = Extralives.image,
x = x, y = y,
dy = Extralives.speed)
def update(self):
""" Check if bottom edge has reached screen bottom. """
if self.bottom>games.screen.height:
self.destroy()
self.add_extralives
def add_extralives(self):
lives+=1
The asteroid class:
class Asteroid(games.Sprite):
global lives
global score
"""
A asteroid which falls through space.
"""
image = games.load_image("asteroid_med.bmp")
speed = 1.7
def __init__(self, x,image, y = 10):
""" Initialize a asteroid object. """
super(Asteroid, self).__init__(image = image,
x = x, y = y,
dy = Asteroid.speed)
def update(self):
""" Check if bottom edge has reached screen bottom. """
if self.bottom>games.screen.height:
self.destroy()
score.value+=10
def handle_caught(self):
if lives.value>0:
lives.value-=1
self.destroy_asteroid()
if lives.value <= 0:
self.destroy_asteroid()
self.end_game()
def destroy_asteroid(self):
self.destroy()
part of the player class which handles the collisions:
def update(self):
""" uses A and D keys to move the ship """
if games.keyboard.is_pressed(games.K_a):
self.x-=4
if games.keyboard.is_pressed(games.K_d):
self.x+=4
if self.left < 0:
self.left = 0
if self.right > games.screen.width:
self.right = games.screen.width
self.check_collison()
def ship_destroy(self):
self.destroy()
def check_collison(self):
""" Check if catch pizzas. """
global lives
for asteroid in self.overlapping_sprites:
asteroid.handle_caught()
if lives.value <=0:
self.ship_destroy()
for extralives in self.overlapping_sprites:
extralives.add_extralives()
Here is your problem:
for asteroid in self.overlapping_sprites:
asteroid.handle_caught()
if lives.value <=0:
self.ship_destroy()
The fact that you call your loop variable asteroid does not mean that it's magically only going to ever be an asteroid. Not if you have other kinds of objects you can collide with! overlapping_sprites is all overlapping sprites, not just asteroids. At some point asteroid is an ExtraLives object. When you try to call handle_caught() on it, this obviously fails because ExtraLives doesn't have a handle_caught() method.
The simplest solution here is to rename add_extralives to handle_caught on your ExtraLives class. After all, you're doing the same thing: handling the situation where you collide with (or "catch") the object, it's just a different kind of object so the result needs to be different, which you specify by providing different code. Being able to implement entirely different kinds of behavior by calling the same methods (called "polymorphism") is kinda the whole point of object-oriented programming.
The following loop has a similar problem, in that you're calling add_extralives() on objects that might not be of type ExtraLives. Fortunately you can remove this code since you're already handling this situation by renaming add_extralives to handle_caught.
for extralives in self.overlapping_sprites:
extralives.add_extralives()

Categories