jetpack_bird.py

Created by fime

Created on April 30, 2021

6.34 KB

For Numworks N0110 - Bug report or review here


Code by Fime - Also check out my Other games


Fly beetween the green pipes with a jetpack and a yellow bird. Everything is ok. Any resemblance with Flappy Bird (or Jetpack Joyride) would be purely coincidental.


F.A.Q. (en français)

  • Comment lancer le script ? Pour lancer le script, il faut ouvrir le menu “options du script” (icone des 3 points à droite du nom du script) et sélectionner “exécuter le script”.
  • Pourquoi le meilleur score n’est-il pas enregistré ? L’architecture du jeu est telle que chaque partie est tout à fait indépendante les une par rapport aux autres. Le seul moyen d’afficher le meilleur score d’une partie à l’autre est donc de le lire puis de l’enregistrer à la fin de la partie dans un fichier stocké dans la mémoire de la calculatrice, et cela a l’avantage de permettre la sauvegarde du meilleur score d’une exécution à l’autre. Cependant, la version officielle d’Épsilon n’offre pas cette fonctionnalité. Si vous souhaitez en profiter, je vous invite à télécharger la dernière version d’Oméga (une version améliorée d’Epsilon) .

𝐂𝐡𝐚𝐧𝐠𝐞𝐥𝐨𝐠 :

  • Version 1.0 :
    • first public release !

𝐂𝐨𝐧𝐭𝐫𝐨𝐥𝐬 :

  • [OK] to climb/jump

𝐅𝐞𝐚𝐭𝐮𝐫𝐞𝐬 :

  • High FPS rate (about 20 fps)
  • Best score saving. Won’t work on Epsilon. Install Omega (it’s an improved version of epsilon)


from kandinsky import fill_rect as krect, draw_string as text
from ion import keydown
from random import randint
from time import *
# Code by Fime, nsi.xyz/jetpackbird

SCREEN_W=320
SCREEN_H=222

GAME_W=200
SCORE_OFFSET=5
SCORE_W=100
GAME_H=200

OFFSET_X=(SCREEN_W-SCORE_W-GAME_W-SCORE_OFFSET)//2# game offset
OFFSET_Y=(SCREEN_H-GAME_H)//2

KEY={"ok":4}
COLOR={
"bg":(50,200,255),
"bird":(255,200,0),
"hurt":(255,50,0),
"jp":(150,150,150),
"mouth":(255,100,0),
"pipe":(100,255,20),
"line":(0,0,0),
"font1":(60,60,60),
"font2":(255,255,255)}

LINE_W=2 #line width

TARG_FPS=20
TARG_SPF=1/TARG_FPS# targ second per frame

def sec(time):
  return monotonic()-time

def rect(x,y,h_s,v_s,c):
  krect(int(x),int(y),int(h_s),int(v_s),COLOR["line"])
  if h_s>2*LINE_W: krect(int(x)+LINE_W,int(y)+LINE_W,int(h_s)-2*LINE_W,int(v_s)-2*LINE_W,c)

def drawBird(x,y,s):
  if sec(hurt_time)>1 or (sec(hurt_time)*5%2>0.5):
    c=COLOR["bird"]
  else:
    c=COLOR["hurt"]
  rect(x,y,s,s,c)
  rect(x-s/2,y+s/8,s/2,s/2,COLOR["jp"])
  rect(x+s/2,y+s/2,s/1.5,s/3,COLOR["mouth"])
  rect(x+s/4,y+s/5,s/3,s/3,COLOR["font2"])  
  
  o=s/2 if flap and int(sec(flap_time)*16)%2==0 else s/4
  rect(x-s/4,y+o,s/2,s/2,c)
  if flap:
    s2=min(s/2+o*2,OFFSET_Y+GAME_H-y-s/8*6)
    rect(x-s/2,y+s/8*5,s/2,s2,COLOR["mouth"])
    krect(int(x-s/2+LINE_W*2),int(y+s/8*5.5),int(s/2-LINE_W*4),int(s2/2),COLOR["font2"])
  
  
