ランダム関数の「ジェニーン・レティ芸術」ガイド


サマリ


最近、私たちはNFT市場を理解し、開発の過程で自然に私のオリジナル芸術を理解しました.
私のオリジナル芸術は簡単にシステムから作品を生成することを意味します.ここでは、作品を創造できるシステム、環境を作りました.
(レイヤーを1つのレイヤーに分割して除外して画像を作成することもありますが)

有名な古典芸術



以上の作品はDmitri CherniakのRingers作品です.最後の取引価格は2100 ETHです.

上の作品はTyler Hobbsのフィデンザという作品です最後の取引価格は1000 ETHです.

以上の作品はKjetil GolidのArchetype作品です.前回の取引価格は420 ETHだった.

以上の作品はMatt DesLauriersのSubscapesという作品です.最後の取引価格は175 ETHです.
以上の作品は、ホスティング、民定、マネージメントサービスをベースに制作されたArt Blockという総合芸術です.ユニークな点は、サードパーティ製アートのソースコードをブロックチェーンに書き込んで管理できることです.

直接作成


自ら芸術を作って芸術家になろう作成する前に、いくつかのルールがあります.
  • の解像度は同じでなければなりません.
  • はランダムではありません.△つまり、どんな種でも得る芸術は、後の作品でも同じ作品でなければならない.
  • 🗒 ネーミング作品


    作品に名前をつけるのが一番面白い部分だと思います.まず作品の全体性と視覚効果を想像して名前を決めましょう
    私はScatterにします.

    🌩 開発環境の構成


    vitejsのバニラ環境から始めました.
    index.htmlに以下のcssを入れてください
    * {
      margin: 0;
      padding: 0;
    }
    
    html, body {
      width: 100%;
      height: 100%;
    }
    
    body {
      display: flex;
      justify-content: center;
      align-items: center;
    }
    
    canvas {
      vertical-align: middle;
    }

    🔥 コードの作成

    // App.ts
    export class App {
      private static instance: App;
    
      public static getInstance() {
        if (!this.instance) {
          throw new Error("App is not initialized");
        }
    
        return this.instance;
      }
    
      canvas: HTMLCanvasElement;
      context: CanvasRenderingContext2D;
    
      scale: number;
      fixedDelta: number = 1 / 60;
    
      constructor() {
        this.canvas = document.createElement('canvas');
        const context = this.canvas.getContext('2d');
        if (!context) {
          throw new Error('Could not get canvas rendering context 2d');
        }
    
        this.context = context;
    
        this.resize = this.resize.bind(this);
        this.render = this.render.bind(this);
        this.resize();
        window.addEventListener('resize', this.resize);
        window.requestAnimationFrame(this.render);
        document.body.appendChild(this.canvas);
        App.instance = this;
      }
    
      render() {
        window.requestAnimationFrame(this.render);
      }
    
      resize() {
        const side = Math.min(
          window.innerWidth,
          window.innerHeight,
        );
    
        this.scale = side / 1000;
    
        this.canvas.width = side;
        this.canvas.height = side;
      }
    }
    // main.ts
    import { App } from "./App";
    
    window.addEventListener('load', () => {
      new App();
    });
    ここまで書くとhttp://localhost:3000に接続されています
    canvasが画面に合うように1:1の割合で再調整されているのが見えます.
    App Classをモノトーンモードで作成しました.キャンバスは1000ベースのscale値を作成します.
    scale値にレンダリング位置を乗算してください.
    requestAnimationFrameは、呼び出し速度がモニタのリフレッシュレートに依存するため、一定時間の微分値を使用して演算されます.
    requestAnimationFrame Function Callを変更して、後で固定FPSを使用できるようにする必要があります.
    次に、基本エンティティを作成し、それを継承して他のオブジェクトを作成します.
    // Entity.ts
    export class Entity {
      addEntity(entity: Entity) {
    
      }
    
      removeEntity(entity: Entity) {
    
      }
      
      start() {
        
      }
    
      update(delta: number) {
    
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
    
      }
    }
    addEntityremoveEntityからアプリケーションインスタンスをインポートしたり、他のエンティティを追加または削除したり、自分を削除したりできます.updateはエンティティの値を更新し、renderはエンティティの値を使用してレンダリングします.
    さらにAppに移動し、Frame Loopを実現し続けます.
    // App.ts
    import { Entity } from "./Entity";
    
    export class App {
      private static instance: App;
    
      public static getInstance() {
        if (!this.instance) {
          throw new Error("App is not initialized");
        }
    
        return this.instance;
      }
    
      canvas: HTMLCanvasElement;
      context: CanvasRenderingContext2D;
      entities: Array<Entity> = [];
    
      scale: number;
      fixedDelta: number = 1 / 60;
    
      constructor() {
        this.canvas = document.createElement('canvas');
        const context = this.canvas.getContext('2d');
        if (!context) {
          throw new Error('Could not get canvas rendering context 2d');
        }
    
        this.context = context;
    
        this.resize = this.resize.bind(this);
        this.render = this.render.bind(this);
        this.resize();
        window.addEventListener('resize', this.resize);
        window.requestAnimationFrame(this.render);
        document.body.appendChild(this.canvas);
        App.instance = this;
      }
    
      addEntity(entity: Entity) {
        this.entities.push(entity);
        entity.start();
      }
    
      removeEntity(entity: Entity) {
        const index = this.entities.indexOf(entity);
        if (index !== -1) {
          this.entities.splice(index, 1);
        }
      }
    
      render() {
        window.requestAnimationFrame(this.render);
    
        for (let i = 0; i < this.entities.length; i++) {
          const entity = this.entities[i];
          entity.update(this.fixedDelta);
          entity.render(this.context, this.scale);
        }
      }
    
      resize() {
        const side = Math.min(
          window.innerWidth,
          window.innerHeight,
        );
    
        this.scale = side / 1000;
    
        this.canvas.width = side;
        this.canvas.height = side;
      }
    }
    addEntityremoveEntity、およびrenderの関数セクションが追加および変更されました.
    次にEntityに戻り、addEntityおよびremoveEntity関数を記述します.
    // Entity.ts
    import { App } from "./App";
    
    export class Entity {
      addEntity(entity: Entity) {
        App.getInstance().addEntity(entity);
      }
    
      removeEntity(entity: Entity) {
        App.getInstance().removeEntity(entity);
      }
    
      start() {
    
      }
    
      update(delta: number) {
    
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
    
      }
    }
    Entityを引き続き使用できるようになりました.
    // BallSpawner.ts
    import { Entity } from "./Entity";
    
    export class BallSpawner extends Entity {
      start() {
        console.log('start ball spawner');
      }
    }
    BallSpawnerを作成し、Appからstartを呼び出すには、addEntityという以前に作成した関数を使用する必要があります.
    // App.ts
    
    // ... 생략
      start() {
        this.addEntity(new BallSpawner());
      }
    // ...
    start関数が追加され、BallSpawnerおよびaddEntityが生成される.今はmaintsは、Appstartを呼び出す必要がある.
    // main.ts
    import { App } from "./App";
    
    window.addEventListener('load', () => {
      const app = new App();
      app.start();
    });
    これに基づいて、コンソールには"start ball spawner"というメッセージが表示されます.
    次に、BallSpanwerで生成されるBallを作成します.
    // Ball.ts
    import { Entity } from "./Entity";
    
    export class Ball extends Entity {
      x: number;
      y: number;
      radius: number;
    
      constructor(x: number, y: number, radius: number) {
        super();
    
        this.x = x;
        this.y = y;
        this.radius = radius;
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
        context.beginPath();
        context.arc(this.x * scale, this.y * scale, this.radius * scale, 0, 2 * Math.PI);
        context.fill();
      }
    }
    既定では、円を描くBall Classです.これはBallSpanwerで生成されるでしょう
    // BallSpawner.ts
    import { Entity } from "./Entity";
    import { Ball } from "./Ball";
    
    export class BallSpawner extends Entity {
      start() {
        this.spawn();
      }
    
      spawn() {
        this.addEntity(new Ball(100, 100, 10));
      }
    }

    そのまま出てきました今から動かしましょう
    // PRNG.ts
    const MAX_INTEGER = 2147483647;
    
    export class PRNG {
      seed: number;
      
      constructor(seed: number) {
        this.seed = seed % MAX_INTEGER;
        if (this.seed <= 0) {
          this.seed += MAX_INTEGER - 1;
        }
      }
    
      private next() {
        this.seed = this.seed * 16807 % MAX_INTEGER;
      }
    
      double() {
        this.next();
        return this.seed / MAX_INTEGER;
      }
    }
    医師卵子ジェネレータを作成する
    // Utils.ts
    import { PRNG } from "./PRNG";
    
    export class Utils {
      static random = new PRNG(0);
    }
    ユーティリティクラスを作成します.
    // Ball.ts
    import { Entity } from "./Entity";
    import { Utils } from "./Utils";
    
    export class Ball extends Entity {
      x: number;
      y: number;
      speed: number;
      angle: number;
      radius: number;
    
      constructor() {
        super();
    
        this.x = Utils.random.double() * 1000;
        this.y = Utils.random.double() * 1000;
        this.speed = Utils.random.double() * 200 + 50;
        this.angle = Utils.random.double() * Math.PI * 2;
        this.radius = Utils.random.double() * 2 + 2;
      }
    
      update(delta: number) {
        const speed = this.speed * delta;
    
        this.x += Math.cos(this.angle) * speed;
        this.y += Math.sin(this.angle) * speed;
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
        context.beginPath();
        context.arc(this.x * scale, this.y * scale, this.radius * scale, 0, 2 * Math.PI);
        context.fill();
      }
    }
    先ほど作成したランダムジェネレータを利用してすべてのPropertyをランダムに生成しました
    // BallSpawner.ts
    import { Entity } from "./Entity";
    import { Ball } from "./Ball";
    
    export class BallSpawner extends Entity {
      start() {
        this.spawn();
      }
    
      spawn() {
        for (let i = 0; i < 100; i++) {
          this.addEntity(new Ball());
        }
      }
    }
    ランダムに100個生成

    このような方法で現れるのが見えます.色を追加します.
    // PRNG.ts
    
    // ... 생략
      color() {
        return `rgb(${this.double() * 255}, ${this.double() * 255}, ${this.double() * 255})`;
      }
    // ...
    // Ball.ts
    import { Entity } from "./Entity";
    import { Utils } from "./Utils";
    
    export class Ball extends Entity {
      x: number;
      y: number;
      speed: number;
      angle: number;
      radius: number;
      color: string;
    
      constructor() {
        super();
    
        this.x = Utils.random.double() * 1000;
        this.y = Utils.random.double() * 1000;
        this.speed = Utils.random.double() * 200 + 50;
        this.angle = Utils.random.double() * Math.PI * 2;
        this.radius = Utils.random.double() * 2 + 2;
        this.color = Utils.random.color();
      }
    
      update(delta: number) {
        const speed = this.speed * delta;
    
        this.x += Math.cos(this.angle) * speed;
        this.y += Math.sin(this.angle) * speed;
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
        context.beginPath();
        context.fillStyle = this.color;
        context.arc(this.x * scale, this.y * scale, this.radius * scale, 0, 2 * Math.PI);
        context.fill();
      }
    }
    ランダムに色を生成する関数を追加し、Ballクラスに色プロファイルを追加し、レンダリング関数で使用します.

    次に、回転するコードを追加します.
    // Ball.ts
    
    // ...생략
      update(delta: number) {
        const speed = this.speed * delta;
    
        this.x += Math.cos(this.angle) * speed;
        this.y += Math.sin(this.angle) * speed;
    
        this.angle += Utils.random.double() * 100.0 * delta;
      }
    // ...
    Ballクラスのupdate関数を変更しました.

    このように描画します.
    PRNGクラスを作成するときに異なるseed値を与えると、新しい作品が表示されます.

    🐼 適用

    // Ball.ts
    import { Entity } from "./Entity";
    import { Utils } from "./Utils";
    
    export class Ball extends Entity {
      x: number;
      y: number;
      speed: number;
      angle: number;
      radius: number;
      color: string;
      depth: number = 0;
    
      constructor() {
        super();
    
        this.radius = Utils.random.double() * 2 + 1;
        this.x = this.radius + Utils.random.double() * (1000 - this.radius);
        this.y = this.radius + Utils.random.double() * (1000 - this.radius);
        this.speed = Utils.random.double() * 200 + 100;
        this.angle = Utils.random.double() * Math.PI * 2;
        this.color = Utils.random.color();
      }
    
      update(delta: number) {
        let speed = this.speed * delta;
        if (speed > this.radius) {
          speed = this.radius;
        }
    
        this.x += Math.cos(this.angle) * speed;
        this.y += Math.sin(this.angle) * speed;
    
        const isEnteredLeft = this.x <= this.radius;
        const isEnteredRight = this.x + this.radius >= 1000;
        const isEnteredBottom = this.y + this.radius >= 1000;
        const isEnteredTop = this.y <= this.radius;
    
        const isEnteredHorizontal = isEnteredLeft || isEnteredRight;
        const isEnteredVertical = isEnteredTop || isEnteredBottom;
    
        if (isEnteredLeft) {
          this.x = this.radius;
        } else if (isEnteredRight) {
          this.x = 1000 - this.radius;
        }
    
        if (isEnteredTop) {
          this.y = this.radius;
        } else if (isEnteredTop) {
          this.y = 1000 - this.radius;
        }
    
        if (this.depth > 0) {
          this.radius -= delta * 0.1;
          if (this.radius <= 0) {
            this.radius = 0;
            this.removeEntity(this);
          }
        }
    
        if (isEnteredHorizontal || isEnteredVertical) {
          this.removeEntity(this);
    
          if (this.depth < 2) {
            const childSize = (this.depth + 1) * 2;
            const childAngle = isEnteredHorizontal ? Math.PI - this.angle : Math.PI * 2.0 - this.angle;
    
            for (let i = 0; i < childSize; i++) {
              const ball = new Ball();
              ball.x = this.x;
              ball.y = this.y;
              ball.color = this.color;
              ball.speed = this.speed * 0.9;
              ball.angle = childAngle;
              ball.radius = this.radius;
              ball.depth = this.depth + 1;
              this.addEntity(ball);
            }
          }
        }
    
        this.angle += (Utils.random.double() - 0.5) * 5.0 * delta;
      }
    
      render(context: CanvasRenderingContext2D, scale: number) {
        context.save();
        context.beginPath();
        context.fillStyle = this.color;
        context.arc(this.x * scale, this.y * scale, this.radius * scale, 0, 2 * Math.PI);
        context.fill();
        context.restore();
      }
    }

    簡単な修正でScatter効果が追加されました.
    この文章では、私の計画を簡単に実施しました.次の文章では、より芸術的なオリジナル芸術を創造します.
    ソースコード
    WE-ARが募集中です.
    興味のある方は見てみましょう求人広告はここです。です.