3-3. マスク画像の紹介

前回マスク画像を試しました。このBooks内に用意している他のマスク画像を紹介します。これらの画像はBooks内で自由に使えます。以下のコードで練習してみましょう。 以下の例のようにPGMask()を複数作ります。読み込む画像名は"mask-star", “mask-snow”, “mask-sparkle”, “mask-smoke"です。色は.color( .white )を指定します。 背景色は screen.clearColor =.darkGrey にします。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 func design( screen:PGScreen ) { screen.clearColor = .darkGrey PGMask( "mask-star" ) .scale( square:128 ) .position( cx:-128, cy:128 ) .color( .white ) PGMask( "mask-snow" ) .scale( square:128 ) .position( cx:128, cy:128 ) .color( .white ) PGMask( "mask-sparkle" ) .scale( square:128 ) .position( cx:-128, cy:-128 ) .color( .white ) PGMask( "mask-smoke" ) .scale( square:128 ) .position( cx:128, cy:-128 ) .color( .white ) } 「コードを実行」を押します。 目標 4つのマスク画像が表示されたら成功です。 終わったら次のページへ進みます。 ...

2023-12-16 · 2023-12-16

3-3. 炎をあげる

前のページ 前のページの煙のコードを応用して、炎を表現してみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func design( screen:PGScreen ) { screen.clearColor = .darkGrey for _ in 0 ..< 160 { PGAddMask( "mask-smoke" ) .color( LLColor( 0.9, 0.34, 0.22, 1.0 ) ) .position( cx:(-50 ... 50).randomize, cy:(-120 ... -110).randomize ) .deltaPosition( dx:(-1.0...1.0).randomize, dy:(0.5...4.5).randomize ) .scale( square: 80.0 ) .deltaScale( dw: 0.5, dh: 0.5 ) .angle( .random ) .deltaAngle( degrees:(-2.0...2.0).randomize ) .life( .random ) .deltaLife( -0.01 ) .iterate { if $0.life < 0.5 { $0.alpha( $0.life ) } else { $0.alpha( (1.0 - $0.life) ) } } .completion { $0 .position( cx:(-50 ... 50).randomize, cy:(-120 ... -110).randomize ) .scale( square: 80.0 ) .life( 1.0 ) } } } screen.clearColor = .darkGrey で背景を暗灰色にします。 forで160個の加算合成マスク画像 PGAddMask() を書きます。 画像ファイルはmask-smokeを指定します。 初期設定のコードを書きます。 .color( LLColor( 0.9, 0.34, 0.22, 1.0 ) ) 色。少しオレンジがかった赤を設定します。 .position( cx:(-50...50).randomize, cy:(-120... -110).randomize ) 位置。x方向は-5050のランダム座標, y方向は-120-110のランダム座標を設定します。 (xはある程度のブレがあり、yはほとんど違いのない位置になります) .deltaPosition( dx:(-1.0...1.0).randomize, dy:(0.5...4.5).randomize ) 毎フレーム、x方向に-1.01.0のランダムな等速移動量、y方向に0.54.5のランダムな等速移動量を設定します。 (yのプラスが大きいので、画面上方向へ大きく移動します) .scale( square:80.0 ) 大きさ。80.0ポイントを設定します。 .deltaScale( dw:0.5, dy:0.5 ) 毎フレーム、0.5ポイント拡大します .angle( .random ) 角度。0.0~1.0のランダムから開始します。 .deltaAngle( degrees:(-2.0...2.0).randomize ) 毎フレーム、-2.0~2.0度のランダム値で等速に回転します。 .life( .random ) ライフ。0.0~1.0のランダムから開始します。 .deltaLife( -0.01 ) 毎フレーム、lifeを0.01減少します。 .iterate{ } を用意して、毎フレームのalphaの処理を計算します。 .life が0.5より小さいとき、 $0.life * 2.0 を設定します。 .life が0.5以上のとき、 (1.0 - $0.life) * 2.0 を設定します。 上記の計算により、lifeが0.5の時、もっとも濃く描画します。lifeが0.5より少ない、あるいは多いときは薄くなります。 ...

2023-12-16 · 2023-12-16

3-4. うねる発光体