def drawPipe(i):
  pipe=pipes[i]
  
  x,y = min(max(pipe[0],OFFSET_X),OFFSET_X+GAME_W),pipe[1]
  if x<=OFFSET_X: h_s = pipe[2]-(x-pipe[0])
  elif x>=OFFSET_X+GAME_W-pipe[2]: h_s = (GAME_W+OFFSET_X)-x
  else: h_s=pipe[2]
  v_s = pipe[3]
  
  rect(x,y,h_s,v_s,COLOR["pipe"])

def drawHeart(x,y,s,c):
  heart=("01100","11110","01111","11110","01100")
  for x2 in range(len(heart)):
    for y2 in range(len(heart[x2])):
      if int(heart[x2][y2]): krect(x+x2*s,y+y2*s,s,s,c)

def initScreen():
  rect(OFFSET_X,OFFSET_Y,GAME_W,GAME_H,COLOR["bg"])
  drawScorePannel()
  actualizeScore()
  actualizeLife()

def clearScreen():
  krect(OFFSET_X+LINE_W,OFFSET_Y+LINE_W,GAME_W-2*LINE_W,GAME_H-2*LINE_W,COLOR["bg"])
  
def createPipe(x,y,h_s,v_s):
  #h_s : horizontal size
  #v_s : vertical size
  pipe=[x,y,h_s,v_s]
  pipes.append(pipe)
  

def addPipes(x,s):
  space_size = GAME_H//2 - difficulty*2
  space_y= randint(OFFSET_Y,OFFSET_Y+GAME_H-space_size-20)
  
  createPipe(x,OFFSET_Y,s,space_y)
  createPipe(x,OFFSET_Y+space_size+space_y,s,GAME_H-(space_size+space_y))
  
def hitBox(p1,p2):
  x1=p1[0]
  y1=p1[1]
  hs1=p1[2]
  vs1=p1[3]
  
  x2=p2[0]
  y2=p2[1]
  hs2=p2[2]
  vs2=p2[3]
  
  if x1 <= x2+hs2 and x1+hs1 >= x2 and y1 <= y2+vs2 and y1+vs1 >= y2:
    return True
  else:
    return False

def gameEngine():
  global bird, pipes, score, best_score, difficulty,flap,total_time,flap_time,fps,hurt_time,life
  
  print(">initialisation: dead...")    
  difficulty=1
  life=3
  score=0
  best_score=readBestScore()
  pipes=[]
  pipe_size=50
  flap=0
  jump_speed=4
  max_speed=15
  fps=TARG_FPS
 
  bird={
  "x":20,
  "y":OFFSET_Y+GAME_H/2,
  "spd_x":5,
  "spd_y":-5,
  "size":20,
  "color":COLOR["bird"]}
  
  addPipes(GAME_W+OFFSET_X,pipe_size)
  addPipes(GAME_W/2-pipe_size/2+OFFSET_X,pipe_size)
  
  initScreen()
  
  spf=TARG_SPF
  total_time=monotonic()
  flap_time=monotonic()
  hurt_time=monotonic()-1
  
  while not (life<1 and sec(hurt_time)>0.5):
    if sec(spf)>=TARG_SPF:
      
      #GAME DATA
      fps=int(1/sec(spf))
      #print(fps)
      spf=monotonic()
      
      #PHYSICS
      limits_y=[OFFSET_Y,OFFSET_Y+GAME_H]
      
      bird["spd_y"]+=jump_speed/3
      bird["spd_y"]=max(-max_speed,min(max_speed,bird["spd_y"]))
      
      bird["y"]+=bird["spd_y"]
      
      if bird["y"]<=limits_y[0]:
        bird["y"]=limits_y[0]
        bird["spd_y"]=0
      
      if bird["y"]>=limits_y[1]-bird["size"]:
        bird["y"]=limits_y[1]-bird["size"]
        bird["spd_y"]=0
        
      if keydown(KEY["ok"]):
        bird["spd_y"]-=abs(-max_speed-bird["spd_y"])/max_speed*jump_speed
        if flap==0:
          flap_time=monotonic()
        flap=1
      else: flap=0
      
      remove_pipe=[]
      last_speed=int(bird["spd_x"])
      for i in pipes:
        i[0]-=last_speed
        if hitBox((bird["x"],bird["y"],bird["size"],bird["size"]),i):
          if sec(hurt_time)>1:
            if life>0:hurt_time=monotonic()
            life-=1
            difficulty+=randint(1,3)
            actualizeLife()
            print(">{}s:hurt! life:{}".format(int(sec(total_time)),life))
        if i[0]+i[2]<=OFFSET_X:
          if i[1]!=OFFSET_Y:
            bird["spd_x"]+=abs(max_speed-bird["spd_x"])/(4*max_speed)
            score+=1
            best_score=max(score,best_score)
            actualizeScore()
            addPipes(GAME_W+OFFSET_X,pipe_size)
          remove_pipe.append(i)
      for i in remove_pipe:
        pipes.remove(i)
                
      #DISPLAY
      clearScreen()
      for i in range(len(pipes)):
        drawPipe(i)
      drawBird(bird["x"],bird["y"],bird["size"])
    
  print(">game end: dead...")
  print(">fps : {}".format(fps))
  transition()
  saveScore(best_score)
  gameEngine()
      
