”勾配*フェード関数”の基本パターンの重ね合わせによるパーリンノイズのようなもの
前回可視化した、「勾配(ある方向に傾いた平面)*フェード関数」の基本パターンを
ランダムに重ね合わせてパーリンノイズのようなもの作るテストを、PiSTARTERで作ってみました~ヾ(*´∀`*)ノ
ちにゃみに、前回立体表示した基本パターンを濃淡で表すと、こげな感じです。
これは、左側が奥、右側が手前に傾いた「平面」に、「図の中心が重み100%、図の周辺が重み0%」になるような滑らかなフェード関数を掛け算した図です。
これを、
ランダムに回転しながらグリッド状(グリッド幅は図の辺の半分)に並べて重ね合わせる
と大きな濃淡の図ができます。さらにこの処理を、
「パターンの大きさを半分、濃度も半分、グリッド幅も半分」にして上から重ねる
と、1段階細かい模様ができます。これを適当な回数(今回は6回にしました)繰り返すと、いい感じに「大きな凸凹」から「小さな凸凹」までを含んだ濃淡ができるんですねー(゜◇゜)
なお、上記のパターンはこんな感じで作れます!
左上の図は、勾配f=[1,0]の平面の高さを濃淡で表したもの、つまり単純にX方向にいくにつれ白くなる画像です。
右上の図は、パーリンノイズのフェード関数
fade(t)=6*t^5–15*t^4+10*t^3
を使って、画像中心を原点とし、濃度=(1-fade(|x|))*(1-fade(|y|))を描画したものです。ただし、濃度はいずれも-1.0が黒、1.0が白です。
ところで、「のようなもの」ってどういうこと?
本物のパーリンノイズでは、フェード関数は座標軸に対して回転させず、勾配の方向のみをランダムに決めているのですが、このプログラムでは、勾配のパターンとフェードのパターンを毎回の掛け算せず、掛け算しちゃった後のパターンを回転させてます。
つまり、フェード関数の計算結果も含めて回転させてます。
フェード画像は点対称じゃないので、これを含めて回転させると、本物のパーリンノイズとは違う、ということに。(´・ω・‘)
そこで、どんな感じになるのかテストしてみたわけなんですが、これでも問題無い気がしました( ゚∀゚)
PiSTARTER用のプログラムはこちら:
' ' ”勾配*フェード関数”の基本パターンの重ね合わせによるパーリンノイズ by みなつ ' ' option strict acls 'var SW=640,SH=360 var SW=1280,SH=720 var CX=SW/2,CY=SH/2 xscreen SW,SH var camz=50 var grid=128 dim g[grid*4+1,grid*4+1] var gridCenter=grid*2 basePerlin var vramW=256,vramH=256 dim vram[vramW,vramH] width 16 color #lime while 1 cls:gcls var h for h=0 to 300 gline SW-10,SH-h,SW-1,SH-h,byg2rgb(h,1) next fill vram,0 locate 0,(SH div 16)-1 var o for o=0 to 5 var oct=pow(2,o) ?format$("Octave=%d Amp=1/%d",o+1,oct) make 1/oct,1/oct viewVram next wait 60*5 wend 'drawAll end def drawAll var x,y for y=0 to vramH-1 for x=0 to vramW-1 var c=(1+vram[x,y])*128 gpset x,y,rgb(c,c,c) next next end def make scl,amp var ix,iy,stp=grid*scl for iy=-stp to vramH-1+stp step stp for ix=-stp to vramW-1+stp step stp rotDraw ix,iy,scl,rad(rnd(360)),amp next next end def rotDraw x,y,scl,th,amp var u,v,size=grid*scl for v=max(-size,y-(VramH-1)) to min(size,y) for u=max(-size,-x) to min(size,vramW-1-x) var px=gridCenter+(u*cos(th)-v*sin(th))/scl var py=gridCenter+(u*sin(th)+v*cos(th))/scl if px<0 || py<0 || px>grid*4 || py>grid*4 then continue var gx=x+u var gy=y-v inc vram[gx,gy],g[px,py]*amp var c=(1+vram[gx,gy])*128 gpset gx,gy,rgb(c,c,c) next next end def basePerlin 'var maxc=0 var x,y var gradU=1,gradV=0 for y=-grid to grid var v=y/grid var fv=1-fad(abs(v)) for x=-grid to grid var u=x/grid var fu=1-fad(abs(u)) var c=(u*gradU+v*gradV)*fu*fv g[gridCenter+x,gridCenter+y]=c 'maxc=max(maxc,c) '?c 'c=(1+c/0.27)*128 'var col=rgb(c,c,c) 'gpset CX+x,CY-y,col next next '?"max=";maxc end def fad(t) return t*t*t*(t*(t*6-15)+10) end def viewVram dim cam[3],camTo[3] set camTo,0,0,0 'カメラの注視点 var th=rad(-90+20) var r=max(vramW,vramH)*0.9 set cam,r*cos(th),r*0.9,r*sin(th) 'カメラの位置 drawVram cam,camTo end def drawVram cam,camTo dim gx1[0],gy1[0] dim gx2[0],gy2[0] dim gx3[0],gy3[0] dim gx4[0],gy4[0] dim col[0] dim mz[0] dim ck[3]:sub ck,camTo,cam:norm ck dim ci[3]:roty ci,ck,pi()/2:ci[1]=0:norm ci dim cj[3]:cross cj,ck,ci:norm cj var tall=64 var i,j,stp=2 for j=-vramH/2 to (vramH-1)/2-stp step stp var y=vramH/2+j for i=-vramW/2 to (vramW-1)/2-stp step stp var x=vramW/2+i var p[3],cp[3],gx,gy,gz,scl,m=0,mag=SW var h=200+vram[x+0,y+0]*700 h=(h div 30)*30 push col,byg2rgb(h,1-0.2+vram[x+0,y+0]) set p,i+0,vram[x+0,y+0]*tall,-j+0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx1,gx:push gy1,gy inc m,gz set p,i+stp,vram[x+stp,y+0]*tall,-j+0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx2,gx:push gy2,gy inc m,gz set p,i+stp,vram[x+stp,y+stp]*tall,-j-stp sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx3,gx:push gy3,gy inc m,gz set p,i+0,vram[x+0,y+stp]*tall,-j-stp sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx4,gx:push gy4,gy inc m,gz push mz,m next next dim idx[len(mz)+1] for i=0 to len(mz)-1:idx[i]=i:next rsort mz,idx var ox=70,oy=-50 '表示オフセット var l=len(mz) for j=0 to l-1 i=idx[j] var c=col[i] var ggx1=gx1[i]+ox var ggx2=gx2[i]+ox var ggx3=gx3[i]+ox var ggx4=gx4[i]+ox var ggy1=gy1[i]+oy var ggy2=gy2[i]+oy var ggy3=gy3[i]+oy var ggy4=gy4[i]+oy gtri ggx1,ggy1,ggx2,ggy2,ggx3,ggy3,0 gtri ggx3,ggy3,ggx4,ggy4,ggx1,ggy1,0 gline ggx1,ggy1,ggx2,ggy2,c gline ggx2,ggy2,ggx3,ggy3,c gline ggx3,ggy3,ggx4,ggy4,c gline ggx4,ggy4,ggx1,ggy1,c next end def byg2rgb(h,v) 'h=0〜300 var hh=h*765/300 var r=255-abs(hh-510) var g=hh var b=510-hh return rgb(r*v,g*v,b*v) end '三次元ベクトル計算ルーチン(左手係) DEF V3$(A) RETURN FORMAT$("(%6.2F,%6.2F,%6.2F)",A[0],A[1],A[2]) END DEF PRNT A ?V3$(A) END DEF SET C,X,Y,Z C[0]=X C[1]=Y C[2]=Z END DEF ADD C,A,B C[0]=A[0]+B[0] C[1]=A[1]+B[1] C[2]=A[2]+B[2] END DEF SUB C,A,B C[0]=A[0]-B[0] C[1]=A[1]-B[1] C[2]=A[2]-B[2] END DEF MUL C,A,B C[0]=A[0]*B C[1]=A[1]*B C[2]=A[2]*B END DEF DIVD C,A,B C[0]=A[0]/B C[1]=A[1]/B C[2]=A[2]/B END DEF DIST(A) RETURN SQR(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]) END DEF IPROD(A,B) RETURN A[0]*B[0]+A[1]*B[1]+A[2]*B[2] END DEF CROSS C,A,B C[0]=A[1]*B[2]-B[1]*A[2] C[1]=A[2]*B[0]-B[2]*A[0] C[2]=A[0]*B[1]-B[0]*A[1] END DEF NORM A VAR D=SQR(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]) A[0]=A[0]/D A[1]=A[1]/D A[2]=A[2]/D END DEF ROTX C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=X C[1]=Y*CS-Z*SN C[2]=Y*SN+Z*CS END DEF ROTY C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=Z*SN+X*CS C[1]=Y C[2]=Z*CS-X*SN END DEF ROTZ C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=X*CS-Y*SN C[1]=X*SN+Y*CS C[2]=Z END DEF ROTN C,A,N,TH VAR SN=SIN(TH),CS=COS(TH) VAR CS1=1-CS VAR A1=A[0],A2=A[1],A3=A[2] VAR N1=N[0],N2=N[1],N3=N[2] VAR N12CS1=N1*N2*CS1 VAR N23CS1=N2*N3*CS1 VAR N31CS1=N3*N1*CS1 VAR N1SN=N1*SN VAR N2SN=N2*SN VAR N3SN=N3*SN C[0]=A1*(CS+N1*N1*CS1) + A2*(N12CS1-N3SN) + A3*(N31CS1+N2SN) C[1]=A1*(N12CS1+N3SN) + A2*(CS+N2*N2*CS1) + A3*(N23CS1-N1SN) C[2]=A1*(N31CS1-N2SN) + A2*(N23CS1+N1SN) + A3*(CS+N3*N3*CS1) END
パーリンノイズの勾配*フェード関数の図
パーリンノイズって、こんな感じで勾配*フェード関数の値を1セットだけ計算しておいて、あとはグリッド毎にランダムな方向回転しながら重ねあわせればいいのかなー?@@;
と思って、ちょっと1セットだけ可視化してみました。
上記の図のPiSTARTER用の表示プログラム:
option strict acls 'var SW=640,SH=360 var SW=1280,SH=720 var CX=SW/2,CY=SH/2 xscreen SW,SH var camz=50 var grid=128 dim g[0,0] g=basePerlin(grid) while 1 view wend end def view dim cam[3],camTo[3] set camTo,0,0,0 var vp=1 var d=0 for d=45 to 45+360 step 1 var th=rad(d) var r=200+sin(th*3)*50 r=200 set cam,r*cos(th),5+(1+sin(th*3))*50,r*sin(th) gpage vp,!vp gcls draw g,grid,cam,camTo dim ck[3]:sub ck,camTo,cam:norm ck dim ci[3]:roty ci,ck,pi()/2:ci[1]=0:norm ci dim cj[3]:cross cj,ck,ci:norm cj var p[3],cp[3],gx,gy,gz,scl,m=0,mag=SW var gx1,gy1,gx2,gy2 set p,-grid*0.6,0,0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl gx1=gx:gy1=gy set p,grid*0.6,0,0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl gx2=gx:gy2=gy gline gx1,gy1,gx2,gy2 set p,0,0,-grid*0.6 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl gx1=gx:gy1=gy set p,0,0,grid*0.6 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl gx2=gx:gy2=gy gline gx1,gy1,gx2,gy2 vp=!vp next end def draw g,grid,cam,camTo dim gx1[0],gy1[0] dim gx2[0],gy2[0] dim gx3[0],gy3[0] dim gx4[0],gy4[0] dim mz[0] dim ck[3]:sub ck,camTo,cam:norm ck dim ci[3]:roty ci,ck,pi()/2:ci[1]=0:norm ci dim cj[3]:cross cj,ck,ci:norm cj var i,j,stp=4 for j=-grid/2 to grid/2-stp step stp var y=grid/2+j for i=-grid/2 to grid/2-stp step stp var x=grid/2+i var p[3],cp[3],gx,gy,gz,scl,m=0,mag=SW set p,i+0,g[x+0,y+0],j+0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx1,gx:push gy1,gy inc m,gz set p,i+stp,g[x+stp,y+0],j+0 sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx2,gx:push gy2,gy inc m,gz set p,i+stp,g[x+stp,y+stp],j+stp sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx3,gx:push gy3,gy inc m,gz set p,i+0,g[x+0,y+stp],j+stp sub cp,p,cam gz=iprod(cp,ck) scl=mag/(camz+gz) gx=cx+iprod(cp,ci)*scl gy=cy-iprod(cp,cj)*scl push gx4,gx:push gy4,gy inc m,gz push mz,m next next dim idx[len(mz)+1] for i=0 to len(mz)-1:idx[i]=i:next rsort mz,idx var l=len(mz) for j=0 to l-1 i=idx[j] gtri gx1[i],gy1[i],gx2[i],gy2[i],gx3[i],gy3[i],0 gtri gx3[i],gy3[i],gx4[i],gy4[i],gx1[i],gy1[i],0 gline gx1[i],gy1[i],gx2[i],gy2[i],#lime gline gx2[i],gy2[i],gx3[i],gy3[i],#lime gline gx3[i],gy3[i],gx4[i],gy4[i],#lime gline gx4[i],gy4[i],gx1[i],gy1[i],#lime next end def basePerlin(grid) dim p[grid+1,grid+1] var gs=grid/2 var x,y var gradU=1,gradV=0 for y=-gs to gs var v=y/gs var fv=1-fad(abs(v)) for x=-gs to gs var u=x/gs var fu=1-fad(abs(u)) var c=(u*gradU+v*gradV)*fu*fv*gs '?c 'var col=rgb(c,c,c) 'gpset CX+x,CY-y,col 'gpset CX+x+v*64,CY-y/2-c*2 p[grid/2+x,grid/2+y]=c next next return p end def fad(t) return t*t*t*(t*(t*6-15)+10) end '三次元ベクトル計算ルーチン(左手系) DEF V3$(A) RETURN FORMAT$("(%6.2F,%6.2F,%6.2F)",A[0],A[1],A[2]) END DEF PRNT A ?V3$(A) END DEF SET C,X,Y,Z C[0]=X C[1]=Y C[2]=Z END DEF ADD C,A,B C[0]=A[0]+B[0] C[1]=A[1]+B[1] C[2]=A[2]+B[2] END DEF SUB C,A,B C[0]=A[0]-B[0] C[1]=A[1]-B[1] C[2]=A[2]-B[2] END DEF MUL C,A,B C[0]=A[0]*B C[1]=A[1]*B C[2]=A[2]*B END DEF DIVD C,A,B C[0]=A[0]/B C[1]=A[1]/B C[2]=A[2]/B END DEF DIST(A) RETURN SQR(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]) END DEF IPROD(A,B) RETURN A[0]*B[0]+A[1]*B[1]+A[2]*B[2] END DEF CROSS C,A,B C[0]=A[1]*B[2]-B[1]*A[2] C[1]=A[2]*B[0]-B[2]*A[0] C[2]=A[0]*B[1]-B[0]*A[1] END DEF NORM A VAR D=SQR(A[0]*A[0]+A[1]*A[1]+A[2]*A[2]) A[0]=A[0]/D A[1]=A[1]/D A[2]=A[2]/D END DEF ROTX C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=X C[1]=Y*CS-Z*SN C[2]=Y*SN+Z*CS END DEF ROTY C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=Z*SN+X*CS C[1]=Y C[2]=Z*CS-X*SN END DEF ROTZ C,A,TH VAR SN=SIN(TH),CS=COS(TH) VAR X=A[0],Y=A[1],Z=A[2] C[0]=X*CS-Y*SN C[1]=X*SN+Y*CS C[2]=Z END DEF ROTN C,A,N,TH VAR SN=SIN(TH),CS=COS(TH) VAR CS1=1-CS VAR A1=A[0],A2=A[1],A3=A[2] VAR N1=N[0],N2=N[1],N3=N[2] VAR N12CS1=N1*N2*CS1 VAR N23CS1=N2*N3*CS1 VAR N31CS1=N3*N1*CS1 VAR N1SN=N1*SN VAR N2SN=N2*SN VAR N3SN=N3*SN C[0]=A1*(CS+N1*N1*CS1) + A2*(N12CS1-N3SN) + A3*(N31CS1+N2SN) C[1]=A1*(N12CS1+N3SN) + A2*(CS+N2*N2*CS1) + A3*(N23CS1-N1SN) C[2]=A1*(N31CS1-N2SN) + A2*(N23CS1+N1SN) + A3*(CS+N3*N3*CS1) END
PiSTARTERのペンタブのテスト
ペンタブのテストしてみました~ヾ(*´∀`*)ノ
筆圧もとれてたのし~(≧∇≦)b
ソースはこちら:
' ' ペンタブレットテスト by みなつ ' 2018年10月15日 ' option strict acls 'var SW=640,SH=360 var SW=1280,SH=720 xscreen SW,SH var TABW=31497,TABH=19686 'ペンタブの最大座標(PTH-450 Intuos5) var xRatio=SW/TABW,yRatio=SH/TABH var brushSize,brushMag=4,col=#white 'ブラシサイズと色 ?"Z:ブラシ縮小 X:ブラシ拡大 D:消去" loop end 'ブラシのサイズを表すスプライトをセット '------------------------------------------------------- def setBrush gpage 0,3 gcls brushSize=floor(pow(2,brushMag)*10)/10 var s=brushSize/2 gcircle s+1,s+1,s gpset s+1,s+1 spset 0,0,0,s*2+2,s*2+2,#SPSHOW:sphome 0,s+1,s+1 gpage 0,0 locate 0,1:?format$("ブラシサイズ=%5.1f",brushSize) end 'メインループ '------------------------------------------------------- def loop setBrush var x,y,pressure,side,dist,btn var tx,ty,tp'現在のペンの位置と筆圧 var lx,ly,lp'一つ前のペンの位置と筆圧 while 1 tabletstat out x,y,pressure,side,dist,btn 'locate 0,0:?format$("(%5d,%5d) pressure=%5d dist=%2d",x,y,pressure,dist) if dist==0 && pressure==0 then continue 'ペンがホバー距離より離れている 'ペンが認識されているので、位置と筆圧を更新 lx=tx:ly=ty:lp=tp tx=x*xRatio:ty=y*yRatio:tp=pressure spofs 0,tx,ty if dist<=17 && pressure>0 then drawLine lx,ly,lp,tx,ty,tp endif var k$=inkey$() if k$=="z" && brushMag>0.1 then dec brushMag,1/4:setBrush if k$=="x" then inc brushMag,1/4::setBrush if k$=="d" then gcls wend end '筆圧を補間して線を引く '------------------------------------------------------- def drawLine lx,ly,lp,tx,ty,tp var minPresure=300 'この筆圧以下は1ドットにする var dx=tx-lx,dy=ty-ly var i,l '初期筆圧 var size0=brushSize*(lp-minPresure)/(2048-minPresure) var bsize0=max(0,min(brushSize/2,size0/2)) '最終筆圧 var size1=brushSize*(tp-minPresure)/(2048-minPresure) var bsize1=max(0,min(brushSize/2,size1/2)) var dsize=bsize1-bsize0 if abs(dx)>abs(dy) then l=abs(dx) '横長 else l=abs(dy) '縦長 endif if l==0 then return '前回のペン位置から動いていない for i=0 to l var t=i/l var x=lx+t*dx var y=ly+t*dy var s=bsize0+t*dsize if s<0.1 then elseif s<0.5 then gpset x,y elseif s<1 then gfill x-0.5,y-0/5,x+0.5,y+0.5 else gcircle x,y,s,1 gpaint x,y,col,1 gcircle x,y,s,col endif next end
短いサンプルをたくさん作ろうプロジェクト 第1弾「ウィザードリィタイプの3D迷路」
プチコンで具体的に動くソースプログラムがあると、「こんなのを作ってみたい!」という方が居たとき便利かも~と思って、動く短いサンプルを色々つくってみることにしました(*´▽`*)
- 目標1:できるだけ分かり易く
- 目標2:十分写経できる短さで
第1弾「ウィザードリィタイプの3D迷路」ですっ!
解説
このタイプの3D迷路は、プレイヤーが向いてる方向に、壁に突き当たるまで左右のマップデータをチェックしていって、
- 壁があるときは斜め線
- 壁が無いときは横線
で描けばOKです(≧∇≦)b
実際に作ってみると、「斜め線、横線はいいとして、壁(柱)の位置はどう決めるのよ?」となると思いますが、描画したい画面の中心(下図では100,100)を基準に
- 一番手前の壁の位置を決める(下図では90)
- 奥に行くに従い1/2、1/3、1/4、・・・としていく
と、シンプルな透視投影になります(≧∇≦)b
プログラム本体
パート1(データの準備)
パート2(メインルーチン)
パート3(壁表示ルーチン)
パート4(マップ表示ルーチンと迷路データ)
マスコットアプリ文化祭2017 プチコン賞 を頂きました!
プチコン賞
マスコットアプリ文化祭2017に応募したプチコン用ゲーム「プロ生ちゃんデバッグチャレンジ」が、プチコンを制作されているスマイルブーム様の「プチコン賞」を受賞しましたヾ(*´∀`*)ノ
上の写真が、今日届いた受賞賞品なのですが・・・北海道のお菓子がすごいいっぱい!うれしぃ~(≧∇≦)b
ありがとうございます!おいしくいただきます(●´ω`●)モグモグモグ
また、このような受賞コメントも頂きました(*´▽`*)
"シンプルな操作方法かつ単純なルール! プレイすると思い通りにプロ生ちゃんパワーを上手に配分できずバグが増大して3DSを放り投げたくなる一方で、繰り返し遊んでしまう中毒性!
以上を評価してプチコン3号賞を送ります。"
大変光栄です。これを励みに、更に精進していきたいと思います!
プロ生ちゃんデバッグチャレンジについて
公開キー【J2C43VAE】
下画面をフリックして迷路に矢印を置き、左上からどんどん出てくるプロ生ちゃんをうまく誘導して、迷路内に4か所出現する「バグ」を退治するゲームです。プロ生ちゃんがバグに触れている間だけバグのパワーが減っていき、全てのバグのパワーを0にするとデバッグ完了となり、ステージクリアです。
制作話
マスコットアプリ文化祭の趣旨的に、何かマスコットキャラを使う必要があったのですが、自分でキャラを描くのはなかなか大変なので、プチコンの公式ページで配布されている「プロ生ちゃんキャラセット」を使うことを前提に、3DSやWiiUのタッチパネルを上手く使えないかな~と考えていました。
プロ生ちゃんキャラセットには、サイドビューの大きめのプロ生ちゃんと、トップビューのちっちゃいプロ生ちゃんのアニメーションパターンが用意されているのですが、タッチパネルで操作するとなると、サイドビューよりトップビューのほうがよさそうだったので、ちっちゃいプロ生ちゃんを使うことにしました。
「ちっちゃいプロ生ちゃんなら、わらわらいっぱい出てくると楽しそう(*´▽`*)」と思い、そのとき、私の大好きなセガの「チューチューロケット」が思い浮かんだのでした(*ノノ)
チューチューロケットは矢印を置いて、猫に襲われないようにねずみのチューチューをロケットまで誘導するゲームなのですが、この対戦がすごく熱くて、一時期すごいハマったのでした。今回、プロ生ちゃんを矢印で誘導するというアイデアは、ここから拝借インスパイアしました!( ゚∀゚)
そして、プロ生ちゃんなら、何かデバッグするのがいいんじゃないかという安易な発想により、救命戦士ナノセイバーよろしく、コンピュータの中に小さくなったプロ生ちゃん(の分身)が潜入し、バグを退治する、という基本ルールができました。
基本ルールが決まればあとはプログラムするだけですが、問題は、コンピュータの中を模したステージをどう作るかというところにありました。というのも、「たくさんのプロ生ちゃんを矢印で誘導するというゲームの性質上、ステージ全体が一度に見渡せたほうがよい」ので、必然的に下画面に収まるステージということになりますが、そうすると、ステージが小さすぎて、数回クリアすると飽きてしまうのですね(´・ω・`) かといって、沢山のステージを手で作るのは大変・・・
そこで、乱数のシードに応じて形が一意に決まるような迷路を作ることにしました。プチコン内蔵の乱数は、同じシードを与えてもプチコン3号とプチコンBIGで乱数系列が異なることをミーバースのyosさん(@yosuitaro)の投稿で知っていました。そこで、3号とBIGで同じ乱数系列を発生させるため、よすぃさんの自作乱数ルーチンを使用させていただきました!
また、迷路の生成については、プロ生ちゃんが突入してくる左上が必ず空白にならないとマズかったので、穴を掘っていく方式の、けんしろウッさん(@kenshiro3114)の自動生成迷路のアルゴリズムを参考にさせていただきました!
ということで、懸案だったステージの自動生成の目途が立ったのですが、実は応募締め切り前日の夜中まで、こげな感じで全く別のことに熱中しておりまして・・・
#プチコンBIG の16dotフォントが奇麗なので、ファイルに保存して3号でも使えるようにしてみたのですが、どうやってもえいださんが改良されたバージョンのほしけんさんの漢字ライブラリに速度でかなわない!
— みなつ (@tksm372) 2018年1月6日
中を拝見したら…ビットマップをキャッシュ!
スバラシイ(≧∇≦)bhttps://t.co/OWBafolIe2
実際にプロ生ちゃんデバッグチャレンジのプログラムを作り始めたのは、締め切り(2017年1月7日)当日の朝でした(*ノノ)
で、迷路作成ルーチンの作成に少々手こずり、これが完成したのがお昼過ぎ(; ̄▽ ̄)
そこからゲームのコア部分を作り始め、20時くらいになんとか「1ゲームプレイする」ところまで完成したものの、そのあと、タイトル画面の絵(これは、昨日書いたベクター型お絵かきソフトでタイトル文字を書き、スマイルツールのお絵かきツールでプロ生ちゃんを配置しました)、ステージセレクト、ハイスコアと作っているうちに・・・あぁぁぁデバッグの時間が足りにゃい・・・プロ生ちゃんデバッグ(リアル)手伝ってぇぇぇ。・゚・(ノД`)・゚・。
と、ジタバタしているうちに、日付が変わり・・・
だうー
— みなつ (@tksm372) 2018年1月7日
1月7日おわっちゃったー(´;ω;`)ウッ…
ま・・・まにあわまへんでした・・・_| ̄|○https://t.co/agXPAK3ptc
「んもぅ、なんであんたはもっと早く始めないの!」と、8月31日に毎年言われていた台詞がよみがえりつつ、猛省しておりましたところ・・・
こりんごさんとプロ生ちゃんから、「8日まで大丈夫」との情報を頂き・・・蘇りました!( ゚∀゚)
そんなこんなで、皆様に助けられ、なんとかマスコットアプリ文化祭2017に応募することができました。この場を借りて、お礼申し上げます<(_ _)>
ベクター型お絵かきソフト
公開キー【4K35QM】(2017年12月9日公開 v1.14)
- SAIのベクターレイヤーのような、お絵かきソフトです。
- ペンで描いたストロークに対して、頂点の追加/削除、マクロ変形、切断、連結等の編集ができます。
- 編集コマンドは、十字キー(上・下・左・右・左上・右上の6方向)で選択します。Lボタンを押すと、上段のコマンドにシフトします。十字キーやLキーは押してる間だけ有効ですが、素早く2回押すと、そのコマンドのロック/ロック解除をトグルできます。
- 曲線は、cosカーブで補間しています。
- 色を塗ったり、レイヤー化したりしたいのですが、なかなか作業が進まず(*ノノ)がんばりたいと思います(*´▽`*)
フライングハトさん
公開キー【TZ3VA3D4 】(最新版2017年10月11日公開)
- ボタンでハトさんを旋回させ、ケーキを取りながらゴールまでなるべく早く飛んでいく、タイムアタックゲームです。
- Villitさん主催の「2週間で、お題に沿ったゲームを0から作る」イベント、SmileBasic 2weeksの第1回「ワンボタンゲーム」の回に投稿した作品を、yos(よすぃ)(@yosuitaro)さんにステージを、PianoRider(@pianorider)さんにBGMを作成していただき、パワーアップしたゲームです!
- 最初はかなりシンプルなゲームだったのですが、よすぃさんはじめ皆様にアイデアを頂き、ゴースト表示や、リプレイ機能、マップエディタ等の機能が追加されました!
- ワンボタンだけの簡単プレイですが、ケーキを全部とったり、最速クリアを目指したり等、やりこみ要素もあるので、是非遊んでみて下さい(≧∇≦)b