Execute only once in python - python

So in my game I have a class called MovementService. This class handles moving an object when the uses presses an arrow key. However, when you press the up arrow 5 times in a row real quick, the object will move one square 5 times. This feels weird, because you're already done with pressing, but the character is still moving.
So I went and added some code to the class to try and prevent that. But now the movement is only executed once. But thing is, it's the first movement. How can I make sure it's the last press?
class MovementService():
lastExecutionEpoch = 0
minimumDifference = 1
def moveUp(self):
self.execute('MOVEUP')
def moveDown(self):
self.execute('MOVEDOWN')
def execute(self, movement):
if self.lastExecutionEpoch < (int(time.time()) - self.minimumDifference):
self.lastExecutionEpoch = int(time.time())
...
Do the actual movement
...

Related

Moving object when button clicked- PYQT

I’ve been trying to make an object move between three locations upon clicking a button. This is the code that I have now
def objectMove():
If window.button.pressed():
window.object1.setGeometry(200,120,91,91)
window.object1.setGeometry(1,120,91,91)
window.object1.setGeometry(90,120,91,91)
window.button.clicked.connect(objectMove)
My intention for this code was to have an object move to these three locations every time the button is clicked and the button can only be clicked 9 times before the screen times out. But I’m unsure how I could fix this
hold qrects of positions in dict under self_def_init_
self.val = 0
self.val_dict = {0:QRect(200,120,91,91),1:QRect(200,120,91,91),2:QRect(200,120,91,91)}
and update your method as below code
def objectMove():
windowObject.setGeometry(self.val_dict[self.val])
self.val += 1
if self.val == 3:
self.val = 0

Updating object on Python < arcade library >

