たまたま見かけた情報教材の動画で、きれいな?かわいい?アニメーションを見かけたので作ってみることにしました。
情報教材の動画はColosoってところの「魅力的なライブイラストを描く」といやつです。絵は描けないけど、右のようなアニメーションだったらプログラミングで作れるかな?
STEP1 ひな形作成
とりあえず色は頂戴する。
def setup():
size(600, 300)
def draw():
background(3, 88, 134)
stroke(249, 170, 173)
strokeWeight(5)
line(0, height / 2, width, height / 2)クラスを使って作るだろうからとりあえずの雛形
class particleA(object):
def __init__(self, x, y, sizeMax, speed):
self.x = x
self.y = y
self.sizeMax = sizeMax
self.speed = speed
self.frame = 0
def drawParticle(self):
line(self.x - self.sizeMax / 2, self.y, self.x + self.sizeMax / 2, self.y)
def setup():
global p1, p2
size(600, 300)
p1 = particleA(100, 100, 10, 2)
p2 = particleA(200, 200, 20, 2)
def draw():
background(3, 88, 134)
stroke(249, 170, 173)
strokeWeight(5)
p1.drawParticle()
p2.drawParticle()STEP2 分析
お手本のムービーを観察。フレームごとの内側の空白部分と線の長さを調べた。
| フレーム | サイズ | 余白 | 線 | 余白(比) | 線(比) |
|---|---|---|---|---|---|
| 1 | 20 | 0 | 10 | 0 | 0.0625 |
| 2 | 20 | 0 | 10 | 0 | 0.0625 |
| 3 | 35 | 0 | 17.5 | 0 | 0.109375 |
| 4 | 35 | 0 | 17.5 | 0 | 0.109375 |
| 5 | 56 | 0 | 28 | 0 | 0.175 |
| 6 | 80 | 16 | 24 | 0.1 | 0.15 |
| 7 | 80 | 16 | 24 | 0.1 | 0.15 |
| 8 | 110 | 40 | 15 | 0.25 | 0.09375 |
| 9 | 150 | 71 | 4 | 0.44375 | 0.025 |
| 10 | 160 | 78 | 2 | 0.4875 | 0.0125 |
| 11 | 0 | 0 | 0 | 0 | 0 |
| 12 | 0 | 0 | 0 | 0 | 0 |
STEP4 固定値だけど作ってみる

class particleA(object):
def __init__(self, x, y, sizeMax, speed):
self.x = x
self.y = y
self.sizeMax = sizeMax
self.speed = speed
self.frame = 0
self.frameMax = 12
self.sizes = [10, 10, 17.5, 17.5, 28, 24, 24, 15, 4, 2, 0, 0]
self.paddings = [0, 0, 0, 0, 0, 16, 16, 40, 71, 78, 0, 0]
def drawParticle(self):
w = self.sizes[self.frame]
h = w
p = self.paddings[self.frame]
line(self.x + p, self.y, self.x + p + w, self.y) # 右
line(self.x - p, self.y, self.x - p - w, self.y) # 左
line(self.x, self.y - p, self.x, self.y - p - h) # 上
line(self.x, self.y + p, self.x, self.y + p + h) # 下
self.frame += 1
if self.frame >= self.frameMax:
self.frame = 0
def setup():
global p1, p2
size(600, 300)
p1 = particleA(100, 100, 10, 2)
p2 = particleA(400, 200, 20, 2)
def draw():
background(3, 88, 134)
stroke(249, 170, 173)
strokeWeight(5)
p1.drawParticle()
p2.drawParticle()STEP4 固定値から比率に変更
class particleA(object):
def __init__(self, x, y, wMax, hMax, speed):
self.x = x
self.y = y
self.wMax = wMax
self.hMax = hMax
self.speed = speed
self.frame = 0
self.frameMax = 12
self.delay = random(60, 180)
self.sizes = [0.0625, 0.0625, 0.109375, 0.109375, 0.175, 0.15, 0.15, 0.09375, 0.025, 0.0125, 0, 0]
self.paddings = [0, 0, 0, 0, 0, 0.1, 0.1, 0.25, 0.44375, 0.4875, 0, 0]
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
w = self.sizes[self.frame] * self.wMax
h = self.sizes[self.frame] * self.hMax
pW = self.paddings[self.frame] * self.wMax
pH = self.paddings[self.frame] * self.hMax
line(self.x + pW, self.y, self.x + pW + w, self.y) # 右
line(self.x - pW, self.y, self.x - pW - w, self.y) # 左
line(self.x, self.y - pH, self.x, self.y - pH - h) # 上
line(self.x, self.y + pH, self.x, self.y + pH + h) # 下
if frameCount % self.speed == 0:
self.frame += 1
if self.frame >= self.frameMax:
self.frame = 0
# self.wMax = random(20, 160)
# self.hMax = random(20, 160)
# self.x = random(0, width)
# self.y = random(0, height)
self.delay = random(60, 180)
def setup():
global p1, p2
size(600, 300)
p1 = particleA(100, 100, 160, 160, 2)
p2 = particleA(400, 200, 50, 50, 2)
def draw():
background(3, 88, 134)
stroke(249, 170, 173)
strokeWeight(2)
p1.drawParticle()
p2.drawParticle()STEP5 別パターンの追加
3パターン追加されるので基底クラスを作成した。
- ParticleA … 十字
- ParticleB … ひし形(パラメーターでカーブを調整できる)
- ParticleC … ひし形~十字
- ParticleD … フラフラ十字

