ランダム関数の「ジェニーン・レティ芸術」ガイド
91439 ワード
サマリ
最近、私たちは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) {
}
}
addEntity
、removeEntity
からアプリケーションインスタンスをインポートしたり、他のエンティティを追加または削除したり、自分を削除したりできます.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;
}
}
addEntity
、removeEntity
、および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は、App
のstart
を呼び出す必要がある.// 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が募集中です.
興味のある方は見てみましょう求人広告はここです。です.
Reference
この問題について(ランダム関数の「ジェニーン・レティ芸術」ガイド), 我々は、より多くの情報をここで見つけました https://velog.io/@kimbyungchan/Generative-Artテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol