Lite version for Epsilon users.
Controls : - arrows : move and directing the bullets - ok : jump (hold to jump higher) - toolbox : shot bullets - backspace : pause
from math import * from kandinsky import fill_rect as drawRect,draw_string as drawTxt,get_pixel as getPxl from ion import keydown as key from time import monotonic as cTime,sleep from random import randint as rInt,seed as rSeed TARG_SPF=0.02 #50fps BG_COL,PL_COL,PTF_COL,NMY_COL,NMY_COL2,BLACK=(75,40,40),(240,10,10),(200,100,100),(0,150,255),(0,50,200),(0,0,0) NAME,AUTH,START_MSG,EDITOR_URL=" R U | N "," by F | M E ","Press [OK] to start","/python/fime/ruin_lvl_maker" class Entity(): def __init__(it,x,y,w,h,drawFonc): it.x,it.y,it.w,it.h=x,y,w,h it.draw=lambda:drawFonc(it) def hitBox(it,it2): if it.x<it2.x+it2.w and it2.x<it.x+it.w and it.y<it2.y+it2.h and it2.y<it.y+it.h:return 1 return 0 class Platform(Entity): def __init__(it,x,y,w,h):super().__init__(x,y,w,h,drawPlatform) def hitBox(it,it2): if super().hitBox(it2) and it2.y+it2.h<it.y+it.h:return 1 return 0 class Movable(Entity): def __init__(it,*arg): super().__init__(*arg) it.vx,it.vy,it.grounded=0,0,0 def setVel(it,vx,vy):it.vx,it.vy=vx,vy def addVel(it,vx,vy): it.vx+=vx it.vy+=vy def applyPhysics(it): if it.grounded: it2=it.grounded it.vy=0 if it.x>it2.x+it2.w or it2.x>it.x+it.w: it.grounded=0 else : it.addVel(0,0.2) it.y+=min(it.vy,4) it.vx/=1.3 it.x+=it.vx it.x=max(min(it.x,320-it.w),0) def onPlatform(it,plat): if plat.hitBox(it) and not it.grounded and it.vy>0: it.grounded=plat it.vy,it.y=0,plat.y-it.h def jump(it):it.vy,it.grounded=-4.3,0 class Enemy(Movable): def __init__(it,*arg): super().__init__(*list(arg)+[drawEnemy]) def applyPhysics(it): if it.grounded: it2=it.grounded if it2.w>20: if it.x<it2.x+it.w: it.vx+=0.05 elif it.x>it2.x+it2.w-it.w*2: it.vx-=0.05 elif it.vx==0: it.vx=1 super().applyPhysics() it.vx*=1.3 class Bullet(Movable): def __init__(it,it2,input_vy): super().__init__(it2.x+it2.w/2,it2.y+it2.h/2,3,3,drawBullet) it.setVel(copysign(3,it2.vx)+it2.vx,it2.vy+input_vy*2-1) def applyPhysics(it): it.addVel(0,0.2) it.x+=it.vx it.y+=it.vy def fade(col1,col2,n):return tuple([i1*(1-n)+i2*n for i1,i2 in zip(col1,col2)]) def shadow(it): for i in range(1,6): drawRect(int(it.x-i*2),int(it.y+i*it.h),it.w-i,it.h,fade(BLACK,BG_COL,i/6)) def drawBaseEntity(it,col): drawRect(int(it.x+2),int(it.y),it.w-2,it.h,col) drawRect(int(it.x),int(it.y),2,it.h,BLACK) def drawPlayer(it): drawBaseEntity(it,PL_COL) drawRect(int(it.x+it.w/2),int(it.y+7),2,3,BLACK) for i in (3,it.h-3):drawRect(int(it.x+i+it.vx/4),int(it.y+2),2,2,BLACK) def drawEnemy(it): drawBaseEntity(it,NMY_COL) drawRect(int(it.x+2),int(it.y+it.h/2),it.w-2,it.h//2,NMY_COL2) for i in (3,it.h-3):drawRect(int(it.x+i),int(it.y+it.h/2-2),2,5,BLACK) def hideEntity(it): drawRect(int(it.x),int(it.y),int(it.w),int(it.h),BG_COL) def drawPlatform(it): drawBaseEntity(it,PTF_COL) shadow(it) def drawDoor(it): drawRect(int(it.x),int(it.y),it.w,it.h,BLACK) for i in range(1,5): drawRect(int(it.x+1),int(it.y+it.h-i*2),int(it.w/2-i*2+3),1,fade(PTF_COL,BLACK,i/6)) def drawBullet(it):drawRect(int(it.x),int(it.y),it.w,it.h,PTF_COL) def createDoor(l1): x,y,w,h=l1 x,y,w,h=x+w//2-7.5,y-15,15,15 return Entity(x,y,w,h,drawDoor) def createPlayer(l1): x,y,w,h=l1 y,w,h=y-10,10,10 return Movable(x,y,w,h,drawPlayer) def createEnemy(l1,id): x,y,w,h=l1 x,y,w,h=x+10*id,y-10,10,10 return Enemy(x,y,w,h) def unpackPlatforms(n,type): string=levels(type)[n] Hex2Int=lambda n:int("0x"+n) level=[] for i in range(0,len(string),9): ptf_str=string[i:i+9] plat=[] for j in range(0,8,2):plat+=[Hex2Int(ptf_str[j:j+2])*5] plat.append(int(ptf_str[-1])) level.append(plat) return level def loadLevel(lvl,type): file=unpackPlatforms(lvl,type) platforms,enemies=[],[] for i in file: platforms+=[Platform(*i[0:4])] if i[4]: enemies+=[createEnemy(i[0:4],j) for j in range(i[4])] player,door=createPlayer(file[0][0:4]),createDoor(file[-1][:4]) return [player,platforms,enemies,door] def shortTransition(): for i in range(30):drawRect(0,0,320,222,fade(BG_COL,BLACK,sin(i/30))) def releaseKey(x): while key(x):pass class GameEngine(): def __init__(it,lvl_type="original"): it.lvl,it.status,it.total_frame,it.lvl_type,it.lvl_nb=0,0,0,lvl_type,len(levels(lvl_type)) def nextLevel(it): if it.status==2: game.playTransition(mode=1) it.lvl+=1 game.playTransition() else:shortTransition() def displayEndMsg(it): t=game.total_frame*TARG_SPF msg=["You finished the ", "{} original levels !".format(it.lvl_nb), "","Virtual time: {} min {}s".format(t//60,round(t%60,2)), "","Download the level maker at :", "my.numworks.com", EDITOR_URL] if it.lvl_type=="custom":msg=[msg[3]] for i,txt in enumerate(msg): drawTxt(txt,160-len(txt)*5,111-(len(msg)//2-i)*20,PTF_COL,BG_COL) def playTransition(it,h=222,mode=0): try:l=loadLevel(it.lvl,it.lvl_type) except:return entities,s_init,y=l[1]+[l[3]],20,int(h) if not mode: entities+=[l[0]]+l[2] for entity in entities:entity.y-=y del l while 1: if y<1:break if mode:s=(1-y/h)*s_init+5 else:s=sqrt(y/h)*s_init y=round(y-s,1) sleep(TARG_SPF*2) drawRect(0,0,320,222,BG_COL) for entity in entities: entity.y+=s entity.draw() def playLevel(it): drawRect(0,0,320,222,BG_COL) player,platforms,enemies,door=loadLevel(it.lvl,it.lvl_type) frame_nb,shot_frame,bullets,it.status=0,0,[],0 while it.status==0: t=cTime() frame_nb+=1 player.addVel(key(3)-key(0),0.1*(1-key(4))) if (frame_nb+9)%10==0:door.draw() for b in bullets: hideEntity(b) b.applyPhysics() if b.y>222:bullets.remove(b) else:b.draw() for movable in enemies+[player]: hideEntity(movable) if movable!=player: if movable.hitBox(player): it.status=1 break for b in bullets: if b.hitBox(movable): movable.addVel(b.vx/3,b.vy/3) if movable.y>222: enemies.remove(movable) movable.applyPhysics() for platform in platforms: movable.onPlatform(platform) if (frame_nb+9)%10==0 and movable==player:platform.draw() movable.draw() if frame_nb-shot_frame>10 and key(16): shot_frame=frame_nb bullets+=[Bullet(player,key(2)-key(1))] if player.grounded: if key(4):player.jump() if player.hitBox(door)==1:it.status=2 if player.y>222:it.status=1 while cTime()-t<TARG_SPF:pass if key(17): drawTxt(" P A U S E D ",95,101,BG_COL,PTF_COL) frame_nb+=10-frame_nb%10 releaseKey(17) while not key(17):pass releaseKey(17) drawRect(95,101,130,20,BG_COL) it.total_frame+=frame_nb def levels(lvl_type): if lvl_type!="custom":return ("011606010071632010391606010", "011606010111606010231606010341606010", "0216060101e1601010331606010", "042306010161c060100e1410011290f06011350f06010", "08280601026280a011342102010291b020100f1b0201003140a011190d0201026080a010", "0624060101a28020102b220201031190a01118160a0110a0e020101b070201030070a010", "0527060101927010102a27010103420060112819060110c19060110511010100b09010101a060a013330606010", "0428060100c2001010041c010100c16010102f1e01010391801010301101010260b0601012070a010", "0128060101526010103026010103921010102d1a010101a1501010230e01010310d0a010", "052506010051e06011051606011050f06011050806011301806010", "0628060101623060110c1e020101719020102b19020103b12020102b0c02010170c02010060906010", "0228060101d28060103122060111d1d020100e1b020100515020100e0f02010240d06011320d06010", "0105040100c05350100823010101a1f060111e1801010341206011280e06010280e06010", "362706010292006011351a020102f1302010042006011041706011080f010100c0706010", "032806010242806011342106011251906011081901010021201010090c01010150706011270706010", "042806010192306011251e06010311a060112514060100316060110a0e01010140806010", "3726060101f2601010042601010081e010101019010102519010102f1006011220b06010", "1a28060102a2306010331b01010251701010141706011051201010100a010101c0606010", "0327060100c20010101619010102119030112d1903011351306010260a060111a0a01010050a06010", "0220060101d1b020113117020111c0f06010", "2f28060101428040110422020100e1b04010271a04011321402010270e040110e0e04011040806010") else:return []#insert your lvl here game=GameEngine(lvl_type="")#"custom" for custom lvl game.playTransition() while game.lvl<game.lvl_nb: game.playLevel() game.nextLevel() game.displayEndMsg() # Commands: # arrows = move # toolbox/paste = fire # backspace/clear = pause