前のページ ここでは、ぼやけた円と加算合成をつかって、発光体を表現してみます。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func design( screen:PGScreen ) { screen.clearColor = .darkGrey for _ in 0 ..< 80 { PGAddBlurryCircle() .color( .random ) .position( screen.randomPoint ) .scale( square: 100.0 ) .deltaScale( dw: 0.5, dh: 0.5 ) .alpha( 0 ) .life( .random ) .deltaLife( -0.003 ) .iterate { $0.alpha( sin( $0.life * Float.pi ) ) } .completion { $0 .color( .random ) .position( screen.randomPoint ) .scale( square: 100.0 ) .life( 1.0 ) .alpha( 0 ) } } } screen.clearColor = .darkGrey で背景を暗灰色にします。 forで80個の加算合成のぼやけた縁 PGAddBlurryCircle() を書きます。 初期設定のコードを書きます。 .color( .random ) 色。ランダムを設定します。 .position( screen.randomPoint ) 位置。画面内のランダム座標を設定します。 .scale( square:100.0 ) 大きさ。100.0ポイントを設定します。 .deltaScale( dw:0.5, dy:0.5 ) 毎フレーム、0.5ポイント拡大します。 .alpha( 0 ) アルファ。透明から開始します。 .life( .random ) ライフ。0.0~1.0のランダムから開始します。 .deltaLife( -0.003 ) 毎フレーム、lifeを0.003減少します。 .iterate{ } を用意して、毎フレームのalphaの処理を計算します。 .alpha( sin( $0.life * Float.pi ) ) lifeに合わせたサイン値です。 上記の計算で、.life=1.0で透明、0.5のときにもっとも濃くなり、0.0で透明に戻ります。 ...

2023-12-16 · 2023-12-16

3-4. マスクを重ねる表現

マスク用画像の紹介を試しました。マスクを使った図形を重ねるていくと豊かで複雑な表現が可能になります。 ここではスモーク画像を重ねて絵を作ってみます。 背景色はscreen.clearColor = .darkGreyを指定します。 PGMask( "mask-smoke" ) をforループで50個重ねてみましょう。 .position、.scale、.alpha、.angle をつかって以下のようにランダムな値を指定します。 1 2 3 4 5 6 7 8 9 10 11 12 13 func design( screen:PGScreen ) { screen.clearColor = .darkGrey for _ in 0 ..< 50 { PGMask( "mask-smoke" ) .scale( square:(16...192).randomize ) .position( cx:(-128...128).randomize, cy:(-128...128).randomize ) .alpha( .random ) .angle( .random ) .color( .white ) } } 「コードを実行」を押します。 目標 煙が重なっているような表現ができたら成功です。 (+1) 何回かコード実行をしてみてください。色々な形の煙ができます。 ...

2023-12-16 · 2023-12-16

3-5. 噴水

前のページ 前のページと同様、ぼやけた円と加算合成を用いて、噴水のような表現を考えてみます。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 func design( screen:PGScreen ) { screen.clearColor = .darkGrey for _ in 0 ..< 1000 { PGAddBlurryCircle() .color( LLColor( 0.16, 0.3, 0.5, 0.8 ) ) .position( cx:(-10...10).randomize, cy:screen.minY - (0.0...48.0).randomize ) .deltaPosition( dx:(-2.0...2.0).randomize, dy:(19.0...20.0).randomize ) .scale( square: 48.0 ) .life( .random ) .deltaLife( -0.008 ) .iterate { $0.deltaPosition( dx:$0.deltaPosition.x, dy:$0.deltaPosition.y - 0.35 ) } .completion { $0 .position( cx:(-10...10).randomize, cy:screen.minY - (0.0...48.0).randomize ) .deltaPosition( dx:(-2.0...2.0).randomize, dy:(19.0...20.0).randomize ) .life( 1.0 ) } } } screen.clearColor = .darkGrey で背景を暗灰色にします。 forで1000個の加算合成のぼやけた円 PGAddBlurryCircle() を書きます。 初期設定のコードを書きます。 .color( LLColor( 0.16, 0.3, 0.5, 0.8 ) ) 色。水色を設定します。 .position( cx:(-10...10).randomize, cy:screen.minY - (0.0...48.0).randomize ) 位置。x方向は中央付近, y方向は画面下へ配置します。 .deltaPosition( dx:(-2.0...2.0).randomize, dy:(19.0...20.0).randomize ) 毎フレーム、x方向に-2.0~2.0ポイントのランダムに移動, y方向に約20ポイント移動します。(少し左右に振れつつ、上方向へ飛び上がります) .scale( square:48.0 ) 大きさ。48.0ポイントを設定します。 .alpha( 0 ) アルファ。透明を設定します。 .life( .random ) ライフ。0.0~1.0のランダムを設定します。 .deltaLife( -0.008 ) 毎フレーム、lifeを0.008減少します。 .iterate{ } を用意して、毎フレームのdeltaPositionを変化します。 .deltaPosition( dx:$0.deltaPosition.x, dy:$0.deltaPosition.y - 0.35 ) x方向の移動量は変化なし, y方向の移動量を-0.35していきます。 上記の計算により、だんだんと上方向への移動量が減り、下に落ちるようになります。 ...

