Trying to do animation but the program would close before it - python

I'm a beginner and was wondering if there was any way to finish the current animation before the program closes. Here is the sample of the code:
if playerHealth <= 0: # If the player dies
expl = Explosion(hit.rect.center, 'lg')
all_sprites.add(expl) # Show animation of him blowing up
running = False # End the game
Basically the running = False code would run before the animation(expl) starts. Is there a better way of showing this animation fully?

This sounds like a case for using a callback function. Pygame's animation class has the on_finished property which is intended to be assigned to a callback. The callback would be called once the animation is finished playing and would stop the game. Here's an example Explosion class.
class Explosion:
def __init__(self, rect, size, cb_func):
self.animate_explosion(cb_func)
...
def animate_explosion(self, cb_func):
# start animation here
...
# when animation finishes
self.on_finished = cb_func()
And then within your game logic you have something like the following:
def callback():
running = False
if playerHealth <= 0: # If the player dies
expl = Explosion(hit.rect.center, 'lg', callback())
all_sprites.add(expl) # Show animation of him blowing up

Probably You need more modifications, but one of them is:
if playerHealth <= 0 and not blowing_up_animation_started: # If the player dies
expl = Explosion(hit.rect.center, 'lg')
all_sprites.add(expl) # Show animation of him blowing up
blowing_up_animation_started = True
blowing_up_animation_finished = False
if blowing_up_animation_finished:
running = False # End the game

Related

Pause Function Ursina - Python

I'm trying to do a pause menu for my game in Ursina Engine and I can't fount informatino how the function pause() works or how to do it.
Can someone help me?
Pausing is already implemented in ursina. Just set application.paused to True or False. application.pause() and application.resume() does the same.
from ursina import *
app = Ursina()
# Make a simple game so we have something to test with
from ursina.prefabs.first_person_controller import FirstPersonController
player = FirstPersonController(gravity=0, model='cube', color=color.azure)
camera.z = -10
ground = Entity(model='plane', texture='grass', scale=10)
# Create an Entity for handling pausing an unpausing.
# Make sure to set ignore_paused to True so the pause handler itself can still recieve input while the game is paused.
pause_handler = Entity(ignore_paused=True)
pause_text = Text('PAUSED', origin=(0,0), scale=2, enabled=False) # Make a Text saying "PAUSED" just to make it clear when it's paused.
def pause_handler_input(key):
if key == 'escape':
application.paused = not application.paused # Pause/unpause the game.
pause_text.enabled = application.paused # Also toggle "PAUSED" graphic.
pause_handler.input = pause_handler_input # Assign the input function to the pause handler.
app.run()

Kivy: better way to do timed events (dice rolling animation)

