For the last few days I have been struggling with seemingly trivial problem of changing screens in Kivy. I have this gif animation that lasts 6 seconds (at least according to Canva as I created it in Canva). I have a screen with this gif that I want to play before the players get the chance to play the game. Just like an introduction.
So what I want is I want this gif to be played only once and then I want to immediately transition to the main game.
** PROBLEMS THAT I ENCOUNTERED:**
The gif is not played from the start. It starts kinda from the end despite the fact that if you download it and open it, it plays normally. In Kivy sometimes it starts in the middle, sometimes it starts from the end etc. It's very irregular and I have no idea what has an impact on it.
I don't know how to tell Kivy to change the screen after the animation is completed. I tried using Clock.schedule_once but for some reason I can't get it to work despite the fact I had been following advices that I found here on Stack Overflow and also on YouTube.
I'm not going to include the whole code as it's very long (as I mentioned I've been working on this project for a while and it consists of several different classes and files) but below you can find my python and Kivy file for the "final_round_animation". **All I need is to move it to some different screen. You can use a blank screen with a white background. It doesn't matter. All I need is to find out how to play this gif once correctly, and then move from this screen to another one. **
py file
from kivy.uix.screenmanager import Screen
class FinalRoundAnimation(Screen):
pass
kivy file:
<FinalRoundAnimation>
name: 'final_round_animation'
FloatLayout:
orientation: 'horizontal'
size: 1280, 720
Image:
id: gif
source:'Final Round Animation.gif'
anim_delay: 0.03
allow_stretch: True
keep_ratio: False
keep_data: True
I've spent literally days already trying to find the solution here on Stack Overflow and also other places. But what I tried was:
https://youtu.be/fq9yA_XVzLA?t=329
It was something in this style:
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.clock import Clock
class Swap(ScreenManager):
def on_enter(self):
Clock.schedule_once(self.change_screen, 6)
def change_screen(self):
self.current = 'main_game_trial'
class FinalRoundAnimation(Screen):
pass
class MainGameTrial(Screen):
pass
The problems with this approach were as below"
Clock.schedule_once(self.change_screen(), 6)
I came to conclusion that maybe the fact that it didn't work like in the video was because I tried to do it within some class that is some part of the project and in that video it was shown that it was made in the file with the App.
I tried using anim_loop
within kivy file and then referencing it in the py file. Basically I wanted to create a condition that if anim_loop will be greater than 1 then move to a different screen. However, to no avail. When I set anim_loop for example to 2, the gif wasn't playing at all. I don't know why. If I set it to 10 it kept looping endlessly.
Tried to apply tens of different situations from Stack Overflow threads that I went over when I was searching for solution.
I would be very very grateful if you could help me with this.
Thank you in advance for your input.
Ideally, the Image
class would fire an event when the gif animation ends, but it does not. You can simulate this by extending the Image
class:
class MyImage(Image):
complete = BooleanProperty(False)
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.anim_loop = 1 # only allow one animation loop
self.textures_used = 0
self.num_textures = None
def on_texture(self, image, texture):
if self.num_textures is None:
self.num_textures = len(self._coreimage.image.textures)
self.textures_used += 1
if (self.textures_used + 1) == self.num_textures:
self.complete = True
Then use that new class in your kv
:
<FinalRoundAnimation>:
name: 'final_round_animation'
FloatLayout:
orientation: 'horizontal'
size: 1280, 720
MyImage:
id: gif
source: 'Final Round Animation.gif'
anim_delay: -1 # do not run the animation
allow_stretch: True
keep_ratio: False
keep_data: True
on_complete:
if self.complete: root.manager.current='main_game_trial'; \
self.anim_delay = -1; \
self.texture = self._coreimage.image.textures[0]
else: root.manager.current='final_round_animation'
the on_complete
now triggers the Screen
change.
And add an on_enter()
method to the `FinalRoundAnimation' class:
class FinalRoundAnimation(Screen):
def on_enter(self, *args):
gif = self.ids.gif
gif.reload()
gif.textures_used = 0
gif.num_textures = None
gif.complete = False
gif.anim_delay = 0.03 # starts the animation