2023-12-16 · 2023-12-16

3-6. ぼたん雪の降る夜

前のページ ぼやけた円を雪にみたてて、これを降らせてみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 func design( screen:PGScreen ) { screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) for _ in 0 ..< 80 { let size = (10.0 ... 50.0).randomize let speed = size / 50.0 let c = LLColor( 0.9, 0.95, 1.0, Float( speed ) ) PGBlurryCircle() .color( c ) .position( cx:(screen.minX...screen.maxX).randomize, cy:(screen.minY-200...screen.maxY+200).randomize ) .deltaPosition( dx:(-0.5 ... 0.5).randomize * speed, dy:(-8.0 ... -6.5).randomize * speed ) .scale( square:size ) .iterate { if $0.position.y < Float( screen.minY - 200.0 ) { $0 .position( cx:(screen.minX...screen.maxX).randomize, cy:screen.maxY + 200 ) } } } } screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) で背景を群青色にします。 forで、80回繰り返します。 forの中に、初期設定に必要な変数をつくります。 let size = (10.0 ... 50.0).randomize 大きさ用の変数。10.0~50.0のランダム値をつくり、代入します。 let speed = size / 50.0 速度用の変数。sizeに合わせて0.2~1.0の値をつくり、代入します。 let c = LLColor( 0.9, 0.95, 1.0, Float( speed ) ) 色用の変数。少し青みがかった白をつくり、代入します。またアルファにspeedの値を設定します。 forの中で、ぼやけた円 PGBlurryCircle() をつくります。 初期設定のコードを書きます。 .color( c ) 色。変数cを指定します。 .position( cx:(screen.minX...screen.maxX).randomize, cy:(screen.minY-200...screen.maxY+200).randomize ) 位置。x方向は左端右端のランダム、 y方向は上端-200下端+200ポイントのランダム座標に設定します。(画面全体から縦にはみ出した範囲にランダムに配置されます)。 .deltaPosition( dx:(-0.5 ... 0.5).randomize * speed, dy:(-8.0 ... -6.5).randomize * speed ) 毎フレームの移動量。x方向は左右-0.50.5ポイントのランダム、 y方向は-8.0-6.5のランダムに変数speedを掛け算した値を設定します。 .scale( square:size ) 大きさ。変数sizeを設定します。 .iterate{ } を用意して、図形の再利用のタイミングをうかがいます。 if $0.position.y < Float( screen.minY - 200.0 ) { ... } 図形が画面の下端から200ポイントはみ出したとき、{ }の中の処理を行います。 .position( cx:(screen.minX...screen.maxX).randomize, cy:screen.maxY+200.randomize ) x方向は左端~右端のランダム、 y方向は上端+200ポイントの位置に再配置します。 「コードを実行」を押します。 目標 雪が降るエフェクトが表示されたら成功です。 次のページ ...

2023-12-16 · 2023-12-16

3-7. トゥインクルスター