class Particle(object): # 基底クラス
def __init__(self, x, y, wMax, hMax, speed):
self.x = x
self.y = y
self.wMax = wMax
self.hMax = hMax
self.speed = speed
self.frame = 0
self.frameMax = 12
self.delay = 0
def setRandom(self):
self.wMax = random(20, 160)
self.hMax = random(20, 160)
self.x = random(0, width)
self.y = random(0, height)
self.delay = random(60, 180)
def countUp(self):
if frameCount % self.speed == 0:
self.frame += 1
if self.frame >= self.frameMax:
self.frame = 0
# self.setRandom()
class ParticleA(Particle): # 十字
def __init__(self, x, y, wMax, hMax, speed):
super(ParticleA, self).__init__(x, y, wMax, hMax, speed)
self.sizes = [0.0625, 0.0625, 0.109375, 0.109375, 0.175, 0.15, 0.15, 0.09375, 0.025, 0.0125, 0, 0]
self.paddings = [0, 0, 0, 0, 0, 0.1, 0.1, 0.25, 0.44375, 0.4875, 0, 0]
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
w = self.sizes[self.frame] * self.wMax
h = self.sizes[self.frame] * self.hMax
pW = self.paddings[self.frame] * self.wMax
pH = self.paddings[self.frame] * self.hMax
line(self.x + pW, self.y, self.x + pW + w, self.y ) # 右
line(self.x - pW, self.y, self.x - pW - w, self.y ) # 左
line(self.x, self.y - pH, self.x, self.y - pH - h) # 上
line(self.x, self.y + pH, self.x, self.y + pH + h) # 下
self.countUp()
class ParticleB(Particle): # ひし形
def __init__(self, x, y, wMax, hMax, speed, par=0.2):
super(ParticleB, self).__init__(x, y, wMax, hMax, speed)
self.sizes = [0.2884615385, 0.5192307692, 0.7115384615, 0.8365384615, 1, 1, 1, 0.8365384615, 0.7115384615, 0.7115384615, 0.5192307692, 0.5192307692]
self.par = par
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
w = self.sizes[self.frame] * self.wMax / 2
h = self.sizes[self.frame] * self.hMax / 2
bezier(self.x, self.y - h, self.x, self.y - h * self.par, self.x + w * self.par, self.y, self.x + w, self.y ) # 右上
bezier(self.x + w, self.y, self.x + w * self.par, self.y, self.x, self.y + h * self.par, self.x, self.y + h) # 右下
bezier(self.x, self.y + h, self.x, self.y + h * self.par, self.x - w * self.par, self.y, self.x - w, self.y ) # 左下
bezier(self.x - w, self.y, self.x - w * self.par, self.y, self.x, self.y - h * self.par, self.x, self.y - h) # 左上
self.countUp()
class ParticleC(Particle): # ひし形~十字
def __init__(self, x, y, wMax, hMax, speed):
super(ParticleC, self).__init__(x, y, wMax, hMax, speed)
self.sizes = [0.158974359, 0.2820512821, 0.3948717949, 0.1487179487, 0.08205128205, 0.05641025641, 0.01025641026, 0, 0, 0, 0, 0]
self.pars = [0.2, 0.2, 0.2, 0.8, 0.2, 0.2, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0]
self.paddings1 = [0, 0, 0, 0.1179487179, 0.2666666667, 0.358974359, 0, 0, 0, 0, 0, 0]
self.lines1 = [0, 0, 0, 0.07692307692, 0.02051282051, 0.01538461538, 0, 0, 0, 0, 0, 0]
self.paddings2 = [0, 0, 0, 0.02564102564, 0.06153846154, 0.08717948718, 0, 0, 0, 0, 0, 0]
self.lines2 = [0, 0, 0, 0.05641025641, 0.02051282051, 0.01025641026, 0, 0, 0, 0, 0, 0]
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
# ひし形
if self.sizes[self.frame] > 0:
w = self.sizes[self.frame] * self.wMax / 2
h = self.sizes[self.frame] * self.hMax / 2
p = self.pars[self.frame]
bezier(self.x, self.y - h, self.x, self.y - h * p, self.x + w * p, self.y, self.x + w, self.y ) # 右上
bezier(self.x + w, self.y, self.x + w * p, self.y, self.x, self.y + h * p, self.x, self.y + h) # 右下
bezier(self.x, self.y + h, self.x, self.y + h * p, self.x - w * p, self.y, self.x - w, self.y ) # 左下
bezier(self.x - w, self.y, self.x - w * p, self.y, self.x, self.y - h * p, self.x, self.y - h) # 左上
# 十字
if self.lines1[self.frame] > 0:
p1 = self.paddings1[self.frame] * self.wMax
l1 = self.lines1[self.frame] * self.wMax
p2 = self.paddings2[self.frame] * self.wMax + p1 + l1
l2 = self.lines2[self.frame] * self.wMax
# 内側直線
line(self.x + p1, self.y, self.x + p1 + l1, self.y ) # 右
line(self.x - p1, self.y, self.x - p1 - l1, self.y ) # 左
line(self.x, self.y - p1, self.x, self.y - p1 - l1) # 上
line(self.x, self.y + p1, self.x, self.y + p1 + l1) # 下
# 外側直線
line(self.x + p2, self.y, self.x + p2 + l2, self.y ) # 右
line(self.x - p2, self.y, self.x - p2 - l2, self.y ) # 左
line(self.x, self.y - p2, self.x, self.y - p2 - l2) # 上
line(self.x, self.y + p2, self.x, self.y + p2 + l2) # 下
self.countUp()
class ParticleD(Particle): # フラフラ十字
def __init__(self, x, y, wMax, hMax, speed):
super(ParticleD, self).__init__(x, y, wMax, hMax, speed)
self.sizes = [0.73684, 0.73684, 0.73684, 0.73684, 1.00000, 1.00000, 1.00000, 0.89474, 0.89474, 0.89474, 1.00000, 1.00000]
self.bureXs = [1, 1, 1, 1, 0, 0, 0, -1, -1, -1, 0, 0]
self.bureYs = [0, 0, 0, 0, 0, 0, 0, -1, -1, -1, 0, 0]
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
w = self.sizes[self.frame] * self.wMax / 2
h = self.sizes[self.frame] * self.hMax / 2
bx = self.bureXs[self.frame]
by = self.bureYs[self.frame]
line(self.x + bx - w , self.y + by, self.x + bx + w, self.y + by ) # 左右
line(self.x + bx, self.y + by - h, self.x + bx, self.y + by + h) # 上下
self.countUp()
def setup():
global stars, fontSize
size(500, 500)
fontSize = 48
font = createFont(u"美咲ゴシック", fontSize)
textFont(font)
stars = list()
stars.append(ParticleA(320, 90, 150, 150, 3))
stars.append(ParticleB(70, 170, 30, 50, 3))
stars.append(ParticleC(240, 250, 200, 200, 3))
stars.append(ParticleD(470, 240, 14, 16, 3))
stars.append(ParticleC(50, 255, 200, 200, 3))
stars.append(ParticleB(90, 350, 50, 80, 3))
stars.append(ParticleC(340, 360, 200, 200, 3))
stars.append(ParticleC(420, 370, 250, 250, 3))
stars.append(ParticleB(140, 380, 40, 60, 3, 0.05))
stars.append(ParticleD(340, 450, 22, 28, 3))
def draw():
background(3, 88, 134)
# 文字
fill(23, 108, 154)
textAlign(CENTER)
textSize(fontSize)
x = width / 2
y = height / 2.3
text("STAR PARTICLE", x, y)
textSize(fontSize / 2)
y += fontSize / 2
text("Animation By vivinos__", x, y)
y += fontSize / 1.5
text("2022.10.9", x, y)
# 星
stroke(249, 170, 173)
strokeWeight(2)
noFill()
for star in stars:
star.drawParticle()残骸
タイプ2は当初arc()を使って描こうとした。(完成形はbezier()にした。シンプルなので。)
class ParticleBOld(Particle):
def __init__(self, x, y, wMax, hMax, speed):
super(ParticleBOld, self).__init__(x, y, wMax, hMax, speed)
self.inWidth = [0.2884615385, 0.3269230769, 0.4230769231, 0.4903846154, 0.5384615385, 0.5384615385, 0.5384615385, 0.4903846154, 0.4230769231, 0.4230769231, 0.3269230769, 0.3269230769]
self.inHeight = [0.2884615385, 0.3269230769, 0.4230769231, 0.4903846154, 0.5384615385, 0.5384615385, 0.5384615385, 0.4903846154, 0.4230769231, 0.4230769231, 0.3269230769, 0.3269230769]
self.outWidth = [0.2884615385, 0.5192307692, 0.7115384615, 0.8365384615, 1, 1, 1, 0.8365384615, 0.7115384615, 0.7115384615, 0.5192307692, 0.5192307692]
self.outHeight = [0.4166666667, 0.6666666667, 0.7083333333, 0.8958333333, 1, 1, 1, 0.8958333333, 0.7083333333, 0.7083333333, 0.6666666667, 0.6666666667]
def drawParticle(self):
if self.delay > 0:
self.delay -= 1
return
# 比率から実サイズへ
oW = self.outWidth[self.frame] * self.wMax / 2
oH = self.outHeight[self.frame] * self.hMax / 2
iW = self.inWidth[self.frame] * self.wMax / 2
iH = self.inHeight[self.frame] * self.hMax / 2
# 試作の直線
# line(self.x, self.y - oH, self.x + oW, self.y) # 右上
# line(self.x + oW, self.y, self.x, self.y + oH) # 右下
# line(self.x, self.y + oH, self.x -oW, self.y) # 左下
# line(self.x -oW, self.y, self.x, self.y - oH) # 左上
# ダイアモンド
arc(self.x + iW, self.y - iH, iW * 2, iH * 2, PI * 0.5, PI ) # 右上
arc(self.x + iW, self.y + iH, iW * 2, iH * 2, PI, PI * 1.5) # 右下
arc(self.x - iW, self.y + iH, iW * 2, iH * 2, PI * 1.5, PI * 2.0) # 左下
arc(self.x - iW, self.y - iH, iW * 2, iH * 2, 0, PI * 0.5) # 左上
line(self.x + iW, self.y, self.x + oW, self.y) # 右
line(self.x - iW, self.y, self.x - oW, self.y) # 左
line(self.x, self.y - iH, self.x, self.y - oH) # 上
line(self.x, self.y + iH, self.x, self.y + oH) # 下
self.countUp()



