Create Your Own Desktop Pet with Python

TheNobody
Analytics Vidhya
Published in
7 min readMar 12, 2020
make 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 pyautogui
x = 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.

idle
while changing from idle to sleep
sleeping
while changing from sleep back to idle
walking towards left
walking towards right

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 = idle
elif event_number == 5:
check = 1
print('from idle to sleep')
window.after(100,update,cycle,check,event_number,x) #no. 5 = idle to sleep
elif 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 left
elif 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 right
elif event_number in sleep_num:
check = 2
print('sleep')
window.after(1000,update,cycle,check,event_number,x)#no. 10,11,12,13,15 = sleep
elif 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 tk
x = 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 = idle
elif event_number == 5:
check = 1
print('from idle to sleep')
window.after(100,update,cycle,check,event_number,x) #no. 5 = idle to sleep
elif 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 left
elif 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 right
elif event_number in sleep_num:
check = 2
print('sleep')
window.after(1000,update,cycle,check,event_number,x)#no. 10,11,12,13,15 = sleep
elif 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_number
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)
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!!

--

--