Pixel Plumber

On your display
A tiny one-button retro platform game for your AWTRIX NG pixel clock.
- Works with
- AWTRIX NG
- Topic
- Gaming
- Includes
- Script
Choose your display in the next step.
Flow description
Turn your AWTRIX NG into a tiny 32×8 platform game!
Pixel Plumber is an endless one-button runner built entirely as an AWTRIX NG Berry script. Your little pixel hero runs automatically while you use the Select button to jump.
Jump over pipes, stomp walking enemies and collect shimmering coin patterns along the way. Pipes can even be used as platforms, and coins appear in different formations to guide your jumps.
The world becomes progressively faster and obstacles appear at varying distances, so each run feels a little different and gets increasingly challenging.
Features include:
- 🎮 One-button gameplay
- 🏃 Animated pixel character
- 🟢 Pipes you can jump onto
- 👾 Enemies to avoid or stomp
- 🪙 Animated coin clusters and patterns
- ☁️ Scrolling background with parallax
- ⚡ Progressive difficulty
- 🏆 Score and high-score tracking
- 🎲 Procedurally varied encounters
Everything runs directly on the AWTRIX NG device as a lightweight Berry script, no external server or API required.
Controls: Press Select to jump. After game over, press Select to start a new run.
jpLKDCJvE0q6.ax
# @name Pixel Plumber
# @desc Tiny endless platform runner
# @version 1.3c
class PixelPlumber
var py
var vy
var jump
var alive
var ox
var ot
var cx
var cp
var cm
var cc
var score
var dist
var speed
var high
var last
var step
var seed
var dead
def init()
self.seed=now_ms()+731
self.high=0
self.start()
end
def start()
self.py=4
self.vy=0
self.jump=false
self.alive=true
self.score=0
self.dist=0
self.speed=180
self.last=now_ms()
self.step=0
self.cc=0
self.cm=0
self.new_obj()
end
def rnd(n)
self.seed=(self.seed*1103515245+12345)%2147483647
if self.seed<0
self.seed=-self.seed
end
return self.seed%n
end
def on_button(b)
if b!="select"
return
end
if !self.alive
self.start()
return
end
if !self.jump
self.vy=-2
self.jump=true
end
end
def new_obj()
var gap
if self.dist<10
gap=4+self.rnd(8)
elif self.dist<25
gap=3+self.rnd(8)
else
gap=2+self.rnd(8)
end
self.ox=32+gap
var r=self.rnd(10)
if r<2
self.ot=0
elif r<6
self.ot=1
else
self.ot=2
end
self.cc=0
self.cm=0
if self.rnd(100)<45
self.cx=self.ox-2
self.cp=self.rnd(4)
if self.cp==0 || self.cp==1
self.cc=4
else
self.cc=3
end
if self.cp==3 && self.ot!=0
self.cx=self.ox-1
end
end
end
def cy(i)
if self.cp==0
return 3
end
if self.cp==1
if i==0 || i==3
return 4
end
return 2
end
if self.cp==2
return 4-i
end
return 2
end
def die()
self.alive=false
self.dead=now_ms()
if self.score>self.high
self.high=self.score
end
end
def update()
if !self.alive
return
end
var n=now_ms()
if n-self.last<self.speed
return
end
self.last=n
self.step+=1
var old=self.py
if self.jump
self.py+=self.vy
self.vy+=1
end
self.ox-=1
if self.cc>0
self.cx-=1
end
var px=5
# pipe
if self.ot==1
if self.ox-1<=px+1 && self.ox+2>=px
if self.vy>=0 && old<=2 && self.py>=2
self.py=2
self.vy=0
self.jump=false
elif self.py>2
self.die()
return
end
end
if !self.jump && self.py==2
if self.ox+2<px || self.ox-1>px+1
self.jump=true
self.vy=1
end
end
end
# enemy
if self.ot==2
if self.ox<=px+1 && self.ox+1>=px
if self.py<=2 && self.vy>=0
self.score+=10
self.vy=-1
self.jump=true
self.ox=-5
else
self.die()
return
end
end
end
# coins
if self.cc>0
for i:0..self.cc-1
var bit=1<<i
if (self.cm&bit)==0
var x=self.cx+i*2
var y=self.cy(i)
if x>=px && x<=px+1
if y>=self.py && y<=self.py+1
self.cm=self.cm|bit
self.score+=1
end
end
end
end
end
# ground
if self.py>=4
self.py=4
self.vy=0
self.jump=false
end
# next encounter
if self.ox<-7
self.dist+=1
self.score+=1
if self.dist%5==0
self.speed-=5
if self.speed<105
self.speed=105
end
end
self.new_obj()
end
end
def world()
clear(0x001025)
var c=31-((self.step/3)%40)
pixel(c,1,0xAAAAAA)
pixel(c+1,0,0xFFFFFF)
pixel(c+1,1,0xFFFFFF)
pixel(c+2,1,0xAAAAAA)
rect_fill(0,6,32,2,0x8B4513)
for x:0..31
if ((x+self.step)%4)<2
pixel(x,6,0x38C84A)
end
end
end
def player()
var x=5
var y=self.py
pixel(x,y,0xFF2020)
pixel(x+1,y,0xFF2020)
if self.jump
pixel(x,y+1,0xFFD080)
pixel(x+1,y+1,0x1666FF)
elif self.step%2==0
pixel(x,y+1,0x1666FF)
pixel(x+1,y+1,0xFFD080)
else
pixel(x,y+1,0xFFD080)
pixel(x+1,y+1,0x1666FF)
end
end
def pipe()
var x=self.ox
# 4px top
rect_fill(x-1,4,4,1,0x00D848)
# 2px stem
rect_fill(x,5,2,1,0x00A838)
pixel(x,4,0x66FF77)
end
def enemy()
var x=self.ox
pixel(x,4,0xB86428)
pixel(x+1,4,0xB86428)
pixel(x,5,0x743716)
pixel(x+1,5,0x743716)
if self.step%2==0
pixel(x,4,0xFFFFFF)
else
pixel(x+1,4,0xFFFFFF)
end
end
def coins()
if self.cc==0
return
end
for i:0..self.cc-1
var bit=1<<i
if (self.cm&bit)==0
var f=(self.step+i)%3
var col=0xFFD000
if f==1
col=0xFF9500
elif f==2
col=0xFFFF99
end
pixel(
self.cx+i*2,
self.cy(i),
col
)
end
end
end
def gameover()
clear(0x080000)
if now_ms()-self.dead<2200
text(
1,
6,
str(self.score),
0xFFFFFF
)
else
text(
0,
6,
"HI",
0xFFCC00
)
text(
14,
6,
str(self.high),
0xFFFFFF
)
end
end
def draw()
if !self.alive
self.gameover()
return
end
self.update()
if !self.alive
self.gameover()
return
end
self.world()
if self.ot==1
self.pipe()
elif self.ot==2
self.enemy()
end
self.coins()
self.player()
end
end
return PixelPlumber()
Discussion 0
Ask a question, suggest a change or share how you use it.
No comments yet. Start the conversation.
More flows for AWTRIX NG Scripts or Gaming
Something wrong with this flow? Report it.
Have an idea?
Sign in to ask questions and join the conversation.