前のページ 前のページの雪を降らせるコードを参考に、流れ星の表現をつくってみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 func design( screen:PGScreen ) { screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) for _ in 0 ..< 10 { let size = (40.0 ... 80.0).randomize let speed = size / 80.0 let c = LLColor( 1.0, 0.8, 0.25, Float( speed ) ) PGAddMask( "mask-star" ) .color( c ) .position( cx:(screen.minX-200...screen.maxX+200).randomize, cy:(screen.minY...screen.maxY).randomize ) .deltaPosition( dx:(10.0 ... 12.0).randomize * speed, dy:(-1.5 ... 3.5).randomize * speed ) .scale( square:size ) .angle( .random ) .deltaAngle( degrees:-4.0 * speed ) .iterate { $0.deltaPosition.y -= 0.05 if Float( screen.maxX + 200.0 ) <= $0.position.x { $0 .position( cx:screen.minX-200, cy:(screen.minY...screen.maxY).randomize ) .deltaPosition( dx:(10.0 ... 12.0).randomize * speed, dy:(-1.5 ... 3.5).randomize * speed ) } } .interval( sec:0.05 ) { PGAddCircle() .color( c ) .position( $0.position ) .scale( square:0 ) .deltaScale( dw:0.5 * speed, dh:0.5 * speed ) .alpha( 0 ) .deltaLife( -0.02 ) .iterate { $0.alpha( sin( $0.life * Float.pi ) * 0.5 ) } } } } screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) で背景を群青色にします。 forで、10回繰り返します。 forの中に、初期設定に必要な変数をつくります。 let size = (40.0 ... 80.0).randomize 大きさ用の変数。40.0~80.0のランダム値をつくり、代入します。 let speed = size / 80.0 速度用の変数。sizeに合わせて0.5~1.0の値をつくり、代入します。 let c = LLColor( 1.0, 0.8, 0.25, Float( speed ) ) 色用の変数。少し赤めの黄色を作成し代入します。またアルファにspeedの値を設定します。 forの中で、加算合成マスク画像 PGAddMask( "mask-star" ) をつくります。星の画像を指定します。 初期設定のコードを書きます。 .color( c ) 色。変数cを指定します。 .position( cx:(screen.minX-200...screen.maxX+200).randomize, cy:(screen.minY...screen.maxY).randomize ) 位置。x方向は左端-200右端+200のランダム、 y方向は上端下端ポイントのランダム座標に設定します。(画面全体から横にはみ出した範囲にランダムに配置されます。前回は縦でした。今回は横です) .deltaPosition( dx:(10.0 ... 12.0).randomize * speed, dy:(-1.5 ... 3.5).randomize * speed ) 毎フレームの移動量。x方向は10.012.0ポイントのランダム、 y方向は-1.53.5のランダムに、変数speedを掛け算した値を設定します。(星が右方向へ移動します) .scale( square:size ) 大きさ。変数sizeを設定します。 .angle( .random ) 角度。ランダムを設定します。 .deltaAngle( degrees:-4.0 * speed ) 毎フレームの回転量。-4.0に変数speedを掛け算した値を設定します。(星が時計回りに回転します) .iterate{ } を用意します。y方向の移動量を調整します。また図形の再利用のタイミングをうかがいます。 $0.deltaPosition.y -= 0.05 毎フレーム、y方向の移動量を0.05減らします。(下方向へ速くなります) if Float( screen.maxX + 200.0 ) <= $0.position.x 図形が画面の右端から200ポイントはみ出したとき、{ }の中の処理を行います。 .position( cx:screen.minX-200, cy:(screen.minY...screen.maxY).randomize ) x方向は左端-200ポイント、y方向は下端~上端のランダムの位置に再配置します。 .deltaPosition( dx:(10.0 ... 12.0).randomize * speed, dy:(-1.5 ... 3.5).randomize * speed ) 毎フレームの移動量を初期化します。 ...

2023-12-16 · 2023-12-16

3-8. 跳ね返る円

前のページ 壁に跳ね返るボールを表現してみましょう。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func design( screen:PGScreen ) { screen.clearColor = .black for _ in 0 ..< 20 { let speed = (4.0...8.0).randomize let radians = (0.0...2.0).randomize * Double.pi let dx = speed * cos( radians ) let dy = speed * sin( radians ) PGAddCircle() .color( .random ) .position( cx: (screen.minX + 30 ... screen.maxX - 30).randomize, cy: (screen.minY + 30 ... screen.maxY - 30).randomize ) .deltaPosition( dx:dx, dy:dy ) .scale( square:60 ) .iterate { if $0.position.x - 30 <= Float( screen.minX ) { $0.deltaPosition.x *= -1 } if Float( screen.maxX ) <= $0.position.x + 30 { $0.deltaPosition.x *= -1 } if $0.position.y - 30 <= Float( screen.minY ) { $0.deltaPosition.y *= -1 } if Float( screen.maxY ) <= $0.position.y + 30 { $0.deltaPosition.y *= -1 } } } } screen.clearColor = .black で背景を黒にします。 forで、20回繰り返します。 forの中に、初期設定に必要な変数をつくります。 let speed = (4.0...8.0).randomize 速度用の変数。4.0~8.0のランダム値をつくり、代入します。 let radians = (0.0...2.0).randomize * Double.pi 進行方向の角度の変数。0~2πのランダムの値をつくり、代入します。 let dx = speed * cos( radians ) x方向の移動量の変数。変数radiansのコサイン値とspeedを掛け算した値を代入します。 let dy = speed * sin( radians ) y方向の移動量の変数。変数radiansのサイン値とspeedを掛け算した値を代入します。 forの中で、加算合成の円 PGAddCircle() をつくります。 PGAddCircleの初期設定のコードを書きます。円の大きさは60ポイント、半径が30ポイントになります。 .color( .random ) 色。ランダムな色を設定します。 .position( cx: (screen.minX + 30 ... screen.maxX - 30).randomize, cy: (screen.minY + 30 ... screen.maxY - 30).randomize ) 位置。x方向は左端+30右端-30のランダム、 y方向は上端-30下端+30ポイントのランダム座標に設定します。 .deltaPosition( dx:dx, dy:dy ) 毎フレームの移動量。x方向は変数dx、 y方向は変数dyの値を設定します。 .scale( square:60 ) 大きさ。60ポイントを設定します。 .iterate{ } を用意します。位置によって図形の移動方向を変えます。 if $0.position.x - 30 <= Float( screen.minX ) { ... } 図形の中央x座標 - 30ポイント(円の半径)が、画面の左端に到達したとき、{ }の中の処理を行います。 Float( screen.maxX ) <= $0.position.x + 30 { ... } 図形の中央x座標 + 30ポイント(円の半径)が、画面の右端に到達したとき、{ }の中の処理を行います。 $0.deltaPosition.x *= -1 x方向の移動量の正負を逆にします。 if $0.position.y - 30 <= Float( screen.minX ) { ... } 図形の中央y座標 - 30ポイント(円の半径)が、画面の下端に到達したとき、{ }の中の処理を行います。 Float( screen.maxX ) <= $0.position.y + 30 { ... } 図形の中央y座標 + 30ポイント(円の半径)が、画面の上端に到達したとき、{ }の中の処理を行います。 $0.deltaPosition.y *= -1 y方向の移動量の正負を逆にします。 ...

