ОММММ€€€¬ЄЄЄ¬€€€¬МММ¬МАМ¬МАМ¬МАМММмо€€МоЄЄАо€ЁАоМ¬АМА¬ААА¬ААА¬ААОММММ€€€¬ЄЄЄ¬€€€¬МММ¬МММ¬МАМ¬МАМММмо€€МоЄЄАо€ЁАоМ¬АММ¬ААА¬ААА¬АА¬МММ¬ЄЄЄ¬Є¬Є¬ЄКМ¬ЄЄЄЊ€€€МАМОММОМ¬МЄЄАм¬ЄАоЄЄАоЄЄАо€€МоАмоММоо¬МММ¬ЄЄЄ¬Є¬Є¬ЄКМ¬ЄЄЄЊ€€€МАМОММОМ¬МЄЄАм¬ЄАоЄЄАоЄЄАо€€МоАмоММоо >Р=""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""воо""""""вооо""""""""""вооо""""""""""""""воо""""""вооо""""""""""вооо""""""""""""""воо""""""вооо""""""""""вооо""""""""""""""тоо""""""вояя""""""""""вооо""""""""""""""тоо""""""вояя""""""""""вооо""""""""""""""тоо""""""вояя""""""""""воооа""""""тяяяяоо""""""воя""""""сяоооооооооа""""""тяяяяоо""""""воя""""""сяоооооооооа""""""тяяяяоо""""""воя""""""сяоооооооооа""""""тяяяяоо""""""воя""""""сяооооооооо""""""тяяяяоо""""""воя""""""сяооооооооо""""""тяяя""""""воя""""""сяооооооооо""""""тяяя""""""воя""""""тяяоооо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""тяяя""""""воя""""""тяяо""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""вооо""""""тяо""""""вооя""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояяс""""""""""""""""тяяя""""""вояя""""""""""""""""тяяя""""""вояя""""""""""вооо""""""тяяя""""""вояя""""""""""вооо""""""тяяя""""""вояя""""""""""вооо""""""тяяя""""""вояя""""""""""вооосяяяяяяаоооояясяооооооооосяяяяяяаоооояясяооооооооосяяяяяяаоооояясяооооооооосяяяяяяаоооояясяооооооооосяяяяяяаоооояясяооооооооосяяяяяяаоооояясяоооооооооаоооояясяооооооооосяоооооооооDDD@ADAADAD@DAAAAAAAAD@A@AAAA@DDD@DD@DD@DD@@@@@D8-- title: FauxjiBoink! -- author: @jtruk -- desc: A riff on a classic Atari demo. Compressed: <1k bytes -- script: lua -- group: Hex Heroes -- date: Feb 2023 -- release: Lovebyte Feb 2023 -- license: Code Credit License v1.1.0 T=0 -- TIME -- Time triggers -- 3300 (~1 minute / Max running time) T_FUJIDROP=120 T_FUJIMOVE=158 T_TWEEN_ON=500 T_TWEEN_OFF=1260 T_WARP_ON=1560 T_WARP_OFF=2320 T_HEART_MELT=2160 T_TILESPLODE=3010 T_NOFLOOR=3250 -- The main model (tween between these) MODEL_NOW=0 MODEL_NEXT=1 -- This is the twist within the model WARP_FACTOR=0 -- Object -- Affectionately known as FUJI through -- the code, but morphs into other -- models FUJI={ x=120, y=60, moving=true, xm=0, -- x movement ym=0, -- y movement r=0, -- rotation } -- Sound volume VOL=0 -- Setup background tiles -- Spent a chunk of codesize budget -- on this just for the thrill of -- them exploding =) TILES={} for i=0,20 do -- 7 tiles across x=i%7 -- 3 rows. Shifted for alternate cols y=i//7 TILES[i+1]={ x=60+x*20, y=20+(y*2+x%2)*20, -- NB: There's a time switch that -- prevents these from animating -- before we're ready moving=true, -- Make each one fall in a different -- way xm=2*math.random()-1, ym=-math.random(), r=.8, } end -- Set palette... -- [0RGB][1RGB] white, then red P={1,1,1,1,0,0} for i=1,6 do poke(0x3FC0+i-1,P[i]*255) end -- Rainbow effect on colour 2 -- Didn't quite accurately nail the -- colours of the original, but may -- only be me who notices! function SCN(n) for i=0,2 do poke( 0x3FC6+i, -- changes with time -- corrects for object display height -- different cycle periods for R,G,B T*(9+i)+(FUJI.y-n)*32 ) end end tweenTime=0 function TIC() cls() -- Move and draw tiles for i=1,#TILES do doTile(TILES[i]) end -- Draw some text A="FauxjiBoink!" textX=179 -- steal the volume to bounce the text textY=126-math.sin(VOL) print(A,textX,textY,4) print(A,textX-1,textY-1,1) if T>T_FUJIDROP then -- Fuji has started if doMove(FUJI,1) then -- returns true if we have hit the -- side or the floor VOL=15 end end -- Start Fuji moving sideways if T==T_FUJIMOVE then FUJI.xm=1 end -- Warp if T>=T_WARP_ON and T2, we clamp it to 1 -- and do nothing else, which gives -- some time between tweens to admire -- the model :) tweenPos=0 if T>T_TWEEN_ON and T2 then -- switch model MODEL_NOW=MODEL_NEXT MODEL_NEXT=(MODEL_NOW+1)%2 tweenTime=0 tweenPos=0 elseif tweenPos>1 then tweenPos=1 end tweenTime=tweenTime+1 end -- The Fuji is 60 pixels high -- Iterate through, finding the six -- points for this row to draw -- These points are taken from vector -- model definitions, and warped/blended for y=0,60 do rowRot=FUJI.r+(30-y)*WARP_FACTOR^3/8 c=math.cos(rowRot) s=math.sin(rowRot) unitY=y/60 wedgeW=7*s -- the width of the side modelTween1=MODEL_NOW modelTween2=MODEL_NEXT -- heart if T>T_HEART_MELT then if(y<(T-T_HEART_MELT)*2)then modelTween1=2 else modelTween1=0 end end -- When not blending, -- MODEL_NOW=MODEL_NEXT and this -- function does nothing useful! points=blend( tweenPos, getPoints(modelTween1,c,unitY), getPoints(modelTween2,c,unitY) ) u=FUJI.y-y --upside down y! drawSide(points,u,wedgeW,8) if(c>0)then -- colourful front drawFace(points,u,wedgeW,2) else -- back drawFace(points,u,-wedgeW,9) end end -- Cheap shadow casting -- Move up and left across the screen -- If the destPixel is red or white -- (i.e. background) then we can cast -- against it -- If the chosen pixel up and to the -- left of it is one that casts a -- shadow then shift its index for y=136,7,-1 do for x=240,7,-1 do destPix=pix(x,y) if destPix<2 then -- Is background pixel if pix(x-7,y-(y+x)/30)>1 then -- Should cast pix(x,y,destPix+14) end end end end -- sound if(VOL>0 and T190 then hasHit=true ob.xm=-ob.xm end -- Gravity and floor bouncing newYm=ob.ym+.1 -- default: fall faster if(T130 then -- we've hit the floor hasHit=true if(ob.ym<.2)then -- This catches the tiles to freeze -- them when they're not bouncing -- much ob.moving=false else -- Flip the y movement, with damper newYm=-ob.ym*elasticity end end end ob.ym=newYm return hasHit end -- g: model index (0-1) -- r: x rotation -- x: x pos -- u: fractional y -- w: xscale -- Uses WARP(W): 0-1 function getPoints(modelId,rot,unitY) modelW=40 -- Models m={} -- FUJI a=math.min(.35+.6*(1.18-unitY)^7,1) b=math.min(.23+.6*(1-unitY)^5,1) m[1]={-a,-b,-.12,.12,b,a} -- TIC k=unitY>.8 l=k or unitY<.2 m[2]={ k and -1 or -.8, k and -.3 or -.5, -.15, .15, l and .5 or .3, l and 1 or .6 } -- LOVEBYTE HEART f=8-(unitY*9//1) w=1/7 h=w*(f<=1 and 1.5-f or f>=4 and f-8.5 or 5.5) j=f<=1 and (3.5+f)*w or 0 m[3]={ -h, -j, 0, 0, j, h } local points={} for i=1,6 do points[i]=FUJI.x +rot*m[modelId+1][i]*modelW end return points end function blend(factor,p1,p2) local points={} for i=1,6 do points[i]= (1-factor)*p1[i] + factor*p2[i] end return points end -- drawSide -- p: points -- y: ypix -- o: sideOffset -- c: colour function drawSide(p,y,o,c) for i=1,5,2 do -- p[i] and p[i+1]: span of front edge -- side if p[i]~=p[i+1] then -- Don't draw if zero width line(p[i]-o,y,p[i+1]+o,y,c) line(p[i]+o,y,p[i+1]-o,y,c) end end end -- drawFace -- p: points -- y: ypix -- o: sideOffset -- c: colour function drawFace(p,y,o,c) for i=1,5,2 do -- p[i] and p[i+1]: span of front edge if p[i]~=p[i+1] then line(p[i]+o,y,p[i+1]+o,y,c) end end end -- This is a utility function that -- may or may not have saved bytes -- Inputs: -- x and y -- dx and dy - already rotated, -- can swap these around flexibly -- since this is a square function drawQuad(x,y,dx,dy) -- Draw two triangles that have -- two points in common x0=x-dx y0=y-dy x3=x+dx y3=y+dy tri(x0,y0,x+dy,y-dx,x3,y3,1) tri(x0,y0,x-dy,y+dx,x3,y3,1) end -- Move and draw function doTile(tile) if T>T_TILESPLODE then doMove(tile,.83) end -- Tiles are 20 pix wide and high -- so the corners (NE,SE,SW,NW) -- are at radius distance sqrt(10^2+10^2) -- i.e. about 14. drawQuad( tile.x, tile.y, math.cos(tile.r)*14, math.sin(tile.r)*14 ) end