みなつ@プチコン

BASICでゲームが作れるWiiU/3DS用ソフト「プチコン」のブログです(*´▽`*)

”勾配*フェード関数”の基本パターンの重ね合わせによるパーリンノイズのようなもの

前回可視化した、「勾配(ある方向に傾いた平面)*フェード関数」の基本パターンを

ランダムに重ね合わせてパーリンノイズのようなもの作るテストを、PiSTARTERで作ってみました~ヾ(*´∀`*)ノ

f:id:tksm372:20181018001120p:plain

 

ちにゃみに、前回立体表示した基本パターンを濃淡で表すと、こげな感じです。

f:id:tksm372:20181018002000p:plain

これは、左側が奥、右側が手前に傾いた「平面」に、「図の中心が重み100%、図の周辺が重み0%」になるような滑らかなフェード関数を掛け算した図です。

これを、

ランダムに回転しながらグリッド状(グリッド幅は図の辺の半分)に並べて重ね合わせる

と大きな濃淡の図ができます。さらにこの処理を、

「パターンの大きさを半分、濃度も半分、グリッド幅も半分」にして上から重ねる

と、1段階細かい模様ができます。これを適当な回数(今回は6回にしました)繰り返すと、いい感じに「大きな凸凹」から「小さな凸凹」までを含んだ濃淡ができるんですねー(゜◇゜)

 

なお、上記のパターンはこんな感じで作れます!
f:id:tksm372:20181018011119p:plain左上の図は、勾配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セットだけ可視化してみました。

f:id:tksm372:20181017010608p:plain

 

上記の図の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

f:id:tksm372:20181015214412p:plain

 

ソースはこちら:

'
' ペンタブレットテスト 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迷路」ですっ!

f:id:tksm372:20180729191625j:plain

 

解説

このタイプの3D迷路は、プレイヤーが向いてる方向に、壁に突き当たるまで左右のマップデータをチェックしていって、

  • 壁があるときは斜め線
  • 壁が無いときは横線

で描けばOKです(≧∇≦)b

実際に作ってみると、「斜め線、横線はいいとして、壁(柱)の位置はどう決めるのよ?」となると思いますが、描画したい画面の中心(下図では100,100)を基準に

  • 一番手前の壁の位置を決める(下図では90)
  • 奥に行くに従い1/2、1/3、1/4、・・・としていく

と、シンプルな透視投影になります(≧∇≦)b

f:id:tksm372:20180730054231p:plain 

プログラム本体

パート1(データの準備)

f:id:tksm372:20180729195600p:plain

パート2(メインルーチン)

f:id:tksm372:20180729193458p:plain

パート3(壁表示ルーチン)

f:id:tksm372:20180729193508p:plain

パート4(マップ表示ルーチンと迷路データ)

f:id:tksm372:20180729193519p:plain

 

マスコットアプリ文化祭2017 プチコン賞 を頂きました!

f:id:tksm372:20180215184818p:plain

プチコン

マスコットアプリ文化祭2017に応募したプチコン用ゲーム「プロ生ちゃんデバッグチャレンジ」が、プチコンを制作されているスマイルブーム様の「プチコン賞」を受賞しましたヾ(*´∀`*)ノ

上の写真が、今日届いた受賞賞品なのですが・・・北海道のお菓子がすごいいっぱい!うれしぃ~(≧∇≦)b
ありがとうございます!おいしくいただきます(●´ω`●)モグモグモグ

また、このような受賞コメントも頂きました(*´▽`*)

"シンプルな操作方法かつ単純なルール! プレイすると思い通りにプロ生ちゃんパワーを上手に配分できずバグが増大して3DSを放り投げたくなる一方で、繰り返し遊んでしまう中毒性!
以上を評価してプチコン3号賞を送ります。"

大変光栄です。これを励みに、更に精進していきたいと思います!

 

プロ生ちゃんデバッグチャレンジについて

f:id:tksm372:20180215192119p:plain

公開キー【J2C43VAE】

下画面をフリックして迷路に矢印を置き、左上からどんどん出てくるプロ生ちゃんをうまく誘導して、迷路内に4か所出現する「バグ」を退治するゲームです。プロ生ちゃんがバグに触れている間だけバグのパワーが減っていき、全てのバグのパワーを0にするとデバッグ完了となり、ステージクリアです。

 

制作話

マスコットアプリ文化祭の趣旨的に、何かマスコットキャラを使う必要があったのですが、自分でキャラを描くのはなかなか大変なので、プチコンの公式ページで配布されている「プロ生ちゃんキャラセット」を使うことを前提に、3DSWiiUのタッチパネルを上手く使えないかな~と考えていました。

プロ生ちゃんキャラセットには、サイドビューの大きめのプロ生ちゃんと、トップビューのちっちゃいプロ生ちゃんのアニメーションパターンが用意されているのですが、タッチパネルで操作するとなると、サイドビューよりトップビューのほうがよさそうだったので、ちっちゃいプロ生ちゃんを使うことにしました。

「ちっちゃいプロ生ちゃんなら、わらわらいっぱい出てくると楽しそう(*´▽`*)」と思い、そのとき、私の大好きなセガの「チューチューロケット」が思い浮かんだのでした(*ノノ)

