This is a numworks demake of the cats are liquid game by last quarter studios.
In it’s current state, it is more of a proof of concept than a real game. Still, the scrolling and the physics engine are pretty powerful considering the platform, and even if the code is not commented, you should be able to reuse them, mod them, and do your own game with them.
I don’t regret at all the time spent on this I could’ve used studying in math class, i just hope that my grades won’t be that bad at the end of the year…
The game have very basic controls:
I don’t think this is necessary but just in case, i put this game, this engine, the sprites and all of the code under a permissive creative commons 4.0 attribution license
This means that you can share, modify, study, and do everything you want with my work as long as you tell others that i, heredos, am the author of the original work.
Please also note that the idea of the game, the lumi character, and all of the source material i used as an inspiration are the property of Last Quarter Studios Limited Partnership, and i DO NOT own any of them.
I removed all the comments because it would take too much space on the small calculator memory, and this description has a character limit, so, sorry.
from random import randint from time import sleep from kandinsky import * from ion import * class sp: def ld(self,c,sx): a=0 self.bmp=[] while c>0: self.bmp+=[[]] for i in range(sx): self.bmp[a]+=[c%2] c=c//2 a+=1 def __init__(self): self.bmp=[[],[]] self.size=(4,4) def drw(self,x,y,color): for i in range(len(self.bmp)): for j in range(len(self.bmp[i])): if self.bmp[i][j]: set_pixel(j+x,i+y,color) def drwr(self,x,y,r,color): if r==0: self.drw(x,y,color) elif r==1: a=len(self.bmp) for i in range(a): b=len(self.bmp[i]) for j in range(b): if self.bmp[i][j]: set_pixel(x+a-i-1,y+j,color) elif r==2: a=len(self.bmp) for i in range(a): b=len(self.bmp[i]) for j in range(b): if self.bmp[i][j]: set_pixel(x+b-j-1,y+a-i-1,color) elif r==3: for i in range(len(self.bmp)): b=len(self.bmp[i]) for j in range(b): if self.bmp[i][j]: set_pixel(x+i,y+b-j-1,color) sprites=(sp(),sp(),sp(),sp()) sprites[0].ld(8861580,6) sprites[1].ld(72342380552863743,8) sprites[2].ld(4340483223793664385,16) sprites[3].ld(4359202964317896252,8) def menu(): fill_rect(0,0,320,222,(0,0,0)) draw_string("CALculator beta 2",70,10,"white","black") draw_string("press (OK) to play",65,40,"white","black") draw_string("press (EXE) to quit",60,100,"white","black") while 1: if keydown(KEY_OK): game() if keydown(KEY_EXE): exit() def drwlumi(): global sprites,xvel,yvel,form,lastform s=24 p=(158,99) if form!=lastform: if lastform==2: a=int(xvel*2) if a>0: fill_rect(163-a-4,103,16+a,16,(0,0,0)) if a<0: fill_rect(163+4,103,16-a,16,(0,0,0)) if form==1: fill_rect(159,99,24,24,(255,255,255)) sprites[1].drw(159,99,(0,0,0)) sprites[1].drwr(175,115,2,(0,0,0)) sprites[1].drwr(159,115,3,(0,0,0)) sprites[1].drwr(175,99,1,(0,0,0)) sprites[0].drw(163,105,(50,200,255)) sprites[0].drw(173,105,(50,200,255)) sprites[2].drw(163,113,(50,200,255)) elif form==2: fill_rect(159,99,24,24,(0,0,0)) fill_rect(163,103,16,16,(50,50,255)) sprites[1].drwr(163+4+8,103,1,(0,0,0)) sprites[1].drwr(163+4+8,111,2,(0,0,0)) sprites[1].drw(163-4,103,(0,0,0)) sprites[1].drwr(163-4,111,3,(0,0,0)) elif form==0: fill_rect(159,99,24,24,(0,0,0)) for i in range(16): sprites[3].drw(randint(159,175),randint(99,115),(100,100,100)) sprites[0].drw(163,105,(50,200,255)) sprites[0].drw(173,105,(50,200,255)) sprites[2].drw(163,113,(50,200,255)) elif form==2: a=int(xvel) if a>0: fill_rect(163-a-4,103,16+a,16,(50,50,255)) fill_rect(163-a-4-a,103,a,16,(0,0,0)) sprites[1].drw(163-a-4,103,(0,0,0)) sprites[1].drwr(163-a-4,111,3,(0,0,0)) if a<0: fill_rect(163+4,103,16-a,16,(50,50,255)) fill_rect(163+16-a+4,103,16-a,16,(0,0,0)) sprites[1].drwr(163-a+4+8,103,1,(0,0,0)) sprites[1].drwr(163-a+4+8,111,2,(0,0,0)) def sgn(x): return -(x<0)+(x>0) def col(r): for i in r: a=i def game(): global form global orientation global lastform global xvel fill_rect(0,0,xmax(),ymax(),(0,0,0)) r=(rect(60,0,240,30),rect(100,100,15,15,(255, 126, 65)),rect(0,200,1000,100),rect(0,50,20,150),rect(300,0,150,180), rect(450,0,200,30),rect(500,170,200,30),rect(700,-100,20,300)) orientation=(0,0) lastform=-1 form=1 xvel=0 yvel=0 x=0 y=0 onwall=False onground=0 onceil=False box=((159,99,183,123),(159,99,183,123),(163,103,169,119)) sprites=(sp(),sp(),sp(),sp()) sprites[0].ld(8861580,6) sprites[1].ld(72342380552863743,8) sprites[2].ld(4340483223793664385,16) sprites[3].ld(4359202964317896252,8) drwlumi() lastform=1 while 1: lastform=form if onground<=9: yvel+=(form+1)*0.2 else: yvel=0 if keydown(KEY_UP): if onceil: yvel=0 elif onground>0 : form=0 yvel=-10 onground=0 elif yvel>0 and form==0:yvel=0 elif keydown(KEY_DOWN): form=2 drwlumi() if lastform!=2: for i in r: i.erase(0,4) for i in r: i.rewrite(0,4) elif keydown(KEY_OK)|keydown(KEY_EXE): if onground>0: yvel=-10 onground=0 if onwall and not onceil: yvel=-2 form=1 else: form=1 if lastform==2 and form!=2: tmp=False if onground: for i in r: if i.col(add(box[0],(0,-4,0,-4))): tmp=True else: for i in r: if i.col(box[form]): tmp=True if tmp: form=2 if yvel<0: yvel=0 else: if onground: for i in r: i.erase(0,-4) for i in r: i.rewrite(0,-4) if keydown(KEY_LEFT): xvel-=0.5 elif keydown(KEY_RIGHT): xvel+=0.5 else: xvel-=sgn(xvel)*0.1 if keydown(KEY_HOME): menu() if abs(xvel)>(3*form**2) and xvel!=0: xvel-=sgn(xvel) drwlumi() onwall=False for i in r: i.erase(int(xvel),int(yvel)) for i in r: i.rewrite(int(xvel),int(yvel)) if i.col(add(box[form],(xvel,yvel,xvel,yvel))): if i.col(add(box[form],(xvel,-1,xvel,-1))): onwall=True if i.col(add(box[form],(0,yvel,0,yvel))): onground=10 if onwall: xvel=-xvel onceil=False if onground>0: if yvel<0: yvel=-yvel onground=0 onceil=True else: onground-=1 yvel=0 if onground<0: onground=0 orientation=(sgn(xvel),sgn(yvel)) if 0: fill_rect(0,0,40,40,(0,0,0)) draw_string(str(onground)+str(yvel),0,0) sleep(0.05) def xmax(): return 340 def ymax(): return 222 def add(a,b): d=min(len(a),len(b)) c=[i for i in range(d)] for i in range(d): c[i]=a[i]+b[i] return c class rect: def __init__(self,x,y,w,h,c=(255,255,255)): fill_rect(x,y,w,h,c) self.x=x self.y=y self.w=w self.h=h self.c=c def erase(self,ax,ay): ax,ay=-ax,-ay if self.col((0,0,xmax(),ymax())): if ax>0: fill_rect(self.x,self.y,ax,self.h,'black') self.x+=ax elif ax<0: fill_rect(self.x+self.w+ax,self.y,-ax,self.h,'black') self.w-=abs(ax) if ay>0: fill_rect(self.x,self.y,self.w,ay,'black') self.y+=ay elif ay<0: fill_rect(self.x,self.y+self.h+ay,self.w,-ay,'black') self.h-=abs(ay) else: if ax>0: self.x+=ax self.w-=abs(ax) if ay>0: self.y+=ay self.h-=abs(ay) def rewrite(self,ax,ay): ax,ay=-ax,-ay if self.col((-ax,-ay,xmax()-ax,ymax()-ay)): if ax>0: fill_rect(self.x+self.w,self.y,ax,self.h,self.c) elif ax<0: fill_rect(self.x+ax,self.y,-ax,self.h,self.c) self.x+=ax self.w+=abs(ax) if ay>0: fill_rect(self.x,self.y+self.h,self.w,ay,self.c) elif ay<0: fill_rect(self.x,self.y+ay,self.w,-ay,self.c) self.y+=ay self.h+=abs(ay) else: if ax<0: self.x+=ax self.w+=abs(ax) if ay<0: self.y+=ay self.h+=abs(ay) def col(self,r): return ((r[0]<self.x+self.w) and (r[2]>self.x)) and ((r[1]<self.y+self.h) and (r[3]>self.y)) def decomp_char(c): a=int("0x"+c) b=[] while a>0: b+=[a%2] a=a//2 return b.reverse() def intro(): s="a project inspired by..." for i in range(len(s)): draw_string(s[i],35+10*i,101) sleep(0.05) for i in range(len(s)): fill_rect(35+10*i,101,10,20,(255,255,255)) sleep(0.05) for i in range(90): for j in range(i): set_pixel(i-j-1+170,90-j+10,(0,0,0)) set_pixel(90-(i-j-1)+60,j-1+121,(0,0,0)) set_pixel(90-(i-j-1)+60,90-(j)+10,(0,0,0)) sleep(0.0001) for i in range(45): for j in range(i): set_pixel(i-j-1+170,j+121,(255,200,100)) sleep(0.01) for i in range(33): fill_rect(0,0,i*10,222,color(0,0,0)) sleep(0.1) menu() intro()