Create Your Own Desktop Pet with Python
Everyone loves animals, right? But there must be someone which is allergic to cats or dogs , just like me. So one day, I just thought, why don’t just make a digital one? Although they are not real, but hey, I can get my own cat! Therefore, in this article, I will show you how I write my own desktop cat using Python Programming language!
The Final Product
Getting Started
First of all, we need to import our module, and assign a few variable which I will explain later in the article, and I am going to use ‘Tkinter’ as our GUI.
import random
import tkinter as tk
import pyautoguix = 1400
cycle = 0
check = 1
idle_num =[1,2,3,4]
sleep_num = [10,11,12,13,15]
walk_left = [6,7]
walk_right = [8,9]
event_number = random.randrange(1,3,1)
impath = 'C:\\your\\path\\to\\file'
and the reason why I import random is because our pet is moving in random motion.
After that, we need to create a tkinter window which we are going to place our pet.
window = tk.Tk()
next, we have to know what action we want our pet have, I my case, I want a cat, and I want her could idle, sleep and walking around my desktop, so I have made some hard work on making .gif for our cat.
while we have those .gif, we have to call it from local file to our python program:
#call buddy's action .gif to an array
idle = [tk.PhotoImage(file=impath+'idle.gif',format = 'gif -index %i' %(i)) for i in range(5)]#idle gif , 5 frames
idle_to_sleep = [tk.PhotoImage(file=impath+'idle_to_sleep.gif',format = 'gif -index %i' %(i)) for i in range(8)]#idle to sleep gif, 8 frames
sleep = [tk.PhotoImage(file=impath+'sleep.gif',format = 'gif -index %i' %(i)) for i in range(3)]#sleep gif, 3 frames
sleep_to_idle = [tk.PhotoImage(file=impath+'sleep_to_idle.gif',format = 'gif -index %i' %(i)) for i in range(8)]#sleep to idle gif, 8 frames
walk_positive = [tk.PhotoImage(file=impath+'walking_positive.gif',format = 'gif -index %i' %(i)) for i in range(8)]#walk to left gif, 8 frames
walk_negative = [tk.PhotoImage(file=impath+'walking_negative.gif',format = 'gif -index %i' %(i)) for i in range(8)]#walk to right gif, 8 frames
to make our pet background from black to transparent, we need a few lines of code:
window.config(highlightbackground='black')
window.overrideredirect(True)
window.wm_attributes('-transparentcolor','black')
as I want her to be movable and showing animation, I assign her as a label:
label = tk.Label(window,bd=0,bg='black')
label.pack()
window.mainloop()
And that’s the perpetration we need to make our program works.
Make it alive!
Since we call our .gif in the form of array, we need to make a function to loop each frame:
#make the gif work
def gif_work(cycle,frames,event_number,first_num,last_num):
if cycle < len(frames) -1:
cycle+=1
else:
cycle = 0
event_number = random.randrange(first_num,last_num+1,1)
return cycle,event_number
as the code shows, every time we call this function, the variable ‘cycle’ will increase by 1, but when it is big enough to the (length of the frame array -1 ), it back to 0 and change the event_number in random range, it is because I want my cat change it action every time the .gif have looped once. It could help making the pet more natural since every move is random but logical, like when it is sleeping, the .gif loop once, it immediately think which action to do next, it could be change from sleeping to continue sleeping or awake and being idle.
update the frame
We need our pet to do an action with assigning a number to every action:
def update(cycle,check,event_number,x):
#idle
if check ==0:
frame = idle[cycle]
cycle ,event_number = gif_work(cycle,idle,event_number,1,9)
#idle to sleep
elif check ==1:
frame = idle_to_sleep[cycle]
cycle ,event_number = gif_work(cycle,idle_to_sleep,event_number,10,10)#sleep
elif check == 2:
frame = sleep[cycle]
cycle ,event_number = gif_work(cycle,sleep,event_number,10,15)#sleep to idle
elif check ==3:
frame = sleep_to_idle[cycle]
cycle ,event_number = gif_work(cycle,sleep_to_idle,event_number,1,1)#walk toward left
elif check == 4:
frame = walk_positive[cycle]
cycle , event_number = gif_work(cycle,walk_positive,event_number,1,9)
x -= 3#walk towards right
elif check == 5:
frame = walk_negative[cycle]
cycle , event_number = gif_work(cycle,walk_negative,event_number,1,9)
x -= -3
window.geometry('100x100+'+str(x)+'+1050')
label.configure(image=frame)
window.after(1,event,cycle,check,event_number,x)
the code
x = 1400
window.geometry('100x100+'+str(x)+'+1050')
is the location of our tkinter window aka the position of our pet, ‘100x100’ is the size of our pet in pixel, ‘x’ is the x position in our screen, and ‘1050’ is the floor our pet stepping on.(it change with the resolution of your screen)
Event Change
To make the event change , we need a function to define when and the probability to do an action :
idle_num =[1,2,3,4]
sleep_num = [10,11,12,13,15]
walk_left = [6,7]
walk_right = [8,9]#transfer random no. to event
def event(cycle,check,event_number,x):
if event_number in idle_num:
check = 0
print('idle')
window.after(400,update,cycle,check,event_number,x) #no. 1,2,3,4 = idleelif event_number == 5:
check = 1
print('from idle to sleep')
window.after(100,update,cycle,check,event_number,x) #no. 5 = idle to sleepelif event_number in walk_left:
check = 4
print('walking towards left')
window.after(100,update,cycle,check,event_number,x)#no. 6,7 = walk towards leftelif event_number in walk_right:
check = 5
print('walking towards right')
window.after(100,update,cycle,check,event_number,x)#no 8,9 = walk towards rightelif event_number in sleep_num:
check = 2
print('sleep')
window.after(1000,update,cycle,check,event_number,x)#no. 10,11,12,13,15 = sleepelif event_number == 14:
check = 3
print('from sleep to idle')
window.after(100,update,cycle,check,event_number,x)#no. 15 = sleep to idle
if any of you is confused in
window.after(1000,update,cycle,check,event_number,x)
it mean that the program will call the update function with the following assignment after 1000 ms, which is 1s and we could control the speed of the animation by changing it.
Logic behind the code
If you have pay attention to the above code, you should notice that after our cat change from idle to sleep, the next action must be sleep, same as after changing from sleep to idle, it must be idling,
idle_num =[1,2,3,4]
#sleep to idle
elif check ==3:
frame = sleep_to_idle[cycle]
cycle ,event_number = gif_work(cycle,sleep_to_idle,event_number,1,1)#must be idle
in the variable we have assigned at the beginning:
check = 1
idle_num =[1,2,3,4]#5 is idle to sleep
sleep_num = [10,11,12,13,15] #14 is sleep to idle,sorry for skipping
walk_left = [6,7]
walk_right = [8,9]
we could see that we have 15 numbers, at the start of the program, our pet must be idling because we assigned variable ‘check’ is 1, after the .gif loop once, the ‘event_number‘ will be randomly change in 1 to 9, so it had a probability of 4/9 to keep idling or walking toward left and right, and 1/9 chance to change from idle to sleeping. And once it changed to sleeping, it must perform a sleep action to prevent instant waking up which is not sound natural.
And just like a normal cat, it had a very high chance to keep sleeping and sleeping and sleeping.
the full code
import pyautogui
import random
import tkinter as tkx = 1400
cycle = 0
check = 1
idle_num =[1,2,3,4]
sleep_num = [10,11,12,13,15]
walk_left = [6,7]
walk_right = [8,9]
event_number = random.randrange(1,3,1)
impath = 'C:\\Users\\fx770\\Desktop\\Project\\Buddy\\image\\'#transfer random no. to event
def event(cycle,check,event_number,x):
if event_number in idle_num:
check = 0
print('idle')
window.after(400,update,cycle,check,event_number,x) #no. 1,2,3,4 = idleelif event_number == 5:
check = 1
print('from idle to sleep')
window.after(100,update,cycle,check,event_number,x) #no. 5 = idle to sleepelif event_number in walk_left:
check = 4
print('walking towards left')
window.after(100,update,cycle,check,event_number,x)#no. 6,7 = walk towards leftelif event_number in walk_right:
check = 5
print('walking towards right')
window.after(100,update,cycle,check,event_number,x)#no 8,9 = walk towards rightelif event_number in sleep_num:
check = 2
print('sleep')
window.after(1000,update,cycle,check,event_number,x)#no. 10,11,12,13,15 = sleepelif event_number == 14:
check = 3
print('from sleep to idle')
window.after(100,update,cycle,check,event_number,x)#no. 15 = sleep to idle#making gif work
def gif_work(cycle,frames,event_number,first_num,last_num):
if cycle < len(frames) -1:
cycle+=1
else:
cycle = 0
event_number = random.randrange(first_num,last_num+1,1)
return cycle,event_numberdef update(cycle,check,event_number,x):
#idle
if check ==0:
frame = idle[cycle]
cycle ,event_number = gif_work(cycle,idle,event_number,1,9)
#idle to sleep
elif check ==1:
frame = idle_to_sleep[cycle]
cycle ,event_number = gif_work(cycle,idle_to_sleep,event_number,10,10)#sleep
elif check == 2:
frame = sleep[cycle]
cycle ,event_number = gif_work(cycle,sleep,event_number,10,15)#sleep to idle
elif check ==3:
frame = sleep_to_idle[cycle]
cycle ,event_number = gif_work(cycle,sleep_to_idle,event_number,1,1)#walk toward left
elif check == 4:
frame = walk_positive[cycle]
cycle , event_number = gif_work(cycle,walk_positive,event_number,1,9)
x -= 3#walk towards right
elif check == 5:
frame = walk_negative[cycle]
cycle , event_number = gif_work(cycle,walk_negative,event_number,1,9)
x -= -3
window.geometry('100x100+'+str(x)+'+1050')
label.configure(image=frame)
window.after(1,event,cycle,check,event_number,x)window = tk.Tk()#call buddy's action gif
idle = [tk.PhotoImage(file=impath+'idle.gif',format = 'gif -index %i' %(i)) for i in range(5)]#idle gif
idle_to_sleep = [tk.PhotoImage(file=impath+'idle_to_sleep.gif',format = 'gif -index %i' %(i)) for i in range(8)]#idle to sleep gif
sleep = [tk.PhotoImage(file=impath+'sleep.gif',format = 'gif -index %i' %(i)) for i in range(3)]#sleep gif
sleep_to_idle = [tk.PhotoImage(file=impath+'sleep_to_idle.gif',format = 'gif -index %i' %(i)) for i in range(8)]#sleep to idle gif
walk_positive = [tk.PhotoImage(file=impath+'walking_positive.gif',format = 'gif -index %i' %(i)) for i in range(8)]#walk to left gif
walk_negative = [tk.PhotoImage(file=impath+'walking_negative.gif',format = 'gif -index %i' %(i)) for i in range(8)]#walk to right gif#window configuration
window.config(highlightbackground='black')
label = tk.Label(window,bd=0,bg='black')
window.overrideredirect(True)
window.wm_attributes('-transparentcolor','black')label.pack()#loop the program
window.after(1,update,cycle,check,event_number,x)window.mainloop()
Hope you enjoy the tutorial and feel good after making your own desktop pet!!