2023-12-16 · 2023-12-16

3-9. 花火

前のページ このページでは、次のBooksで紹介する新しい仕組みを先取りし、花火を表現します。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 func design( screen:PGScreen ) { screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) } func update( screen:PGScreen ) { if (0.0...1.0).randomize < 0.97 { return } let size = (10.0...20.0).randomize let speed = size / 4.0 let pos = screen.randomPoint let c = LLColor.random for _ in 0 ..< 150 { let radians = (0.0...2.0).randomize * Double.pi let speed2 = speed * (0.65...1.0).randomize let dx = speed2 * cos( radians ) let dy = speed2 * sin( radians ) PGAddBlurryCircle() .color( c ) .position( pos ) .deltaPosition( dx:dx, dy:dy ) .deltaLife( -0.005 ) .scale( square:size ) .iterate { $0 .deltaPosition( dx:$0.deltaPosition.x * 0.985, dy:$0.deltaPosition.y * 0.985 ) .cy( $0.cy - 1.5 ) .alpha( $0.life ) } } } func design( screen:PGScreen ) { } に加えて、func update( screen:PGScreen ) { } 関数を追加します。このupdateが新しい仕組みです。毎フレーム繰り返し処理される関数です。 design( screen:PGScreen ) 内に screen.clearColor = LLColor( 0.0, 0.05, 0.2, 1.0 ) を書き、背景を群青色にします。design( screen:PGScreen )のコードはこれで完了です。 update( screen:PGScreen )内に処理を書いていきます。まず図形をつくる確率を調整します。 if (0.0...1.0).randomize < 0.97 { return } 97%の確率で何もせず、update関数を終了(return)します。 update( screen:PGScreen )は毎秒最大60回実行されます。 上記の処理により、updateが呼ばれたら3%の確率で処理を継続します。 ...

2023-12-16 · 2023-12-16

4-1. 重ねて模様をつくる

前章 まで、Lily Playgroundでの図形や画像の描き方を紹介しました。この章は、ここまで学んだ図形を並べて、模様を作っていきたいと思います。きれいな模様を描いていきましょう。 x,yの2重のfor文をつくり、その中で円が規則的に並ぶようにコードを書きます。 円の色を交互に変えるように、条件分岐で色を変化させましょう。変数var cをつくります。cには色(LLColor.clear)を入れます。 チェッカーの条件にならって、cの値を変えてみましょう。条件ごとにオレンジ色( 1.0, 0.5, 0.0, 1.0 )と、明るい緑色( 0.2, 0.8, 0.2, 1.0 ) をcに入れます。 c を円の .color に使います。すると 「c の色が変わる = 円の色が変わる」ことになります。手順3の条件で cの色は互い違いになったので、円の色も互い違いにできます。 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 func design( screen:PGScreen ) { for y in 0 ..< 9 { for x in 0 ..< 9 { var c = LLColor.clear if (x + y) % 2 == 0 { c = LLColor( 1.0, 0.5, 0.0, 1.0 ) } else { c = LLColor( 0.2, 0.8, 0.2, 1.0 ) } PGCircle() .scale( square:100 ) .position( cx: -200 + x * 50, cy: -200 + y * 50 ) .color( c ) .alpha( 0.33 ) } } } 「コードを実行」を押します。 目標 重ねた円による模様が表現できたら成功です。 終わったら次のページへ進みます。 ...

2023-12-16 · 2023-12-16