Skip to content

Commit

Permalink
Organisms now clone similar sprite, refers to #15
Browse files Browse the repository at this point in the history
- when an organism makes a clone,
    the new clone has a similar shape to the parent
- fixed the problem with gradient and scratch
- add "pupils" to the organism with gradient
  • Loading branch information
raffaelepojer committed Aug 19, 2020
1 parent f4b6000 commit b9b1286
Show file tree
Hide file tree
Showing 2 changed files with 145 additions and 61 deletions.
54 changes: 31 additions & 23 deletions src/extensions/botch/organism.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,47 +21,50 @@ class Organism {
* @param {RenderedTarget} target_ target (sprite)
* @param {number} mass_ mass of the vehicle
* @param {number} maxForce_ max force of the vehicle
* @param {string} svg_ new svg of the organism
* @param {Array} dna dna
* @param {string} svgPoints_ svg points of the organism
* @param {Array} dna_ dna
*/
constructor (target_, mass_ = 1, maxForce_ = 0.5, svg_, dna) {
constructor (target_, mass_ = 1, maxForce_ = 0.5, svgPoints_, dna_,) {
// vehicle proprieties
this.acceleration = new Vector2(0, 0);
this.velocity = new Vector2(1, 2);
this.position = new Vector2(target_.x, target_.y);
this.maxSpeed = 5;
this.maxForce = maxForce_; // agility ?
this.target = target_;
this.mass = mass_;
this.svg = svg_;
// organism utils and proprieties
this.target = target_;
this.svgPoints = svgPoints_;
this.health = 1;
this.renderer = this.target.renderer;
this.runtime = this.target.runtime;
this.storage = this.runtime.storage;
this.mr = 0.01;
this.living = 0; // performance.now();
this.living = 0;
this.effectStep = 7;
this.currEffectStep = this.effectStep;
this.effectSign = 1;
this.dna = [];
// utils
this.renderer = this.target.renderer;
this.runtime = this.target.runtime;
this.storage = this.runtime.storage;

this.svgGen = new svgen(100, 100);
this.botchUtil = new BotchUtil(this.runtime);

this.dna = [];

if (dna) {
if (dna_) {
// Mutation
this.dna[0] = dna[0];
this.dna[0] = dna_[0];
if (Math.random() < this.mr) {
this.dna[0] += this.botchUtil.rdn(-0.3, 0.3);
this.dna[0] += this.botchUtil.rdn(-1, 1);
}
this.dna[1] = dna[1];
this.dna[1] = dna_[1];
if (Math.random() < this.mr) {
this.dna[1] += this.botchUtil.rdn(-0.3, 0.3);
this.dna[1] += this.botchUtil.rdn(-1, 1);
}
this.dna[2] = dna[2];
this.dna[2] = dna_[2];
if (Math.random() < this.mr) {
this.dna[2] += this.botchUtil.rdn(-15, 15);
}
this.dna[3] = dna[3];
this.dna[3] = dna_[3];
if (Math.random() < this.smr) {
this.dna[3] += this.botchUtil.rdn(-15, 15);
}
Expand All @@ -72,9 +75,14 @@ class Organism {
this.dna[3] = Math.random() * 150; // poison perception
}

// this.svg = new svgen(130, 130).generateMultiple(this.dna[0], this.dna[1], 5);
this.svg = new svgen(130, 130).generateOrgSVG(100, this.dna[0], this.dna[1], 5);
this.botchUtil.uploadCostumeEdit(this.svg, this.target.id);
if (svgPoints_) {
this.svg = this.svgGen.generateOrgSVG(100, this.dna[0], this.dna[1], 5, svgPoints_);
this.botchUtil.uploadCostumeEdit(this.svg, this.target.id);
} else {
// this.svg = new svgen(130, 130).generateMultiple(this.dna[0], this.dna[1], 5);
this.svg = this.svgGen.generateOrgSVG(100, this.dna[0], this.dna[1], 5);
this.botchUtil.uploadCostumeEdit(this.svg, this.target.id);
}

// Variable assignment to the sprite
// each clone has the its own dna saved and the dna of the non-clone target
Expand Down Expand Up @@ -277,8 +285,8 @@ class Organism {
* @since botch-0.1
*/
clone () {
if (/* !this.target.isOriginal && */Math.random() < 0.002) {
return new Organism(this.target, 1, 0.5, this.svg, this.dna);
if (Math.random() < 0.002) {
return new Organism(this.target, 1, 0.5, this.svgGen.getOrgPoints(), this.dna);
}
return null;
}
Expand Down
152 changes: 114 additions & 38 deletions src/extensions/botch/svg-generator.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const Vector2 = require('./vector2');
const MathUtil = require('../../util/math-util');
const Organism = require('./organism');

class SVGgen {
/**
Expand All @@ -15,6 +16,9 @@ class SVGgen {
this.color = color;
this.points = [];
this.strokeWidth = 4;

this.svgPoints = [];
this.controlPoints = [];
}

rdn (min, max) {
Expand Down Expand Up @@ -72,78 +76,150 @@ class SVGgen {
});
}

/**
* Return the points of the org svg
* @returns {Array} in array[0] = svg points, array[1] = control points
* @since botch-0.2
*/
getOrgPoints () {
return [this.svgPoints, this.controlPoints];
}

/**
* Generate an SVG using quadratic bezier curve
* the function works on a squared svg canvas
* it create 4 points on the diagonals
* y = x
* y = -x + this.height
* if parentPoints point is defined, it create a shape with similar points
* @param {number} dim dimension of the svg (square)
* @param {number} foodR food attraction
* @param {number} poisonR poison attraction
* @param {number} mag max poison or food attraction
* @param {Array} parentPoints the points of the parent
* @returns {string} the svg
* @since botch-0.2
* fa piuttosto schifo da vedere come funzione...
*/
generateOrgSVG (dim, foodR, poisonR, mag) {
generateOrgSVG (dim, foodR, poisonR, mag, parentPoints) {
const f = MathUtil.scale(foodR, -mag, mag, 0, 15);
const p = MathUtil.scale(poisonR, -mag, mag, 0, 15);

// resize the canvas
// resize the canvas to be a square
this.width = dim;
this.height = dim;

// generate the 4 points on the diagonal

const margin = 15;
const w1 = (this.width / 2) - margin;
const w2 = (this.width / 2) + margin;

const ta = Math.floor(this.rdn(0, w1));
const p1 = new Vector2(ta, ta);
// the new points differ by -min +max from the parent point
const min = -10;
const max = 10;
let p1; let p2; let p3; let p4; let c1; let c2; let c3; let c4;

if (parentPoints) {
// generate the 4 points on the diagonal
const ta = MathUtil.clamp(
parentPoints[0][0].x + Math.floor(this.rdn(min, max)), 0, w1);
p1 = new Vector2(ta, ta);

const tb = MathUtil.clamp(
parentPoints[0][1].x + Math.floor(this.rdn(min, max)), w2, this.width - margin);
p2 = new Vector2(tb, -tb + this.height);

const tc = MathUtil.clamp(
parentPoints[0][2].x + Math.floor(this.rdn(min, max)), w2, this.width - margin);
p3 = new Vector2(tc, tc);

const td = MathUtil.clamp(
parentPoints[0][3].x + Math.floor(this.rdn(min, max)), 0, w1);
p4 = new Vector2(td, -td + this.height);

// generate the 4 control points
const va = MathUtil.clamp(
parentPoints[1][0].x + Math.floor(this.rdn(min, max)), 0, this.width);
const v2a = va < this.width / 2 ?
Math.floor(this.rdn(0, va)) : Math.floor(this.rdn(0, -va + this.height));
c1 = new Vector2(va, v2a);

const vb = MathUtil.clamp(
parentPoints[1][1].x + Math.floor(this.rdn(min, max)), this.width / 2, this.width);
const v2b = Math.floor(this.rdn(-vb + this.height, vb));
c2 = new Vector2(vb, v2b);

const vc = MathUtil.clamp(
parentPoints[1][2].x + Math.floor(this.rdn(min, max)), 0, this.width);
const v2c = vc < this.width / 2 ?
Math.floor(this.rdn(-vc + this.height, this.height)) : Math.floor(this.rdn(vc, this.height));
c3 = new Vector2(vc, v2c);

const vd = MathUtil.clamp(
parentPoints[1][3].x + Math.floor(this.rdn(min, max)), 0, this.width / 2);
const v2d = Math.floor(this.rdn(vd, -vd + this.height));
c4 = new Vector2(vd, v2d);
} else {
// generate the 4 points on the diagonal
const ta = Math.floor(this.rdn(0, w1));
p1 = new Vector2(ta, ta);

const tb = Math.floor(this.rdn(w2, this.width - margin));
const p2 = new Vector2(tb, -tb + this.height);
const tb = Math.floor(this.rdn(w2, this.width - margin));
p2 = new Vector2(tb, -tb + this.height);

const tc = Math.floor(this.rdn(w2, this.width - margin));
const p3 = new Vector2(tc, tc);
const tc = Math.floor(this.rdn(w2, this.width - margin));
p3 = new Vector2(tc, tc);

const td = Math.floor(this.rdn(0, w1));
const p4 = new Vector2(td, -td + this.height);
const td = Math.floor(this.rdn(0, w1));
p4 = new Vector2(td, -td + this.height);

// generate the 4 control points
const va = Math.floor(this.rdn(0, this.width));
const v2a = va < this.width / 2 ?
Math.floor(this.rdn(0, va)) : Math.floor(this.rdn(0, -va + this.height));
const c1 = new Vector2(va, v2a);
// generate the 4 control points
const va = Math.floor(this.rdn(0, this.width));
const v2a = va < this.width / 2 ?
Math.floor(this.rdn(0, va)) : Math.floor(this.rdn(0, -va + this.height));
c1 = new Vector2(va, v2a);

const vb = Math.floor(this.rdn(this.width / 2, this.width));
const v2b = Math.floor(this.rdn(-vb + this.height, vb));
const c2 = new Vector2(vb, v2b);
const vb = Math.floor(this.rdn(this.width / 2, this.width));
const v2b = Math.floor(this.rdn(-vb + this.height, vb));
c2 = new Vector2(vb, v2b);

const vc = Math.floor(this.rdn(0, this.width));
const v2c = vc < this.width / 2 ?
Math.floor(this.rdn(-vc + this.height, this.height)) : Math.floor(this.rdn(vc, this.height));
const c3 = new Vector2(vc, v2c);
const vc = Math.floor(this.rdn(0, this.width));
const v2c = vc < this.width / 2 ?
Math.floor(this.rdn(-vc + this.height, this.height)) : Math.floor(this.rdn(vc, this.height));
c3 = new Vector2(vc, v2c);

const vd = Math.floor(this.rdn(0, this.width / 2));
const v2d = Math.floor(this.rdn(vd, -vd + this.height));
const c4 = new Vector2(vd, v2d);
const vd = Math.floor(this.rdn(0, this.width / 2));
const v2d = Math.floor(this.rdn(vd, -vd + this.height));
c4 = new Vector2(vd, v2d);
}

this.svgPoints = [p1, p2, p3, p4];
this.controlPoints = [c1, c2, c3, c4];

return `<svg height="${this.height}" width="${this.width}" viewBox="0 0 ${this.width} ${this.height}" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">` +
`<defs> ` +
`<radialGradient id="RadialGradient1"> ` +
`<stop offset="0%" stop-color="${this.colorLuminance(this.color, 0.4)}"/> ` +
`<stop offset="100%" stop-color="${this.colorLuminance(this.color, -0.2)}"/> ` +
`<radialGradient id="RadialGradient1" ` +
`cx="${this.width / 2}" cy="${this.height / 2}" r="${this.width / 3}" ` +
`gradientUnits="userSpaceOnUse"> ` +
`<stop offset="0" style="stop-color:${this.colorLuminance(this.color, 0.4)}"></stop> ` +
`<stop offset="1" style="stop-color:${this.colorLuminance(this.color, -0.2)}"></stop> ` +
`</radialGradient>` +
`<radialGradient id="RadialGradient2" ` +
`cx="${p2.x}" cy="${p2.y}" r="${f / 3}" ` +
`gradientUnits="userSpaceOnUse"> ` +
`<stop offset="0" style="stop-color:${this.colorLuminance(this.color, -0.9)}"></stop> ` +
`<stop offset="1" style="stop-color:${this.colorLuminance(this.color, 0.9)}"></stop> ` +
`</radialGradient>` +
`<radialGradient id="RadialGradient3" ` +
`cx="${p3.x}" cy="${p3.y}" r="${p / 3}" ` +
`gradientUnits="userSpaceOnUse"> ` +
`<stop offset="0" style="stop-color:${this.colorLuminance(this.color, -0.9)}"></stop> ` +
`<stop offset="1" style="stop-color:${this.colorLuminance(this.color, 0.9)}"></stop> ` +
`</radialGradient>` +
`</defs>` +
`<path d="M ${p1.x} ${p1.y} Q ${c1.x} ${c1.y} ${p2.x} ${p2.y} Q ${c2.x} ${c2.y} ${p3.x} ${p3.y} ` +
`Q ${c3.x} ${c3.y} ${p4.x} ${p4.y} Q ${c4.x} ${c4.y} ${p1.x} ${p1.y}" ` +
`fill="url(#RadialGradient1)" style="stroke:none;stroke-width:1" />` +
`<circle cx="${p2.x}" cy="${p2.y}" ` +
`r="${f}" stroke="none" stroke-width="1" fill="${this.colorLuminance(this.color, 0.7)}" />` + // food
`fill="url(#RadialGradient1)" stroke="none" stroke-width="1" />` +
`<circle cx="${p2.x}" cy="${p2.y}" ` + // food
`r="${f}" stroke="none" stroke-width="1" fill="url(#RadialGradient2)" />` +
`<circle cx="${p3.x}" cy="${p3.y}" ` +
`r="${p}" stroke="none" stroke-width="1" fill="${this.colorLuminance(this.color, -0.7)}" />` +
// `${this.pointToEyesTr(foodR, poisonR)}` +
`r="${p}" stroke="none" stroke-width="1" fill="url(#RadialGradient3)" />` +
`</svg>`;
}

Expand Down

0 comments on commit b9b1286

Please sign in to comment.