DIR : /home/kozerus/public_html/blob_best.html
/home/kozerus/public_html
<html>
<head>
<title>blob.html 20200418_2130 up down left right new Vector</title>
<!--
<title>blob.html 20200418_0900 keypress shift ctrl</title>
<title>blob.html 20200418_0900 blobsallad</title>
<title>blob.html 20200418_0400</title>
-->
<script id="script_blobmain" type="text/javascript">
function log(msg) {
var textArea;
textArea = document.getElementById("logArea");
textArea.value = msg + "\n" + textArea.value;
}
function clearLog() {
var textArea;
textArea = document.getElementById("logArea");
textArea.value = "";
}
</script>
<!-- <script type="text/javascript" src="blobsallad.js"> </script> -->
<!-- <script type="text/javascript" src="blob.js"> </script> -->
<script id="script_blob">
function Vector(x, y) {
this.x = x;
this.y = y;
this.equal = function(v) {
return this.x == v.getX() && this.y == v.getY();
}
this.getX = function() {
return this.x;
}
this.getY = function() {
return this.y;
}
this.setX = function(x) {
this.x = x;
}
this.setY = function(y) {
this.y = y;
}
this.addX = function(x) {
this.x += x;
}
this.addY = function(y) { this.y += y; }
this.set = function(v) {
this.x = v.getX();
this.y = v.getY();
}
this.add = function(v) {
this.x += v.getX();
this.y += v.getY();
}
this.sub = function(v) {
this.x -= v.getX();
this.y -= v.getY();
}
this.dotProd = function(v) {
return this.x * v.getX() + this.y * v.getY();
}
this.length = function() {
return Math.sqrt(this.x * this.x + this.y * this.y);
}
this.scale = function(scaleFactor) {
this.x *= scaleFactor;
this.y *= scaleFactor;
}
this.toString = function() {
return " X: " + this.x + " Y: " + this.y;
}
}
function Environment(x, y, w, h) {
this.left = x;
this.right = x + w;
this.top = y;
this.buttom = y + h;
this.r = new Vector(0.0, 0.0);
this.collision = function(curPos, prevPos) {
var collide = false;
var i;
if(curPos.getX() < this.left) {
curPos.setX(this.left);
collide = true;
}
else if(curPos.getX() > this.right) {
curPos.setX(this.right);
collide = true;
}
if(curPos.getY() < this.top) {
curPos.setY(this.top);
collide = true;
}
else if(curPos.getY() > this.buttom)
{
curPos.setY(this.buttom);
collide = true;
}
return collide;
}
this.draw = function(ctx, scaleFactor)
{
}
}
function PointMass(cx, cy, mass)
{
this.cur = new Vector(cx, cy);
this.prev = new Vector(cx, cy);
this.mass = mass;
this.force = new Vector(0.0, 0.0);
this.result = new Vector(0.0, 0.0);
this.friction = 0.01;
this.getXPos = function()
{
return this.cur.getX();
}
this.getYPos = function()
{
return this.cur.getY();
}
this.getPos = function()
{
return this.cur;
}
this.getXPrevPos = function()
{
return this.prev.getX();
}
this.getYPrevPos = function()
{
return this.prev.getY();
}
this.getPrevPos = function()
{
return this.prev;
}
this.addXPos = function(dx)
{
this.cur.addX(dx);
}
this.addYPos = function(dy)
{
this.cur.addY(dy);
}
this.setForce = function(force)
{
this.force.set(force);
}
this.addForce = function(force)
{
this.force.add(force);
}
this.getMass = function()
{
return this.mass;
}
this.setMass = function(mass)
{
this.mass = mass;
}
this.move = function(dt) {
var t, a, c, dtdt;
dtdt = dt * dt;
a = this.force.getX() / this.mass;
c = this.cur.getX();
t = (2.0 - this.friction) * c - (1.0 - this.friction) * this.prev.getX() + a * dtdt;
this.prev.setX(c);
this.cur.setX(t);
a = this.force.getY() / this.mass;
c = this.cur.getY();
t = (2.0 - this.friction) * c - (1.0 - this.friction) * this.prev.getY() + a * dtdt;
this.prev.setY(c);
this.cur.setY(t);
}
this.setFriction = function(friction) {
this.friction = friction;
}
this.getVelocity = function() {
var cXpX, cYpY;
cXpX = this.cur.getX() - this.prev.getX();
cYpY = this.cur.getY() - this.prev.getY();
return cXpX * cXpX + cYpY * cYpY;
}
this.draw = function(ctx, scaleFactor) {
ctx.lineWidth = 2;
// ctx.fillStyle = '#000000';
// ctx.strokeStyle = '#000000';
ctx.fillStyle = 'white';
ctx.strokeStyle = 'black';
ctx.beginPath();
ctx.arc(this.cur.getX() * scaleFactor,
nthis.cur.getY() * scaleFactor,
4.0, 0.0, Math.PI * 2.0, true);
ctx.fill();
}
}
function ConstraintY(pointMass, y, shortConst, longConst) {
this.pointMass = pointMass;
this.y = y;
this.delta = new Vector(0.0, 0.0);
this.shortConst = shortConst;
this.longConst = longConst;
this.sc = function()
{
var dist;
dist = Math.abs(this.pointMass.getYPos() - this.y);
this.delta.setY(-dist);
if(this.shortConst != 0.0 && dist < this.shortConst)
{
var scaleFactor;
scaleFactor = this.shortConst / dist;
this.delta.scale(scaleFactor);
pointMass.getPos().sub(this.delta);
}
else if(this.longConst != 0.0 && dist > this.longConst)
{
var scaleFactor;
scaleFactor = this.longConst / dist;
this.delta.scale(scaleFactor);
pointMass.getPos().sub(this.delta);
}
}
}
function Joint(pointMassA, pointMassB, shortConst, longConst)
{
this.pointMassA = pointMassA;
this.pointMassB = pointMassB;
this.delta = new Vector(0.0, 0.0);
this.pointMassAPos = pointMassA.getPos();
this.pointMassBPos = pointMassB.getPos();
this.delta.set(this.pointMassBPos);
this.delta.sub(this.pointMassAPos);
this.shortConst = this.delta.length() * shortConst;
this.longConst = this.delta.length() * longConst;
this.scSquared = this.shortConst * this.shortConst;
this.lcSquared = this.longConst * this.longConst;
this.setDist = function(shortConst, longConst)
{
this.shortConst = shortConst;
this.longConst = longConst;
this.scSquared = this.shortConst * this.shortConst;
this.lcSquared = this.longConst * this.longConst;
}
this.scale = function(scaleFactor)
{
this.shortConst = this.shortConst * scaleFactor;
this.longConst = this.longConst * scaleFactor;
this.scSquared = this.shortConst * this.shortConst;
this.lcSquared = this.longConst * this.longConst;
}
this.sc = function()
{
this.delta.set(this.pointMassBPos);
this.delta.sub(this.pointMassAPos);
var dp = this.delta.dotProd(this.delta);
if(this.shortConst != 0.0 && dp < this.scSquared)
{
var scaleFactor;
scaleFactor = this.scSquared / (dp + this.scSquared) - 0.5;
this.delta.scale(scaleFactor);
this.pointMassAPos.sub(this.delta);
this.pointMassBPos.add(this.delta);
}
else if(this.longConst != 0.0 && dp > this.lcSquared)
{
var scaleFactor;
scaleFactor = this.lcSquared / (dp + this.lcSquared) - 0.5;
this.delta.scale(scaleFactor);
this.pointMassAPos.sub(this.delta);
this.pointMassBPos.add(this.delta);
}
}
}
function Stick(pointMassA, pointMassB)
{
function pointMassDist(pointMassA, pointMassB)
{
var aXbX, aYbY;
aXbX = pointMassA.getXPos() - pointMassB.getXPos();
aYbY = pointMassA.getYPos() - pointMassB.getYPos();
return Math.sqrt(aXbX * aXbX + aYbY * aYbY);
}
this.length = pointMassDist(pointMassA, pointMassB);
this.lengthSquared = this.length * this.length;
this.pointMassA = pointMassA;
this.pointMassB = pointMassB;
this.delta = new Vector(0.0, 0.0);
this.getPointMassA = function()
{
return this.pointMassA;
}
this.getPointMassB = function()
{
return this.pointMassB;
}
this.scale = function(scaleFactor)
{
this.length *= scaleFactor;
this.lengthSquared = this.length * this.length;
}
this.sc = function(env)
{
var dotProd, scaleFactor;
var pointMassAPos, pointMassBPos;
pointMassAPos = this.pointMassA.getPos();
pointMassBPos = this.pointMassB.getPos();
this.delta.set(pointMassBPos);
this.delta.sub(pointMassAPos);
dotProd = this.delta.dotProd(this.delta);
scaleFactor = this.lengthSquared / (dotProd + this.lengthSquared) - 0.5;
this.delta.scale(scaleFactor);
pointMassAPos.sub(this.delta);
pointMassBPos.add(this.delta);
}
this.setForce = function(force)
{
this.pointMassA.setForce(force);
this.pointMassB.setForce(force);
}
this.addForce = function(force)
{
this.pointMassA.addForce(force);
this.pointMassB.addForce(force);
}
this.move = function(dt)
{
this.pointMassA.move(dt);
this.pointMassB.move(dt);
}
this.draw = function(ctx, scaleFactor) {
this.pointMassA.draw(ctx, scaleFactor);
this.pointMassB.draw(ctx, scaleFactor);
ctx.lineWidth = 3;
// ctx.fillStyle = '#000000';
// ctx.strokeStyle = '#000000';
ctx.fillStyle = 'darkslategrey';
ctx.strokeStyle = 'linen';
ctx.beginPath();
ctx.moveTo(this.pointMassA.getXPos() * scaleFactor,
this.pointMassA.getYPos() * scaleFactor);
ctx.lineTo(this.pointMassB.getXPos() * scaleFactor,
this.pointMassB.getYPos() * scaleFactor);
ctx.stroke();
}
}
function Spring(restLength, stiffness, damper, pointMassA, pointMassB)
{
this.restLength = restLength;
this.stiffness = stiffness;
this.damper = damper;
this.pointMassA = pointMassA;
this.pointMassB = pointMassB;
this.tmp = Vector(0.0, 0.0);
this.sc = function(env)
{
env.collistion(this.pointMassA.getPos(), this.pointMassA.getPrevPos());
env.collistion(this.pointMassB.getPos(), this.pointMassB.getPrevPos());
}
this.move = function(dt)
{
var aXbX;
var aYbY;
var springForce;
var length;
aXbX = this.pointMassA.getXPos() - this.pointMassB.getXPos();
aYbY = this.pointMassA.getYPos() - this.pointMassB.getYPos();
length = Math.sqrt(aXbX * aXbX + aYbY * aYbY);
springForce = this.stiffness * (length / this.restLength - 1.0);
var avXbvX;
var avYbvY;
var damperForce;
avXbvX = this.pointMassA.getXVel() - this.pointMassB.getXVel();
avYbvY = this.pointMassA.getYVel() - this.pointMassB.getYVel();
damperForce = avXbvX * aXbX + avYbvY * aYbY;
damperForce *= this.damper;
var fx;
var fy;
fx = (springForce + damperForce) * aXbX;
fy = (springForce + damperForce) * aYbY;
this.tmp.setX(-fx);
this.tmp.setY(-ft);
this.pointMassA.addForce(this.tmp);
this.tmp.setX(fx);
this.tmp.setY(ft);
this.pointMassB.addForce(this.tmp);
this.pointMassA.move(dt);
this.pointMassB.move(dt);
}
this.addForce = function(force)
{
this.pointMassA.addForce(force);
this.pointMassB.addForce(force);
}
this.draw = function(ctx, scaleFactor) {
this.pointMassA.draw(ctx, scaleFactor);
this.pointMassB.draw(ctx, scaleFactor);
// ctx.fillStyle = '#000000';
// ctx.strokeStyle = '#000000';
ctx.fillStyle = 'red';
ctx.strokeStyle = 'blue';
ctx.beginPath();
ctx.moveTo(this.pointMassA.getXPos() * scaleFactor,
this.pointMassA.getYPos() * scaleFactor);
ctx.lineTo(this.pointMassB.getXPos() * scaleFactor,
this.pointMassB.getXPos() * scaleFactor);
ctx.stroke();
}
}
function Blob(x, y, radius, numPointMasses) {
this.x = x;
this.y = y;
// alert( "BUGS_480 x="+x+" y="+radius+" numpointmasses="+numPointMasses );
this.sticks = new Array();
this.pointMasses = new Array();
this.joints = new Array();
this.middlePointMass;
this.radius = radius;
this.drawFaceStyle = 1;
this.drawEyeStyle = 1;
this.selected = false;
numPointMasses = 8;
var f = 0.1;
var low = 0.95, high = 1.05;
var t, i, p;
function clampIndex(index, maxIndex) {
index += maxIndex;
return index % maxIndex;
}
for(i = 0, t = 0.0; i < numPointMasses; i++) {
this.pointMasses[i] = new PointMass(Math.cos(t) * radius + x, Math.sin(t) * radius + y, 1.0);
t += 2.0 * Math.PI / numPointMasses;
}
this.middlePointMass = new PointMass(x, y, 1.0);
this.pointMasses[0].setMass(4.0);
this.pointMasses[1].setMass(4.0);
for(i = 0; i < numPointMasses; i++)
{
this.sticks[i] = new Stick(this.pointMasses[i], this.pointMasses[clampIndex(i + 1, numPointMasses)]);
}
for(i = 0, p = 0; i < numPointMasses; i++)
{
this.joints[p++] = new Joint(this.pointMasses[i], this.pointMasses[clampIndex(i + numPointMasses / 2 + 1, numPointMasses)], low, high);
this.joints[p++] = new Joint(this.pointMasses[i], this.middlePointMass, high * 0.9, low * 1.1); // 0.8, 1.2 works
}
this.addBlob = function(blob)
{
var index = this.joints.length;
var dist;
this.joints[index] = new Joint(this.middlePointMass, blob.getMiddlePointMass(), 0.0, 0.0);
dist = this.radius + blob.getRadius();
this.joints[index].setDist(dist * 0.95, 0.0);
}
this.getMiddlePointMass = function()
{
return this.middlePointMass;
}
this.getRadius = function()
{
return this.radius;
}
this.getXPos = function()
{
return this.middlePointMass.getXPos();
}
this.getYPos = function()
{
return this.middlePointMass.getYPos();
}
this.scale = function(scaleFactor)
{
var i;
for(i = 0; i < this.joints.length; i++)
{
this.joints[i].scale(scaleFactor);
}
for(i = 0; i < this.sticks.length; i++)
{
this.sticks[i].scale(scaleFactor);
}
this.radius *= scaleFactor;
}
this.move = function(dt)
{
var i;
for(i = 0; i < this.pointMasses.length; i++)
{
this.pointMasses[i].move(dt);
}
this.middlePointMass.move(dt);
}
this.sc = function(env)
{
var i, j;
for(j = 0; j < 4; j++)
{
for(i = 0; i < this.pointMasses.length; i++)
{
if(env.collision(this.pointMasses[i].getPos(), this.pointMasses[i].getPrevPos()) == true)
{
this.pointMasses[i].setFriction(0.75);
}
else
{
this.pointMasses[i].setFriction(0.01);
}
}
for(i = 0; i < this.sticks.length; i++)
{
this.sticks[i].sc(env);
}
for(i = 0; i < this.joints.length; i++)
{
this.joints[i].sc();
}
}
}
this.setForce = function(force)
{
var i;
for(i = 0; i < this.pointMasses.length; i++)
{
this.pointMasses[i].setForce(force);
}
this.middlePointMass.setForce(force);
}
this.addForce = function(force)
{
var i;
for(i = 0; i < this.pointMasses.length; i++)
{
this.pointMasses[i].addForce(force);
}
this.middlePointMass.addForce(force);
this.pointMasses[0].addForce(force);
this.pointMasses[0].addForce(force);
this.pointMasses[0].addForce(force);
this.pointMasses[0].addForce(force);
}
this.moveTo = function(x, y)
{
var i, blobPos;
blobPos = this.middlePointMass.getPos();
x -= blobPos.getX(x);
y -= blobPos.getY(y);
for(i = 0; i < this.pointMasses.length; i++)
{
blobPos = this.pointMasses[i].getPos();
blobPos.addX(x);
blobPos.addY(y);
}
blobPos = this.middlePointMass.getPos();
blobPos.addX(x);
blobPos.addY(y);
}
this.setSelected = function(selected)
{
this.selected = selected;
}
this.drawEars = function(ctx, scaleFactor) {
ctx.strokeStyle = "#000000";
ctx.fillStyle = "#FFFFFF";
// ctx.strokeStyle = "#FFFFFF";
// ctx.fillStyle = "#000000";
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo((-0.55 * this.radius) * scaleFactor, (-0.35 * this.radius) * scaleFactor);
ctx.lineTo((-0.52 * this.radius) * scaleFactor, (-0.55 * this.radius) * scaleFactor);
ctx.lineTo((-0.45 * this.radius) * scaleFactor, (-0.40 * this.radius) * scaleFactor);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.moveTo((0.55 * this.radius) * scaleFactor, (-0.35 * this.radius) * scaleFactor);
ctx.lineTo((0.52 * this.radius) * scaleFactor, (-0.55 * this.radius) * scaleFactor);
ctx.lineTo((0.45 * this.radius) * scaleFactor, (-0.40 * this.radius) * scaleFactor);
ctx.fill();
ctx.stroke();
}
this.drawHappyEyes1 = function(ctx, scaleFactor) {
ctx.lineWidth = 1;
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.arc((-0.15 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor,
this.radius * 0.12 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.beginPath();
ctx.arc(( 0.15 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor,
this.radius * 0.12 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.fill();
ctx.stroke();
ctx.fillStyle = "#000000";
ctx.beginPath();
ctx.arc((-0.15 * this.radius) * scaleFactor,
(-0.17 * this.radius) * scaleFactor,
this.radius * 0.06 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.fill();
ctx.beginPath();
ctx.arc(( 0.15 * this.radius) * scaleFactor,
(-0.17 * this.radius) * scaleFactor,
this.radius * 0.06 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.fill();
}
this.drawHappyEyes2 = function(ctx, scaleFactor) {
ctx.lineWidth = 1;
ctx.fillStyle = "#FFFFFF";
ctx.beginPath();
ctx.arc((-0.15 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor,
this.radius * 0.12 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.stroke();
ctx.beginPath();
ctx.arc(( 0.15 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor,
this.radius * 0.12 * scaleFactor, 0, 2.0 * Math.PI, false);
ctx.stroke();
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo((-0.25 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor);
ctx.lineTo((-0.05 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(( 0.25 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor);
ctx.lineTo(( 0.05 * this.radius) * scaleFactor,
(-0.20 * this.radius) * scaleFactor);
ctx.stroke();
}
this.drawHappyFace1 = function(ctx, scaleFactor) {
ctx.lineWidth = 2;
// ctx.strokeStyle = "#000000";
// ctx.fillStyle = "#000000";
ctx.strokeStyle = "black";
ctx.fillStyle = "black";
ctx.beginPath();
ctx.arc(0.0, 0.0,
this.radius * 0.25 * scaleFactor, 0, Math.PI, false);
ctx.stroke();
}
this.drawHappyFace2 = function(ctx, scaleFactor) {
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000";
ctx.fillStyle = "#000000";
ctx.beginPath();
ctx.arc(0.0, 0.0,
this.radius * 0.25 * scaleFactor, 0, Math.PI, false);
ctx.fill();
}
this.drawOohFace = function(ctx, scaleFactor) {
ctx.lineWidth = 2;
ctx.strokeStyle = "#000000";
ctx.fillStyle = "#000000";
ctx.beginPath();
ctx.arc(0.0, (0.1 * this.radius) * scaleFactor,
this.radius * 0.25 * scaleFactor, 0, Math.PI, false);
ctx.fill();
ctx.beginPath();
ctx.moveTo((-0.25 * this.radius) * scaleFactor, (-0.3 * this.radius) * scaleFactor);
ctx.lineTo((-0.05 * this.radius) * scaleFactor, (-0.2 * this.radius) * scaleFactor);
ctx.lineTo((-0.25 * this.radius) * scaleFactor, (-0.1 * this.radius) * scaleFactor);
ctx.moveTo((0.25 * this.radius) * scaleFactor, (-0.3 * this.radius) * scaleFactor);
ctx.lineTo((0.05 * this.radius) * scaleFactor, (-0.2 * this.radius) * scaleFactor);
ctx.lineTo((0.25 * this.radius) * scaleFactor, (-0.1 * this.radius) * scaleFactor);
ctx.stroke();
}
this.drawFace = function(ctx, scaleFactor) {
if(this.drawFaceStyle == 1 && Math.random() < 0.05) {
this.drawFaceStyle = 2;
}
else if(this.drawFaceStyle == 2 && Math.random() < 0.1) {
this.drawFaceStyle = 1;
}
if(this.drawEyeStyle == 1 && Math.random() < 0.025) {
this.drawEyeStyle = 2;
}
else if(this.drawEyeStyle == 2 && Math.random() < 0.3) {
this.drawEyeStyle = 1;
}
if(this.middlePointMass.getVelocity() > 0.004)
{
this.drawOohFace(ctx, scaleFactor);
}
else
{
if(this.drawFaceStyle == 1)
{
this.drawHappyFace1(ctx, scaleFactor, 0.0, -0.3);
}
else
{
this.drawHappyFace2(ctx, scaleFactor, 0.0, -0.3);
}
if(this.drawEyeStyle == 1)
{
this.drawHappyEyes1(ctx, scaleFactor, 0.0, -0.3);
}
else
{
this.drawHappyEyes2(ctx, scaleFactor, 0.0, -0.3);
}
}
}
this.getPointMass = function(index)
{
index += this.pointMasses.length;
index = index % this.pointMasses.length;
return this.pointMasses[index];
}
this.drawBody = function(ctx, scaleFactor) {
var i;
var colors = `
black
white
red
white
blue
wheat
burlywood
linen
darkslategray
`.split("\n");
// var color = colors[random_int(0,colors.length-1)]
ctx.strokeStyle = "#000000";
// ctx.strokeStyle = "white";
// ctx.strokeStyle = "black`";
if(this.selected == true) {
// ctx.fillStyle = "#FFCCCC";
ctx.fillStyle = "red";
// ctx.fillStyle = color;
}
else {
// ctx.fillStyle = "#FFFFFF";
// ctx.fillStyle = "red";
ctx.fillStyle = "blue";
}
ctx.lineWidth = 5;
ctx.beginPath();
ctx.moveTo(this.pointMasses[0].getXPos() * scaleFactor,
this.pointMasses[0].getYPos() * scaleFactor);
for(i = 0; i < this.pointMasses.length; i++)
{
var px, py, nx, ny, tx, ty, cx, cy;
var prevPointMass, currentPointMass, nextPointMass, nextNextPointMass;
prevPointMass = this.getPointMass(i - 1);
currentPointMass = this.pointMasses[i];
nextPointMass = this.getPointMass(i + 1);
nextNextPointMass = this.getPointMass(i + 2);
tx = nextPointMass.getXPos();
ty = nextPointMass.getYPos();
cx = currentPointMass.getXPos();
cy = currentPointMass.getYPos();
px = cx * 0.5 + tx * 0.5;
py = cy * 0.5 + ty * 0.5;
nx = cx - prevPointMass.getXPos() + tx - nextNextPointMass.getXPos();
ny = cy - prevPointMass.getYPos() + ty - nextNextPointMass.getYPos();
px += nx * 0.16;
py += ny * 0.16;
px = px * scaleFactor;
py = py * scaleFactor;
tx = tx * scaleFactor;
ty = ty * scaleFactor;
ctx.bezierCurveTo(px, py, tx, ty, tx, ty);
}
ctx.closePath();
ctx.stroke();
ctx.fill();
}
this.drawSimpleBody = function(ctx, scaleFactor) {
for(i = 0; i < this.sticks.length; i++) {
this.sticks[i].draw(ctx, scaleFactor);
}
}
this.draw = function(ctx, scaleFactor) {
var i;
var up, ori, ang;
this.drawBody(ctx, scaleFactor);
ctx.strokeStyle = "#000000";
ctx.fillStyle = "#000000"
ctx.save();
ctx.translate(this.middlePointMass.getXPos() * scaleFactor,
(this.middlePointMass.getYPos() - 0.35 * this.radius) * scaleFactor);
up = new Vector(0.0, -1.0);
ori = new Vector(0.0, 0.0);
ori.set(this.pointMasses[0].getPos());
ori.sub(this.middlePointMass.getPos());
ang = Math.acos(ori.dotProd(up) / ori.length());
if(ori.getX() < 0.0) {
ctx.rotate(-ang);
}
else {
ctx.rotate(ang);
}
// this.drawEars(ctx, scaleFactor);
this.drawFace(ctx, scaleFactor);
ctx.restore();
}
}
function BlobCollective(x, y, startNum, maxNum) {
this.maxNum = maxNum;
this.numActive = 1;
this.blobs = new Array();
this.tmpForce = new Vector(0.0, 0.0);
this.selectedBlob = null;
this.blobs[0] = new Blob(x, y, 0.4, 8);
this.split = function() {
var i, maxIndex = 0, maxRadius = 0.0;
var emptySlot;
var motherBlob, newBlob;
if(this.numActive == this.maxNum) {
return;
}
emptySlot = this.blobs.length;
for(i = 0; i < this.blobs.length; i++) {
if(this.blobs[i] != null && this.blobs[i].getRadius() > maxRadius) {
maxRadius = this.blobs[i].getRadius();
motherBlob = this.blobs[i];
}
else if(this.blobs[i] == null) {
emptySlot = i;
}
}
motherBlob.scale(0.75);
newBlob = new Blob(motherBlob.getXPos(),
motherBlob.getYPos(), motherBlob.getRadius(), 8);
for(i = 0; i < this.blobs.length; i++) {
if(this.blobs[i] == null) {
continue;
}
this.blobs[i].addBlob(newBlob);
newBlob.addBlob(this.blobs[i]);
}
this.blobs[emptySlot] = newBlob;
this.numActive++;
}
this.findSmallest = function(exclude) {
var minRadius = 1000.0, minIndex;
var i;
for(i = 0; i < this.blobs.length; i++) {
if(i == exclude || this.blobs[i] == null) {
continue;
}
if(this.blobs[i].getRadius() < minRadius) {
minIndex = i;
minRadius = this.blobs[i].getRadius();
}
}
return minIndex;
}
this.findClosest = function(exclude) {
var minDist = 1000.0, foundIndex, dist, aXbX, aYbY;
var i;
var myPointMass, otherPointMass;
myPointMass = this.blobs[exclude].getMiddlePointMass();
for(i = 0; i < this.blobs.length; i++)
{
if(i == exclude || this.blobs[i] == null) {
continue;
}
otherPointMass = this.blobs[i].getMiddlePointMass();
aXbX = myPointMass.getXPos() - otherPointMass.getXPos();
aYbY = myPointMass.getYPos() - otherPointMass.getYPos();
dist = aXbX * aXbX + aYbY * aYbY;
if(dist < minDist)
{
minDist = dist;
foundIndex = i;
}
}
return foundIndex;
}
this.join = function()
{
var blob1Index, blob2Index, blob1, blob2;
var r1, r2, r3;
if(this.numActive == 1)
{
return;
}
blob1Index = this.findSmallest(-1);
blob2Index = this.findClosest(blob1Index);
r1 = this.blobs[blob1Index].getRadius();
r2 = this.blobs[blob2Index].getRadius();
r3 = Math.sqrt(r1 * r1 + r2 * r2);
this.blobs[blob1Index] = null;
this.blobs[blob2Index].scale(0.945 * r3 / r2);
this.numActive--;
}
this.selectBlob = function(x, y)
{
var i, minDist = 10000.0;
var otherPointMass;
var selectedBlob;
var selectOffset = null;
if(this.selectedBlob != null)
{
return;
}
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
otherPointMass = this.blobs[i].getMiddlePointMass();
aXbX = x - otherPointMass.getXPos();
aYbY = y - otherPointMass.getYPos();
dist = aXbX * aXbX + aYbY * aYbY;
if(dist < minDist)
{
minDist = dist;
if(dist < this.blobs[i].getRadius() * 0.5)
{
this.selectedBlob = this.blobs[i];
selectOffset = { x : aXbX, y : aYbY };
}
}
}
if(this.selectedBlob != null)
{
this.selectedBlob.setSelected(true);
}
return selectOffset;
}
this.unselectBlob = function()
{
if(this.selectedBlob == null)
{
return;
}
this.selectedBlob.setSelected(false);
this.selectedBlob = null;
}
this.selectedBlobMoveTo = function(x, y)
{
if(this.selectedBlob == null)
{
return;
}
this.selectedBlob.moveTo(x, y);
}
this.move = function(dt)
{
var i;
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
this.blobs[i].move(dt);
}
}
this.sc = function(env)
{
var i;
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
this.blobs[i].sc(env);
}
if(this.blobAnchor != null)
{
this.blobAnchor.sc();
}
}
this.setForce = function(force)
{
var i;
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
if(this.blobs[i] == this.selectedBlob)
{
this.blobs[i].setForce(new Vector(0.0, 0.0));
continue;
}
this.blobs[i].setForce(force);
}
}
this.addForce = function(force)
{
var i;
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
if(this.blobs[i] == this.selectedBlob)
{
continue;
}
this.tmpForce.setX(force.getX() * (Math.random() * 0.75 + 0.25));
this.tmpForce.setY(force.getY() * (Math.random() * 0.75 + 0.25));
this.blobs[i].addForce(this.tmpForce);
}
}
this.draw = function(ctx, scaleFactor)
{
var i;
for(i = 0; i < this.blobs.length; i++)
{
if(this.blobs[i] == null)
{
continue;
}
this.blobs[i].draw(ctx, scaleFactor);
}
}
}
function random_int(max,min) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
function debug(msg, okFunc, cancelFunc)
{
if(confirm(msg) == true && okFunc != null)
{
okFunc();
}
else if(cancelFunc != null)
{
cancelFunc();
}
}
var env;
var width = 600.0;
var height = 400.0;
var scaleFactor = 200.0;
var blobColl;
var gravity;
var stopped;
var savedMouseCoords = null;
var selectOffset = null;
function update()
{
var dt = 0.05;
if(savedMouseCoords != null && selectOffset != null)
{
blobColl.selectedBlobMoveTo(savedMouseCoords.x - selectOffset.x,
savedMouseCoords.y - selectOffset.y);
}
blobColl.move(dt);
blobColl.sc(env);
blobColl.setForce(gravity);
}
function draw() {
// var canvas = document.getElementById('blob');
var canvas = document.getElementById('canvas_blob');
if(canvas.getContext == null) {return; }
var ctx = canvas.getContext('2d');
ctx.clearRect(0, 0, width, height);
env.draw(ctx, scaleFactor);
blobColl.draw(ctx, scaleFactor);
}
function timeout() {
draw();
update();
if(stopped == false) {
setTimeout('timeout()', 30);
}
}
function init() {
// var canvas = document.getElementById('blob');
var canvas = document.getElementById('canvas_blob');
if(canvas.getContext == null) {
alert("ALERT_100 unauthorized access logged");
return;
}
document.onkeydown = function(event) {
var keyCode;
// alert( "BUGS_701 document.onkeydown event="+event );
if(event == null) {
keyCode = window.event.keyCode;
}
else {
keyCode = event.keyCode;
}
if( keypress(event)){ return; }
// alert( "BUGS_701 document.onkeydown keypress event="+event );
// if( event.which === 89 && event.ctrlKey ) {
// if( keyCode === 89 && event.ctrlKey ) {
// alert('MSG_89-ctrl-y control + y');
// }
// else if( keyCode === 90 && event.ctrlKey ) {
// alert('MSG_90-ctrl-z control + z');
// }
switch(keyCode) {
// esc
case 27: alert( "MSG_027 esc keycode="+keyCode ); break;
// slash
case 191: alert( "MSG_191 slash keycode="+keyCode ); break;
// colon
// hat
// dollar
// plus
// minus
case 59: alert( "MSG_191 colon keycode="+keyCode ); break;
case 54: alert( "MSG_54 hat keycode="+keyCode ); break;
case 52: alert( "MSG_191 dollar keycode="+keyCode ); break;
case 107: alert( "MSG_107 plus keycode="+keyCode ); break;
case 109: alert( "MSG_109 minus keycode="+keyCode ); break;
// shift
// control
// winkey
// alt
// tab
// caps
// space
// enter
// case 16: alert( "MSG_16 shift keycode="+keyCode ); break;
// case 17: alert( "MSG_17 control keycode="+keyCode ); break;
case 224: alert( "MSG_224 meta keycode="+keyCode ); break;
case 18: alert( "MSG_18 alt keycode="+keyCode ); break;
case 9: alert( "MSG_9 tab keycode="+keyCode ); break;
case 20: alert( "MSG_191 caps keycode="+keyCode ); break;
case 32: alert( "MSG_32 space keycode="+keyCode ); break;
case 13: alert( "MSG_13 enter keycode="+keyCode ); break;
// 0
// 9
case 48: alert( "MSG_48 0 keycode="+keyCode ); break;
case 49: alert( "MSG_49 1 keycode="+keyCode ); break;
case 50: alert( "MSG_50 2 keycode="+keyCode ); break;
case 51: alert( "MSG_51 3 keycode="+keyCode ); break;
case 52: alert( "MSG_52 4 keycode="+keyCode ); break;
case 53: alert( "MSG_53 5 keycode="+keyCode ); break;
case 54: alert( "MSG_54 6 keycode="+keyCode ); break;
case 55: alert( "MSG_55 7 keycode="+keyCode ); break;
case 56: alert( "MSG_56 8 keycode="+keyCode ); break;
case 57: alert( "MSG_57 9 keycode="+keyCode ); break;
// backtick
// backslash
// tick
// qoute
// case 57: alert( "MSG_57 quote keycode="+keyCode ); break;
// question
case 192: alert( "MSG_192 backtick keycode="+keyCode ); break;
case 220: alert( "MSG_220 backslash keycode="+keyCode ); break;
case 222: alert( "MSG_222 tick keycode="+keyCode ); break;
case 191: alert( "MSG_57 question keycode="+keyCode ); break;
// left
case 37:
blobColl.addForce(new Vector(-50.0, 0.0));
break;
// up
case 38:
blobColl.addForce(new Vector(0.0, -50.0));
break;
// right
case 39:
blobColl.addForce(new Vector(50.0, 0.0));
break;
// down
case 40:
blobColl.addForce(new Vector(0.0, 50.0));
break;
// join 'j'
case 74:
blobColl.join();
break;
// split 'h'
case 72:
blobColl.split();
break;
// toggle gravity 'g'
case 71:
toggleGravity();
break;
default:
break;
}
}
function getMouseCoords(event)
{
if(event == null)
{
event = window.event;
}
if(event == null)
{
return null;
}
if(event.pageX || event.pageY){
return {x:event.pageX / scaleFactor, y:event.pageY / scaleFactor};
}
return null;
}
document.onmousedown = function(event)
{
var mouseCoords;
if(stopped == true)
{
return;
}
mouseCoords = getMouseCoords(event);
if(mouseCoords == null)
{
return;
}
selectOffset = blobColl.selectBlob(mouseCoords.x, mouseCoords.y);
}
document.onmouseup = function(event)
{
blobColl.unselectBlob();
savedMouseCoords = null;
selectOffset = null;
}
document.onmousemove = function(event)
{
var mouseCoords;
if(stopped == true)
{
return;
}
if(selectOffset == null)
{
return;
}
mouseCoords = getMouseCoords(event);
if(mouseCoords == null)
{
return;
}
blobColl.selectedBlobMoveTo(mouseCoords.x - selectOffset.x, mouseCoords.y - selectOffset.y);
savedMouseCoords = mouseCoords;
}
env = new Environment(0.2, 0.2, 2.6, 1.6);
blobColl = new BlobCollective(1.0, 1.0, 1, 200);
gravity = new Vector(0.0, 10.0);
stopped = false;
timeout();
}
function stop()
{
stopped = true;
}
function start()
{
stopped = false;
timeout();
}
function toggleGravity() {
if(gravity.getY() > 0.0) {
gravity.setY(0.0);
}
else {
gravity.setY(10.0);
}
}
</script>
<script id="script_keypress" >
function keypress(e) {
// Ensure event is not null
e = e || window.event;
if ((e.which == 90 || e.keyCode == 90) && e.ctrlKey) {alert( "MSG_090 keypress ctrl-z" );
return('ctrl-z');
}
if ((e.which == 89 || e.keyCode == 89) && e.ctrlKey) {alert( "MSG_089 keypress ctrl-y" );
return('ctrl-y');
}
if ((e.which == 54 || e.keyCode == 54) && e.ctrlKey) {
alert( "MSG_054 keypress ctrl-hat" );
return('ctrl-hat');
}
if ((e.which == 54 || e.keyCode == 54) && e.shiftKey) {
alert( "MSG_054 keypress shift-hat" );
return('shift-hat');
}
if ((e.which == 60 || e.keyCode == 60) && e.shiftKey) {
alert( "MSG_090 keypress dollar shift-4" );
}
// case 59: alert( "MSG_191 colon keycode="+keyCode ); break;
// case 54: alert( "MSG_54 hat keycode="+keyCode ); break;
// case 52: alert( "MSG_191 dollar keycode="+keyCode ); break;
// case 107: alert( "MSG_107 plus keycode="+keyCode ); break;
// case 109: alert( "MSG_109 minus keycode="+keyCode ); break;
}
</script>
<script id="script_trigger" >
// A handler called preventDefault.
// None of the handlers called preventDefault.
function trigger_mouse(args) {
alert( "BUGS_901 trigger _mouse args="+args );
var event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
if(document.getElementById('checkbox')) {
var cb = document.getElementById('checkbox');
var cancelled = !cb.dispatchEvent(event);
if (cancelled) {alert("cancelled");}
else {alert("not cancelled");}
}
}
</script>
<style type="text/css">
canvas { }
</style>
<script id="script_startup_blob">
function startup_blob(args) {
init();
return('');
}
</script>
<script id="script_trigger" >
function trigger(key) {
// alert( "BUGS_801 trigger key="+key );
var trigger_char = "Q";
var trigger_key = "q";
var trigger_keycode = "81";
if( key == 'h') { blobColl.split(); return(''); }
if( key == 'g') { toggleGravity(); return(''); }
if( key == 'j') { blobColl.join(); return(''); }
if( key == '<') { blobColl.move(); return(''); }
if( key == '>') { blobColl.move(); return(''); }
if( key == 'q') { trigger_char="Q"; trigger_key="q"; trigger_keycode="81"; }
if( key == 'h') { trigger_char="H"; trigger_key="h"; trigger_keycode="72"; }
if( key == 'j') { trigger_char="J"; trigger_key="j"; trigger_keycode="74"; }
if( key == 'g') { trigger_char="G"; trigger_key="g"; trigger_keycode="71"; }
// alert( "BUGS_802 triger key="+key+" trigger_char="+trigger_char+" keycode="+trigger_keycode );
// char : "Q",
// key : "q",
// keyCode : 81
//// var e = new KeyboardEvent("keydown", {
var e = new KeyboardEvent("keyPress", {
bubbles : true,
cancelable : true,
key : trigger_key,
char : trigger_char,
shiftKey : true,
keyCode : trigger_keycode
});
alert( "BUGS_803 trigger key="+key );
}
function simulateKeyEvent(character) {
var evt = document.createEvent("KeyboardEvent");
(evt.initKeyEvent || evt.initKeyboardEvent)("keypress", true, true, window,
0, 0, 0, 0,
0, character.charCodeAt(0))
var canceled = !body.dispatchEvent(evt);
// A handler called preventDefault
// None of the handlers called preventDefault
if(canceled) {
alert("canceled");
}
else {
alert("not canceled");
}
}
function simulateKeyPress(character) {
jQuery.event.trigger({ type : 'keypress', which : character.charCodeAt(0) });
}
</script>
<script id="script_replace_key" type="text/javascript">
function replace(e) {
if (e.keyCode==13) e.keyCode=9
}
</script>
</head>
<!-- <body bgcolor=wheat onload="init();"> -->
<body bgcolor=wheat onload="startup_blob();return false;">
<div id="div_blob">
<h3>blobsallad</h3>
<hr color=white>
<canvas id="canvas_blob" width="600" height="400"></canvas><br>
<hr color=white>
<!--
<a href="javascript:stop()">-= stop =- </a>
<a href="javascript:start()">-= start =- </a>
-->
<!--
<img src="/imgs/btn/koeye.png" onclick="trigger('h');return false;" height=30>
<img src="/imgs/btn/koeye.png" onclick="trigger('g');return false;" height=30>
<img src="/imgs/btn/koeye.png" onclick="trigger('j');return false;" height=30>
-->
<!-- <img src="/imgs/btn/koeye.png" onclick="trigger('');return false;" height=30> -->
<img src="/imgs/btn/koeyeb.png" onclick="stop();return false;" height=30>
<img src="/imgs/btn/koeyew.png" onclick="start();return false;" height=30>
-= start =- -= stop =-
<br>
<hr color=whtie>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.split();return false;" height=30>
<img src="/imgs/btn/koeyeb.png" onclick="toggleGravity();return false;" height=30>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.join();return false;" height=30>
-= + =- -= = =- -= - =-
<hr color=whtie>
<br>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.addForce( new Vector(-50.0,0.0));return false;" height=30>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.addForce( new Vector(0.0,-50.0));return false;" height=30>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.addForce( new Vector(0.0,50.0));return false;" height=30>
<img src="/imgs/btn/koeyeb.png" onclick="blobColl.addForce( new Vector(50.0,0.0));return false;" height=30>
-= l =- -= u =- -= d =- -= r =-
<hr color=whtie>
<br>
<!--
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent('h'); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent('g); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent('j); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent('h'); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent(character); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent(character); return false;" height=20>
<img src="/imgs/btn/koeyew.png" onclick="simulateKeyEvent(character); return false; height=20>
-->
<!--
<hr color=white>
<h3>-= h =- -= g =- -= j =-</h3>
<hr color=white>
-->
</div>
<form id="form_replace" >
<input onkeydown="replace(event)" /><br /> <input />
</form>
<script id="script_dispatch">
function dispatch(args) {
document.addEventListener ('keydown', function (event) {
console.log (event.which);
});
var evt = new KeyboardEvent('keydown', {'keyCode':65, 'which':65};
document.dispatchEvent (evt);
}
</script>
</body>
</head>
//
koh5_pano
Drag mouse to navigate.
Navigation
- Left/Right Mouse drag: Changes camera heading.
- Up/Sown Mouse drag: Changes camera pitch.
- Scroll wheel: Changes camera field of view.
- I-Key: Displays Info panel with canvas size, image size and FPS.
17.Aug.2010, Martin Wengenmayer