flappy.py

Created by laigna

Created on March 14, 2026

3.59 KB

Flap the bird. Simple flappy bird game.


# Flappy Bird - NumWorks
# Created by Alvar Laigna - https://alvarlaigna.com
# OK/EXE:flap Back:quit
from kandinsky import fill_rect as F,draw_string as D
from ion import keydown as K
from time import sleep as Z,monotonic as M
from random import randint
SW,SH=320,222
BK=(0,)*3;WH=(255,)*3
# Colors
SKY=(135,200,235);GND=(120,100,50)
PIP=(50,180,50);PD=(40,140,40)
BC=(240,210,40);BE=(0,0,0);BW=(255,120,40)
GH=22;PW=28;GAP=56;BSZ=10
BX=55

okv=1 if K(4)or K(52) else 0

def okd():
 return K(4)or K(52)

def okp():
 global okv
 d=okd()
 if d and not okv:
  okv=1
  return True
 if not d:okv=0
 return False

def wup():
 while okd():Z(0.02)
 Z(0.12)

def title():
 F(0,0,SW,SH,SKY)
 F(0,SH-GH,SW,GH,GND)
 # Ground detail
 for x in range(0,SW,12):
  F(x,SH-GH,2,4,(100,80,40))
 D("FLAPPY BIRD",80,30,BC,(110,175,210))
 # Draw bird
 F(150,85,16,14,BC)
 F(162,87,6,5,WH);F(164,88,3,3,BE)
 F(166,91,6,4,BW)
 # Draw mini pipes
 F(90,60,PW,45,PIP);F(90,130,PW,50,PIP)
 F(200,60,PW,30,PIP);F(200,115,PW,65,PIP)
 D("OK / EXE = flap",80,155,(60,60,80),SKY)
 D("Back = quit",110,175,(60,60,80),SKY)
 D("Press OK",125,198,WH,(100,80,40))
 while True:
  if okp():wup();return True
  if K(17):return False
  Z(0.05)

def flappy():
 while True:
  by=float(SH//2-20);vy=0.0
  pipes=[];sc=0;fr=0
  spd=2.0;grav=0.42;flp=-3.8
  nxt=SW+40
  alive=True
  # Draw sky + ground
  F(0,0,SW,SH-GH,SKY)
  F(0,SH-GH,SW,GH,GND)
  for x in range(0,SW,12):
   F(x,SH-GH,2,4,(100,80,40))
  # Score
  D(str(sc),SW//2-5,6,WH,SKY)
  while alive:
   if K(17):return
   # Flap
   if okp():
    vy=flp
    Z(0.02)
   # Physics
   vy+=grav
   vy=min(vy,6.0)
   oby=int(by)
   by+=vy
   # Ceiling/floor
   if by<0:by=0.0;vy=0
   if by>SH-GH-BSZ:
    alive=False;by=float(SH-GH-BSZ)
   nby=int(by)
   # Erase old bird
   if oby!=nby:
    F(BX,oby,BSZ+8,BSZ+2,SKY)
   # Move pipes
   for p in pipes:
    # Erase old pipe position
    ox=int(p[0])
    if 0<=ox<SW:
     F(ox,0,PW+2,p[1],SKY)
     F(ox,p[1]+GAP,PW+2,SH-GH-p[1]-GAP,SKY)
    p[0]-=spd
    # Score
    if not p[2]and p[0]+PW<BX:
     p[2]=True;sc+=1
     F(0,2,SW,18,SKY)
     D(str(sc),SW//2-5,6,WH,SKY)
   # Remove off-screen pipes
   while pipes and pipes[0][0]<-PW:
    pipes.pop(0)
   # Spawn new pipe
   if not pipes or pipes[-1][0]<nxt:
    gy=randint(40,SH-GH-GAP-40)
    pipes.append([float(SW),gy,False])
    nxt=pipes[-1][0]-120-min(sc*2,30)
   # Draw pipes
   for p in pipes:
    px=int(p[0])
    if-PW<px<SW:
     # Top pipe
     lx=max(0,px);rw=min(PW,SW-lx)
     if px<0:rw=PW+px;lx=0
     F(lx,0,rw,p[1],PIP)
     F(lx,p[1]-4,rw,4,PD)
     # Bottom pipe
     bt=p[1]+GAP
     F(lx,bt,rw,SH-GH-bt,PIP)
     F(lx,bt,rw,4,PD)
   # Draw bird
   F(BX,nby,BSZ+2,BSZ,BC)
   # Wing
   if vy<0:F(BX-2,nby+BSZ-3,5,3,BW)
   else:F(BX-2,nby,5,3,BW)
   # Eye
   F(BX+BSZ-2,nby+1,3,3,WH)
   F(BX+BSZ-1,nby+2,2,2,BE)
   # Beak
   F(BX+BSZ+2,nby+BSZ//2-1,4,3,BW)
   # Collision with pipes
   for p in pipes:
    px=p[0];gy=p[1]
    if BX+BSZ+2>px and BX<px+PW:
     if nby<gy or nby+BSZ>gy+GAP:
      alive=False
   # Ground redraw
   F(0,SH-GH,SW,GH,GND)
   fr+=1
   # Speed ramp
   spd=2.0+sc*0.06
   Z(0.028)
  # Death animation
  for i in range(8):
   F(BX,int(by),BSZ+8,BSZ+2,SKY)
   by+=3;vy=0
   if by>SH-GH-BSZ:by=float(SH-GH-BSZ)
   F(BX,int(by),BSZ+2,BSZ,(220,60,60))
   Z(0.04)
  Z(0.5)
  # Game over overlay
  F(70,60,180,90,BK)
  F(72,62,176,86,(25,)*3)
  D("GAME OVER",108,68,(255,70,70),(25,)*3)
  D("Score: "+str(sc),120,92,WH,(25,)*3)
  if sc>0:
   D("Best effort!",106,115,(200,200,100),(25,)*3)
  D("OK=again",128,140,(120,)*3,(25,)*3)
  while True:
   if K(17):return
   if okp():wup();break
   Z(0.05)

if title():flappy()

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.