I'm currently coding in some assignment.
I create a class named Ship and created some methods to make the object class ship be able to move.
class Ship():
def __init__(self):
self.center.x = 400
self.center.y = 300
self.velocity.dx = .25
self.velocity.dy = .25
def advance_down(self):
self.center.y = self.center.y - self.velocity.dy
This is my code
def check_keys(self):
"""
This function checks for keys that are being held down.
You will need to put your own method calls in here.
"""
if arcade.key.DOWN in self.held_keys:
self.ship1.advance_down()
advance down just changes the position
def on_key_press(self, key: int, modifiers: int):
"""
Puts the current key in the set of keys that are being held.
You will need to add things here to handle firing the bullet.
"""
if key == arcade.key.DOWN:
self.held_keys.add(key)
This adds the current key being pressed to the set of self.held_keys.
I'm calling an update of the positon.
def update(self, delta_time):
"""
Update each object in the game.
:param delta_time: tells us how much time has actually elapsed
""
self.ship1.advance_down()
when I run the code I'm able to display everything just fine but it's not doing anything once I press my keys.
Any ideas why?

How do I program a double key press to make a non-modifier key behave like a modifier key within my program?

I am writing a typing program that includes many more characters than are available on a standard keyboard. In order to achieve this I need to transform some of the alphabet keys into modifier keys CTRL+A. For example f+j would output a. Typing f then j is slow for the user, I need them to be able to press f and j at the same time and receive one output. It's fine (preferable even) if some of the keyboard's normal functionality is stopped while the program is running.
I have looked into pygame Keydown, but it only seems to have functions for increasing key repeat and not stopping key output. Pyglet is also a possibility, but it doesn't have exact documentation on how I could make additional modifier keys. The only way I can figure out is to be constantly scanning the whole keyboard to see if any keys are pressed, but that won't determine the order the keys are pressed in and will create errors for the user, as the user pressing f then j would be read the same as the user pressing j then f and I need only the f then j combo to be understood as a keystroke by the system.
Here's a Pyglet version of how you could do it.
I based it on common GUI class that I use often here on SO because it's modular and easier to build on without the code getting messy after 40 lines.
import pyglet
from pyglet.gl import *
key = pyglet.window.key
class main(pyglet.window.Window):
def __init__ (self):
super(main, self).__init__(800, 800, fullscreen = False)
self.x, self.y = 0, 0
#self.bg = Spr('background.jpg')
self.output = pyglet.text.Label('',
font_size=14,
x=self.width//2, y=self.height//2,
anchor_x='center', anchor_y='center')
self.alive = 1
self.pressed = []
self.key_table = {213 : 'a'}
def on_draw(self):
self.render()
def on_close(self):
self.alive = 0
def on_key_release(self, symbol, modifiers):
if symbol == key.LCTRL:
pass # Again, here's how you modify based on Left CTRL for instance
## All key presses represents a integer, a=97, b=98 etc.
## What we do here is have a custom key_table, representing combinations.
## If the sum of two pressed matches to our table, we add that to our label.
## - If no match was found, we add the character representing each press instead.
## This way we support multiple presses but joined ones still takes priority.
key_values = sum(self.pressed)
if key_values in self.key_table:
self.output.text += self.key_table[key_values]
else:
for i in self.pressed:
self.output.text += chr(i)
self.pressed = []
def on_key_press(self, symbol, modifiers):
if symbol == key.ESCAPE: # [ESC]
self.alive = 0
elif symbol == key.LCTRL:
pass # Modify based on left control for instance
else:
self.pressed.append(symbol)
def render(self):
self.clear()
#self.bg.draw()
self.output.draw()
self.flip()
def run(self):
while self.alive == 1:
self.render()
# -----------> This is key <----------
# This is what replaces pyglet.app.run()
# but is required for the GUI to not freeze
#
event = self.dispatch_events()
x = main()
x.run()
It might look like a lot of code, especially to the Pygame answer. But you could condense this down to ~15 lines as well, but again, the code would get messy if you tried to build on it any further.
Hope this works. Now I haven't thought the math through on this one.. It might be possible that two duplicate key combinations will produce the same value as another key representation, simply replace the dictionary keys 213 for instance with a tuple key such as self.key_table = {(107, 106) : 'a'} which would represent k+j
Few benefits:
No need to keep track of delay's
Fast and responsive
Any key could be turned into a modifier or map against custom keyboard layouts, meaning you could turn QWERTY into DWORAK for this application alone.. Not sure why you would want that, but hey.. None of my business :D
Overrides default keyboard inputs, so you can intercept them and do whatever you want with them.
Edit: One cool feature would be to register each key down but replace the last character with the joined combination.. Again this is all manual works since a keyboard isn't meant to do double-key-representations, and it's more of a graphical idea.. But would be cool :)
Here is some simple code to print keys pressed in quick succession, written in Python 2. It should be able to easily be modified to suit your needs:
import pygame, sys
pygame.init()
screen = pygame.display.set_mode([500,500])
clock = pygame.time.Clock()
combokeys = []
timer = 0
ACCEPTABLE_DELAY = 30 #0.5 seconds
while 1:
clock.tick(60)
timer += 1
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if timer <= ACCEPTABLE_DELAY:
combokeys.append(event.unicode)
else:
combokeys = [event.unicode]
timer = 0
print combokeys
I have not been able to test this code (working at school computer), so please notify me in the comments if something did not work so I can fix it.
You can change the value given for ACCEPTABLE_DELAY to change the delay before something is considered a different key combination. The delay should be (ACCEPTABLE_DELAY/60) seconds.

Timed Threaded function as an attribute in a class

So I am making a text based adventure game. I am working on the engine right now and I am stuck after long hours searching for a solution for this problem.
I have a class called use_action. One of the arguments for that class is a name of a function. I would like to be able to create this action and have a possible custom function incase the item that calls this use_action does something specific.
The custom function I am working with right now is where the player is hurt and is losing 5 HP every so many seconds.
This should start when he uses a specific item and then stops when he uses the medicine that will link to the stop function. The problem I have is that the function gets called immediately. Even though I am trying to call it at the end of a long if else statement. And then when i get to where i am trying to call it it doesn't call.
I am not posting the whole class as it along with its functions are about 150 lines of code.
class use_action(object):
def __init__(self, function = None):
self.function = function
pizza_act = use_action(function = mechanics.tmr.start())
#This is located at the end of an if else statement after the player types use . . .
if self.function != None:
self.function
else:
pass
From Mechanics:
thread_list = []
class TimerClass(threading.Thread):
def __init__(self, function, time):
threading.Thread.__init__(self)
self.event = threading.Event()
self.function = function
self.time = time
thread_list.append(self)
def run(self):
while not self.event.is_set():
self.event.wait( self.time )
self.function()
def stop(self):
self.event.set()
def blank_current_readline():
# Next line said to be reasonably portable for various Unixes
(rows,cols) = struct.unpack('hh', fcntl.ioctl(sys.stdout, termios.TIOCGWINSZ,'1234'))
text_len = len(readline.get_line_buffer())+2
# ANSI escape sequences (All VT100 except ESC[0G)
sys.stdout.write('\x1b[2K') # Clear current line
sys.stdout.write('\x1b[1A\x1b[2K'*(text_len/cols)) # Move cursor up and clear line
sys.stdout.write('\x1b[0G') # Move to start of line
def pizza_poisoned_action():
# threading.Timer(10, pizza_poisoned_action).start()
blank_current_readline()
print "You lost 5 hp."
initialization.gamer.hp -= 5
sys.stdout.write('> ' + readline.get_line_buffer())
sys.stdout.flush() # Needed or text doesn't show until a key is pressed
tmr = TimerClass(pizza_poisoned_action, 5)
Sorry about the length, I tried to only post the relevant stuff for this. If you think i should post some other piece of code that may be relevant let me know!
If you want to pass a function, don't call it. Or else, you'll be passing the return value.
pizza_act = use_action(function = mechanics.test()) #Wrong!
pizza_act = use_action(function = mechanics.test) #Right

Handle animations within an MVC pattern using Pygame

I am currently trying to implement an MVC pattern using Python and Pygame, but I can't figure out how to properly handle animations. Let's say we have a model object that can attack:
class ModelObject:
def attack():
if not self.attacking:
self.attacking = True
# Then compute some stuff
def isattacking():
return self.attacking
And a view object that renders the model object by displaying an attack animation:
class ViewObject(pygame.Sprite):
attacking_ressource = [] # List of surfaces for animation
default_ressource = None
def update():
# Detect the model object is attacking
if self.model.isattacking():
# Create animation if needed
if self.attacking_animation is None:
self.attacking_animation = iter(self.attacking_ressource)
# Set image
self.image = next(self.attacking_animation, self.default_ressource)
else:
# Reset animation
self.attacking_animation = None
self.image = self.default_ressource
The question is, how do the model know that it's no longer attacking?
The view could notify the model when the animation is over, but it guess it's not how the MVC pattern is supposed to work. Or, an animation counter could be set in the model, but it doesn't seem right either.
I think you got it the wrong way round.
The attack should not last as long as the animation, but the animation should last as long as the attack.
So the ViewObject is fine as it already asks the model if it is still attacking.
As for the ModelObject, it's up to you how long the attack should last and how to keep track of time. You could for example call pygame.time.get_ticks() to get the number of millisconds since you started your game once in attack, and then periodically check it again, like:
class ModelObject:
def attack():
if not self.attacking:
self.attacking = True
self.started = pygame.time.get_ticks()
# Then compute some stuff
def isattacking():
return self.attacking
def update():
# attack lasts 1000ms
self.attacking &= pygame.time.get_ticks() - self.started < 1000

Categories