I am writing a yahtzee clone to teach myself Kivy (I'm still very new to Python and programming in general), and I'm having a little trouble figuring out how to best animate the dice rolling. This code works as intended, but I feel like I'm missing something conceptually. Is there a less involved or cleaner way to have a Clock event happen for a set period of time?
This is what I currently have:
The parent layout holds 5 dice as children widgets. The user clicks a button to roll them all using this method:
def roll_all_dice(self):
for dice in self.children:
Clock.schedule_interval(dice.roll, .1)
Clock.schedule_once(dice.roll_animation_callback, .5)
which, if I understand this correctly, schedules a roll every .1s, then .5s later, calls the roll_animation_callback, which stops the events.
Here are the relevant Dice methods:
def roll(self, *args):
'''changes the number of the die and updates the image'''
if self.state != "down":
self.number = randint(1,6)
self.source = self.get_image()
def get_image(self):
'''returns image path for each of the die's sides'''
if self.state == "down":
return "images/down_state/dice" + str(self.number) + ".png"
else:
return "images/up_state/dice" + str(self.number) + ".png"
def roll_animation_callback(self, *args):
'''turns off the dice rolling animation event'''
Clock.unschedule(self.roll)
This seems fine, using the Clock like this is normal.

Python and tile based game: limiting player movement speed

I've been putting together an isometric tile-based RPG using Python and the Pyglet library. I've run into the following problem, however:
My player movement is based on positions on the three-dimensional array that consists of tiles. To limit movement speed, I use a global variable: TILE_TO_TILE_DELAY = 200.
TILE_TO_TILE_DELAY is supposed to be the amount of time in milliseconds it takes for the player to move from one tile to another. During this time, they should not be able to make a new movement.
The system I've been using is that I have a timer class, like this:
import time
def GetSystemTimeInMS(): #Return system time in milliseconds
systime = round((time.clock()*1000), 0)
return systime
class Timer:
def __init__(self,time):
#time = time for which the timer runs
self.time = time
self.start_time = 0
self.stop_time = 0
def StartTimer(self):
#start_time = time at which the timer was started
self.start_time = GetSystemTimeInMS()
self.stop_time = self.start_time + self.time
def TimerIsStopped(self):
if GetSystemTimeInMS() >= self.stop_time:
return True
else:
return False
The player class has a Timer object:
self.MoveTimer = Timer(TILE_TO_TILE_DELAY)
When the player presses the W-key, a function is called that checks for player.MoveTimer.TimerIsStopped(). If it returns True, it calls player.MoveTimer.StartTimer() and starts a new movement to the next position.
In the even loop, the update(dt) function is set to happen 30 times a second:
def update(dt):
if player.MoveTimer.TimerIsStopped()
player.UpdatePosition()
pyglet.clock.schedule_interval(update, 1/30)
Now, by my logic, update(dt) should check 30 times a second whether or not enough time has passed to warrant the player a new movement event. However, for some reason the player moves much faster at lower FPS.
When my FPS is around 30, the player moves much faster than in areas where there are less tile sprites, pumping the framerate to 60. In areas where FPS is high, the player indeed by my measurements moves almost twice as slowly.
I just cannot figure it out, nor did I find anything off the internet after a day of searching. Some help would be much appreciated.
Edit: The code that starts the MoveTimer:
def StartMovement(self, new_next_pos):
self.RequestedMovement = False
if self.GetCanMoveAgain():
self.SetNextPos(new_next_pos)
self.SetMoveDirection(self.GetDirection())
#Start the timer for the movement
self.MoveTimer.StartTimer()
self.SetIsMoving(True)
self.SetStartedMoving(True)
self.SetWalking(True)
self.SetNeedUpdate(True)
self.MOVE_EVENT_HANDLER.CreateMoveEvent()
GetCanMoveAgain() returns the value of player.can_move_again, which is set back to True by the UpdatePosition() in update(dt)
Alright, I fixed the problem, how ever I'm still unsure about what caused it. Maybe it was some sort of a rounding error with milliseconds, having to do with more checks being made to the clock when the FPS is higher. Anyways, the solution:
Instead of using the system clock, I decided to use Pyglet's own "dt" argument in their update functions:
The dt parameter gives the number of seconds (due to latency, load and timer inprecision, this might be slightly more or less than the requested interval).
The new timer looks like this:
class dtTimer: #A timer based on the dt-paremeter of the pyglet event loop
def __init__(self,time):
self.time = time
self.time_passed = 0
def StartTimer(self):
self.time_passed = 0
def UpdateTimer(self, dt):
self.time_passed += dt*1000
def GetTime(self):
return self.time
def GetTimePassed(self):
if not self.TimerIsStopped():
return self.time_passed
else:
return 0
def TimerIsStopped(self):
if self.time_passed > self.time:
return True
else:
return False
When the loop attempts to update the player's position, if the TimerIsStopped returns false, dt is simply added to the Timer's self.time_passed. This has fixed the issue: the time it takes for the player to move is now constant.
Thanks for looking at my issue.

How to play music continuously in pyglet

me and my friend are working on a game and we want our music to loop as long as the game is running. Help please there seems to be no function to put music on repeat
In current versions of pyglet, you should use a SourceGroup, setting the loop attribute to True. You can then queue it into a Player to play it:
snd = pyglet.media.load('sound.wav')
looper = pyglet.media.SourceGroup(snd.audio_format, None)
looper.loop = True
looper.queue(snd)
p = pyglet.media.Player()
p.queue(looper)
p.play()
Not sure if there's a more compact way of doing this but it seems to work...
To make a sound play in a loop, you can use a Player:
# create a player and queue the song
player = pyglet.media.Player()
sound = pyglet.media.load('lines.mp3')
player.queue(sound)
# keep playing for as long as the app is running (or you tell it to stop):
player.eos_action = pyglet.media.SourceGroup.loop
player.play()
To play more background sounds simultaneously, just start up another player for each of the sounds, with the same EOS_LOOP "eos_action" setting as above for each of them.
For playing continuously you can use this code
This will allow you to play files from your root directory
import pyglet
from pyglet.window import key
import glob
window = pyglet.window.Window(1280, 720, "Python Player", resizable=True)
window.set_minimum_size(400,300)
songs=glob.glob("*.wav")
player=pyglet.media.Player()
#window.event
def on_key_press(symbol, modifiers):
if symbol == key.ENTER:
print("A key was pressed")
#window.event
def on_draw():
global player
for i in range(len(songs)):
source=pyglet.resource.media(songs[i])
player.queue(source)
player.play()
pyglet.app.run()
this works for me
myplayer = pyglet.media.Player()
Path = "c:/path/to/youraudio.mp3"
source = pyglet.media.load(filename=source, streaming=False)
myplayer.queue(self.slowCaseSongSource)
myplayer.eos_action = 'loop'
this might be irrelevant:
import pyglet
import time
import random
#WARNING: You have to download your own sounds and define them like this:
#sound_1 = pyglet.resource.media("sound_file.wav", streaming=False)
#replacing "sound_file" with your own file.
# Add the sound variables here
BACKGROUND_OPTIONS = ()
player = pyglet.media.Player()
def play_background_sound():
global player
player.queue(random.choice(BACKGROUND_OPTIONS))
player.play()
# This is optional; it's just a function that keeps the player filled so there aren't any breaks.
def queue_sounds():
global player
while True:
player.queue(random.choice(BACKGROUND_OPTIONS))
time.sleep(60) # change this if the background music you have is shorter than 3 minutes
threading.Thread(target=queue_sounds).start()

I want to add delay between jumps in my platforming game

So i have this platforming game that im programming in pygame. I have a jump method and i want to add a dely between jumps. That way i dont keep jumping into the ceiling. Heres the code
def jump(self):
if (self.onGround == True):
return
self.velocity = 10
self.onGround = False
This is what calls it in the main game loop:
if (event.key==pygame.K_UP):
player.jump()
Keep track of the last time you jumped, or of the next time you're allowed to jump (with pygame.time):
def __init__(self, …):
# ...
self.next_jump = 0
def jump(self):
if pygame.time.get_ticks() < self.next_jump:
return
# ...
self.next_jump = pygame.time.getticks() + 500
Depending on which type of loop you've gone with (traditional event loop, frame-rate-limited loop, unlimited-frame-rate loop) there may be better answers involving, e.g., setting a timer or using a Clock, but this will work with any type.

Categories

Resources