チューチューロケットは矢印を置いて、猫に襲われないようにねずみのチューチューをロケットまで誘導するゲームなのですが、この対戦がすごく熱くて、一時期すごいハマったのでした。今回、プロ生ちゃんを矢印で誘導するというアイデアは、ここから拝借インスパイアしました!( ゚∀゚) 

そして、プロ生ちゃんなら、何かデバッグするのがいいんじゃないかという安易な発想により、救命戦士ナノセイバーよろしく、コンピュータの中に小さくなったプロ生ちゃん(の分身)が潜入し、バグを退治する、という基本ルールができました。

基本ルールが決まればあとはプログラムするだけですが、問題は、コンピュータの中を模したステージをどう作るかというところにありました。というのも、「たくさんのプロ生ちゃんを矢印で誘導するというゲームの性質上、ステージ全体が一度に見渡せたほうがよい」ので、必然的に下画面に収まるステージということになりますが、そうすると、ステージが小さすぎて、数回クリアすると飽きてしまうのですね(´・ω・`) かといって、沢山のステージを手で作るのは大変・・・

そこで、乱数のシードに応じて形が一意に決まるような迷路を作ることにしました。プチコン内蔵の乱数は、同じシードを与えてもプチコン3号とプチコンBIGで乱数系列が異なることをミーバースのyosさん(@yosuitaro)の投稿で知っていました。そこで、3号とBIGで同じ乱数系列を発生させるため、よすぃさんの自作乱数ルーチンを使用させていただきました!

また、迷路の生成については、プロ生ちゃんが突入してくる左上が必ず空白にならないとマズかったので、穴を掘っていく方式の、けんしろウッさん(@kenshiro3114)の自動生成迷路アルゴリズムを参考にさせていただきました!

ということで、懸案だったステージの自動生成の目途が立ったのですが、実は応募締め切り前日の夜中まで、こげな感じで全く別のことに熱中しておりまして・・・

実際にプロ生ちゃんデバッグチャレンジのプログラムを作り始めたのは、締め切り(2017年1月7日)当日の朝でした(*ノノ)

で、迷路作成ルーチンの作成に少々手こずり、これが完成したのがお昼過ぎ(; ̄▽ ̄)
そこからゲームのコア部分を作り始め、20時くらいになんとか「1ゲームプレイする」ところまで完成したものの、そのあと、タイトル画面の絵(これは、昨日書いたベクター型お絵かきソフトでタイトル文字を書き、スマイルツールのお絵かきツールでプロ生ちゃんを配置しました)、ステージセレクト、ハイスコアと作っているうちに・・・あぁぁぁデバッグの時間が足りにゃい・・・プロ生ちゃんデバッグ(リアル)手伝ってぇぇぇ。・゚・(ノД`)・゚・。
と、ジタバタしているうちに、日付が変わり・・・

「んもぅ、なんであんたはもっと早く始めないの!」と、8月31日に毎年言われていた台詞がよみがえりつつ、猛省しておりましたところ・・・

こりんごさんとプロ生ちゃんから、「8日まで大丈夫」との情報を頂き・・・蘇りました!( ゚∀゚) 

そんなこんなで、皆様に助けられ、なんとかマスコットアプリ文化祭2017に応募することができました。この場を借りて、お礼申し上げます<(_ _)>

 


3DS/WiiU プチコン3号/BIG 用ゲーム「プロ生ちゃんデバッグチャレンジ」

ベクター型お絵かきソフト

f:id:tksm372:20180131200757j:plain

公開キー【4K35QM】(2017年12月9日公開 v1.14)

  • SAIのベクターレイヤーのような、お絵かきソフトです。
  • ペンで描いたストロークに対して、頂点の追加/削除、マクロ変形、切断、連結等の編集ができます。
  • 編集コマンドは、十字キー(上・下・左・右・左上・右上の6方向)で選択します。Lボタンを押すと、上段のコマンドにシフトします。十字キーやLキーは押してる間だけ有効ですが、素早く2回押すと、そのコマンドのロック/ロック解除をトグルできます。
  • 曲線は、cosカーブで補間しています。f:id:tksm372:20180131122902p:plain
  • 色を塗ったり、レイヤー化したりしたいのですが、なかなか作業が進まず(*ノノ)がんばりたいと思います(*´▽`*)

 


3DS/WiiU プチコン3号/BIG 用 ベクター型お絵かきソフト

フライングハトさん

 

f:id:tksm372:20180213234100p:plain

公開キー【TZ3VA3D4 】(最新版2017年10月11日公開)

  • ボタンでハトさんを旋回させ、ケーキを取りながらゴールまでなるべく早く飛んでいく、タイムアタックゲームです。
  • Villitさん主催の「2週間で、お題に沿ったゲームを0から作る」イベント、SmileBasic 2weeksの第1回「ワンボタンゲーム」の回に投稿した作品を、yos(よすぃ)(@yosuitaro)さんにステージを、PianoRider(@pianorider‏)さんにBGMを作成していただき、パワーアップしたゲームです!
  • 最初はかなりシンプルなゲームだったのですが、よすぃさんはじめ皆様にアイデアを頂き、ゴースト表示や、リプレイ機能、マップエディタ等の機能が追加されました!
  • ワンボタンだけの簡単プレイですが、ケーキを全部とったり、最速クリアを目指したり等、やりこみ要素もあるので、是非遊んでみて下さい(≧∇≦)b

 


3DS/WiiU プチコン3号/BIG 用ゲーム「フライング ハトさん」by みなつ/yos/PianoRider