ruin_lite.py

Created by fime

Created on May 02, 2022

8.62 KB

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