compression of https://github.com/arthur-jacquin/numworks-games slight speed upgrade. reduce score (bottom of the code) for less ennemies. doable with 25 bullets, even 22.
from math import* from kandinsky import fill_rect as F,draw_string as D from ion import keydown as K from time import monotonic as M from random import randint as R px,py=0,0 pdx,pdy,pa=0,0,pi/4 shooting=None bullets=25 pi2=pi/2 pi3=(3*pi)/2 _2pi=2*pi map=[ 1,1,2,1,1,1,1,1,1, 1,0,0,0,0,0,0,0,1, 1,1,1,0,1,1,5,3,5, 8,0,0,0,0,0,1,0,1, 1,1,1,0,1,1,1,0,1, 1,0,0,0,0,0,0,0,1, 1,0,1,5,3,5,1,0,1, 1,0,1,0,0,3,0,0,1, 1,1,1,0,1,5,1,1,1, 1,0,0,0,0,0,0,0,1, 1,0,4,0,0,0,4,0,1, 1,0,0,0,0,0,0,0,1, 1,0,4,4,0,4,4,0,1, 1,0,4,4,0,4,4,0,1, 1,0,0,0,0,0,0,0,1, 1,0,4,4,0,4,4,0,1, 1,0,4,4,0,4,4,0,1, 1,0,0,0,0,0,0,0,1, 1,1,1,1,1,1,5,3,5, 1,0,0,0,0,0,0,0,1, 1,0,4,4,4,4,4,0,1, 1,0,5,0,0,0,4,0,1, 1,0,3,0,6,0,4,0,1, 1,0,5,0,0,0,4,0,1, 1,0,4,4,4,4,4,0,1, 1,0,0,0,0,0,0,0,1, 1,1,7,7,3,7,7,1,1, 1,1,1,1,0,1,1,1,1, 1,0,0,0,0,0,0,0,1, 1,0,1,1,1,1,1,0,1, 1,0,1,0,0,0,1,0,1, 1,0,1,0,1,0,1,0,1, 1,0,1,0,1,0,1,0,1, 1,0,0,0,0,0,0,0,1, 1,1,1,1,1,1,1,1,1, ] mapX=9 mapY=int(len(map)/mapX) mapS=64 mapL=mapX*mapY textureSize=8 textures=((0b01111110, 0b01111110, 0b00000000, 0b11100111, 0b11100111, 0b00000000, 0b01111110, 0b01111110), (0b10011111, 0b10011011, 0b11111111, 0b11110111, 0b10111101, 0b10100101, 0b10111101, 0b11111111), (0b00000000, 0b11100111, 0b10100101, 0b10100101, 0b00100100, 0b11100111, 0b11100111, 0b00000000), (0b11100011, 0b11110001, 0b11111000, 0b01111100, 0b00111110, 0b00011111, 0b10001111, 0b11000111), (0b00000000, 0b01111110, 0b00000000, 0b01111110, 0b01111110, 0b00000000, 0b01111110, 0b00000000), (0b00000000, 0b00010000, 0b00110000, 0b01111110, 0b01111110, 0b00110000, 0b00010000, 0b00000000), (0b00000000, 0b01111110, 0b01111110, 0b01111110, 0b01111110, 0b01111110, 0b01111110, 0b00000000), (0b00000000, 0b00100100, 0b00100100, 0b00000000, 0b00111100, 0b01000010, 0b01000010, 0b00000000)) doorTexture=3 ennemySprites=(( (2,0,1,2), (5,0,1,2), (2,3,4,1), (1,4,1,2), (6,4,1,2)), ((2,0,1,2), (5,0,1,2), (2,4,4,1), (1,5,1,2), (6,5,1,2)), ((2,0,1,2), (5,0,1,2), (2,5,4,1), (1,6,1,2), (6,6,1,2)), ((2,0,1,2), (5,0,1,2), (2,4,4,1), (1,5,1,2), (6,5,1,2))) ents=[] def movePl(dt): global px,py,pa,pdx,pdy,shooting,bullets;xo,yo=20,20 if pdx<0:xo=-20 if pdy<0:yo=-20 ipx,ipxAddXo,ipxSubXo=int(px)>>6,int(px+xo)>>6,int(px-xo)>>6;ipy,ipyAddYo,ipySubYo=int(py)>>6,int(py+yo)>>6,int(py-yo)>>6 if K(4): if map[ipyAddYo*mapX+ipxAddXo]==doorTexture:map[ipyAddYo*mapX+ipxAddXo]=0 elif shooting==None and bullets>0:shooting=1;bullets-=1 if shooting==0:shooting=None if K(1): if map[ipy*mapX+ipxAddXo]==0:px+=pdx*50*dt if map[ipyAddYo*mapX+ipx]==0:py+=pdy*50*dt elif K(2): if map[ipy*mapX+ipxSubXo]==0:px-=pdx*50*dt if map[ipySubYo*mapX+ipx]==0:py-=pdy*50*dt if K(0): tpa=pa-pi2;tpdx,tpdy=cos(tpa)*50,sin(tpa)*50;xo,yo=20,20 if tpdx<0:xo=-20 if tpdy<0:yo=-20 ipx,ipxAddXo,ipxSubXo=int(px)>>6,int(px+xo)>>6,int(px-xo)>>6;ipy,ipyAddYo,ipySubYo=int(py)>>6,int(py+yo)>>6,int(py-yo)>>6 if map[ipy*mapX+ipxAddXo]==0:px+=tpdx*dt if map[ipyAddYo*mapX+ipx]==0:py+=tpdy*dt elif K(3): tpa=pa+pi2;tpdx,tpdy=cos(tpa)*50,sin(tpa)*50;xo,yo=20,20 if tpdx<0:xo=-20 if tpdy<0:yo=-20 ipx,ipxAddXo,ipxSubXo=int(px)>>6,int(px+xo)>>6,int(px-xo)>>6;ipy,ipyAddYo,ipySubYo=int(py)>>6,int(py+yo)>>6,int(py-yo)>>6 if map[ipy*mapX+ipxAddXo]==0:px+=tpdx*dt if map[ipyAddYo*mapX+ipx]==0:py+=tpdy*dt if K(33):pa=(pa-dt)%_2pi;pdx=cos(pa);pdy=sin(pa) elif K(34):pa=(pa+dt)%_2pi;pdx=cos(pa);pdy=sin(pa) def dist(ax,ay,bx,by):return sqrt((bx-ax)*(bx-ax)+(by-ay)*(by-ay)) def distSq(ax,ay,bx,by):return(bx-ax)*(bx-ax)+(by-ay)*(by-ay) def rays(): global mapS,mapX,mapY,map,s,distMax;r=mx=my=mp=hit=rx=ry=ra=xo=yo=distMax=i=th=tv=0;ra=(pa-HFOV)%_2pi while i<RAYS: if ra==0 or ra==pi:rx=px;ry=py;hit=1 else: hit=0;disH,hx,hy=1000000,px,py;aTan=-1/tan(ra) if ra>pi:ry=((int(py)>>6)<<6)-.0001;rx=(py-ry)*aTan+px;yo=-64;xo=-yo*aTan if ra<pi:ry=((int(py)>>6)<<6)+64;rx=(py-ry)*aTan+px;yo=64;xo=-yo*aTan while 1-hit: mx=int(rx)>>6;my=int(ry)>>6;mp=my*mapX+mx if mp<0 or mp>=mapL or map[mp]>0: if mp>0 and mp<mapL:th=map[mp] hx=rx;hy=ry;disH=distSq(px,py,hx,hy);hit=1 else:rx+=xo;ry+=yo if ra==pi2 or ra==pi3:rx=px;ry=py;hit=1 else: hit=0;disV,vx,vy=1000000,px,py;nTan=-tan(ra) if ra>pi2 and ra<pi3:rx=((int(px)>>6)<<6)-.0001;ry=(px-rx)*nTan+py;xo=-64;yo=-xo*nTan if ra<pi2 or ra>pi3:rx=((int(px)>>6)<<6)+64;ry=(px-rx)*nTan+py;xo=64;yo=-xo*nTan while 1-hit: mx=int(rx)>>6;my=int(ry)>>6;mp=my*mapX+mx if mp<0 or mp>=mapL or map[mp]>0: if mp>0 and mp<mapL:tv=map[mp] vx=rx;vy=ry;disV=distSq(px,py,vx,vy);hit=1 else:rx+=xo;ry+=yo if disV<disH:t=tv;rx=vx;ry=vy;disT=disV;shade=.7 else:t=th;rx=hx;ry=hy;disT=disH;shade=.9 disT=sqrt(disT);depth=shade*25600/disT if depth>128*shade:depth=128*shade lineH=int((mapS<<8)/(disT*cos(pa-ra)));line8th=lineH/8;tyo=0 if lineH>SH:tyo=int(lineH-SH)>>1;lineH=SH o=int(SH-lineH)>>1 if shade==.9: tx=int(rx%mapS)>>3 if ra<pi:tx=7-tx else: tx=int(ry%mapS)>>3 if ra>pi2 and ra<pi3:tx=7-tx txo=7-tx;s[i][0]=o;s[i][1]=t;s[i][2]=txo;s[i][3]=tyo;s[i][4]=depth;s[i][5]=lineH;s[i][6]=line8th;s[i][7]=disT if disT>distMax:distMax=disT ra+=deltaa if ra<0:ra+=_2pi elif ra>_2pi:ra-=_2pi i+=1 def render(): global s;x,i=0,0 while x<SW: o=s[i][0];t=s[i][1];txo=s[i][2];tyo=s[i][3];depth=s[i][4];lineH=s[i][5];line8th=s[i][6];i+=1 if not tyo:F(x,0,W,o,(75,)*3) if depth>20: off=o-tyo;ct=-1 if tyo:outOfScreen=int(tyo/line8th);begin=1+outOfScreen;end=8-outOfScreen;starty=outOfScreen*line8th else:begin,end=1,8;starty=0 c=(textures[t-1][begin-1]>>(txo))&1;l=line8th for y in range(begin,end): ct=(textures[t-1][y]>>(txo))&1 if ct==c:l+=line8th else: if c:F(x,int(starty)+off,W,ceil(l),(depth,)*3) else:F(x,int(starty)+off,W,ceil(l),"k") c=ct;starty+=l;l=line8th if c:F(x,int(starty)+off,W,ceil(l),(depth,)*3) else:F(x,int(starty)+off,W,ceil(l),"k") else:F(x,o,WIDTH,lineH,"k") if not tyo:F(x,o+lineH,W,1+o,(100,)*3) x+=W def sprites(): global score,bullets;i=0 while i<len(ents): ex,ey=ents[i][0],ents[i][1] if px>ex:xo=20 else:xo=-20 if py>ey:yo=20 else:yo=-20 ipx,ipxAddXo=int(ex)>>6,int(ex+xo)>>6;ipy,ipyAddYo=int(ey)>>6,int(ey+yo)>>6 if map[ipy*mapX+ipxAddXo]==0:ex+=xo>>3 if map[ipyAddYo*mapX+ipx]==0:ey+=yo>>3 ents[i][0]=ex;ents[i][1]=ey;dsq=(px-ex)**2+(py-ey)**2;d=sqrt(dsq) if d>distMax:i+=1;continue ax=px+pdx*d;ay=py+pdy*d;a=(ax-ex)**2+(ay-ey)**2;delta=acos(1-a/(2*dsq)) if delta<=HFOV: distToHigh=(px+(pdx*COSPI6-pdy*SINPI6)*d-ex)**2+(py+(pdy*COSPI6+SINPI6*pdx)*d-ey)**2;distToLow=(px+(pdx*COSPI6+pdy*SINPI6)*d-ex)**2+(py+(pdy*COSPI6-SINPI6*pdx)*d-ey)**2 if distToLow<distToHigh:delta*=-1 ray=int(HRES*delta/HFOV)+HRES if s[ray][7]>d: scale=int(1280/d);projx=tan(delta)*d*COSPI6;sx=int((projx*SW)/d+HSW) if shooting and projx<10 and projx>-10: ents.remove(ents[i]);score-=1 if not score:win();info();i+=1;continue t=int(M()%len(ennemySprites));sprite=ennemySprites[t] for r in range(len(sprite)):F((sprite[r][0]-4)*scale+sx,(sprite[r][1]-4)*scale+HSH,sprite[r][2]*scale,sprite[r][3]*scale,(0,255,0)) if d<20:lose() i+=1 def dGun(): global shooting if shooting:F(140,109,10,3,"r");F(170,109,10,3,"r");F(159,91,3,10,"r");F(159,121,3,10,"r");shooting=0 else:F(140,109,10,3,"w");F(170,109,10,3,"w");F(159,91,3,10,"w");F(159,121,3,10,"w") def init(): global pdx,pdy,s,px,py,pa;px,py=64*5.5,64*3.5;pdx,pdy,pa=0,0,pi;pdx,pdy=cos(pa),sin(pa);s.clear() for i in range(RAYS):s.append([0]*8) def spawn(): ex=R(0,(mapX-1)<<6);ey=R(0,(mapY-1)<<6) while map[(ey>>6)*mapX+(ex>>6)]!=0 or dist(px,py,ex,ey)<128:ex=R(0,(mapX-1)<<6);ey=R(0,(mapY-1)<<6) ents.append([ex,ey,0]) def rendergun():F(260,150,60,50,(100,100,150));F(240,140,40,40,(100,100,150));F(250,170,20,20,(100,100,150));F(270,145,40,20,(100,100,150));F(250,125,10,15,(100,100,150));F(280,180,45,40,(100,10,30));F(290,220,35,10,(100,10,30));F(282,170,35,10,(100,10,30)) def lose():global on;D("GAME OVER",115,60);on=0 def win():global on;D("YOU WIN",120,60);on=0 def info():D("ennemies left: "+str(score),0,0,"w",(75,)*3);D("bullets: "+str(bullets),0,20,"w",(75,)*3) def startScreen(): F(0,0,320,222,"w");D("BAD GUYS SHOOTER",75,20,"r");D("Instructions:",95,80);D("[ARROWS] move",95,110);D("[PARENTHESIS] turn",70,130);D("[OK] open doors and shoot",35,150);D("[XNT] start the game",60,170);D("Shoot all the bad guys!",50,200,"r") while 1-K(14):0 on=1 lv=1 def main(): startScreen();init();rays();dt=0;t1=M();t2=t1;f=t1;c=0 for i in range(score):spawn() i=0 while on:t2=M();dt=t2-t1;t1=t2;movePl(dt);rays();render();info();sprites();dGun();rendergun() SW=320 SH=222 HSW=SW>>1 HSH=SH>>1 FOV=pi/3 RAYS=32 HRES=RAYS>>1 W=SW//RAYS s=[] distMax=0 deltaa=FOV/RAYS HFOV=pi/6 COSPI6=sqrt(3)/2 SINPI6=1/2 score=100 if SW%RAYS!=0:print("Screen resolution not compatible\nwith screen width") else:main()