def actualizeScore():
  
  x=OFFSET_X+GAME_W+SCORE_OFFSET+SCORE_W//2
  y=OFFSET_Y
  c=COLOR["font2"]
  
  text(str(score),x-len(str(score))*5,y+40,c,COLOR["bird"])
  text(str(best_score),x-len(str(best_score))*5,y+100,c,COLOR["bird"])
  
def actualizeLife():
  
  x=OFFSET_X+GAME_W+SCORE_OFFSET+5
  y=OFFSET_Y+150
  
  for i in range(3):
    if i>=life: c=COLOR["line"]
    else: c=COLOR["hurt"]
    drawHeart(x+i*30,y,5,c) 

def drawScorePannel(): 

  x=OFFSET_X+GAME_W+SCORE_OFFSET
  y=OFFSET_Y
  
  rect(x,y,SCORE_W,GAME_H,COLOR["bird"])
  
  x=OFFSET_X+GAME_W+SCORE_W//2
  y=OFFSET_Y
  
  text("SCORE",x-len("SCORE")*5,y+10,COLOR["font1"],COLOR["bird"])
  text("BEST",x-len("BEST")*5,y+70,COLOR["font1"],COLOR["bird"])
  
def readBestScore():
  try:
    file=open("jp_bird.sav","r")
    best = file.readline()
    file.close()
    print(">score loaded !")
    return int(best)
  except:
    print(">failed to read the score...")
    return 0

def saveScore(score):
  try :
    file=open("jp_bird.sav","w")
    file.truncate(0)
    file.write(str(score))
    file.close()
    print(">score saved !")
  except:
    print(">failed to save the score...")

def transition():
  for c in [COLOR["font1"],COLOR["bg"]]:
    for y in range(OFFSET_Y,OFFSET_Y+GAME_H,10):
      sleep(0.016)
      krect(OFFSET_X,y,GAME_W,10,c)

gameEngine()

During your visit to our site, NumWorks needs to install "cookies" or use other technologies to collect data about you in order to:

With the exception of Cookies essential to the operation of the site, NumWorks leaves you the choice: you can accept Cookies for audience measurement by clicking on the "Accept and continue" button, or refuse these Cookies by clicking on the "Continue without accepting" button or by continuing your browsing. You can update your choice at any time by clicking on the link "Manage my cookies" at the bottom of the page. For more information, please consult our cookies policy.