2016-11-29 23:55:31 +01:00
|
|
|
class Vector2 {
|
2016-11-30 11:52:10 +01:00
|
|
|
constructor(vec, y) {
|
|
|
|
if(typeof vec === "undefined" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
this.x = 0;
|
|
|
|
this.y = 0;
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
this.x = vec;
|
|
|
|
this.y = vec;
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "number") {
|
|
|
|
this.x = vec;
|
|
|
|
this.y = y;
|
|
|
|
} else if(typeof vec === "object" && vec.constructor == Vector2) {
|
|
|
|
this.x = vec.getX()
|
|
|
|
this.y = vec.getY();
|
|
|
|
} else
|
|
|
|
throw 'Vector2::constructor(): Invalid types ' + (typeof vec) + ' ' + (typeof y);
|
|
|
|
}
|
|
|
|
|
|
|
|
getX() {
|
|
|
|
return this.x;
|
|
|
|
}
|
|
|
|
|
|
|
|
getY() {
|
|
|
|
return this.y;
|
|
|
|
}
|
|
|
|
|
|
|
|
setX(x) {
|
|
|
|
if(typeof x !== "number")
|
|
|
|
throw 'Vector2::setX(): Invalid type ' + (typeof x);
|
|
|
|
|
|
|
|
this.x = x;
|
|
|
|
}
|
|
|
|
|
|
|
|
setY(y) {
|
|
|
|
if(typeof y !== "number")
|
|
|
|
throw 'Vector2::setY(): Invalid type ' + (typeof y);
|
|
|
|
|
|
|
|
this.y = y;
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
add(vec, y) {
|
|
|
|
if(typeof vec === "number" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x + vec,
|
|
|
|
this.y + vec
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "number") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x + vec,
|
|
|
|
this.y + y
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "object" && vec.constructor == Vector2) {
|
|
|
|
return new Vector2(
|
|
|
|
this.x + vec.getX(),
|
|
|
|
this.y + vec.getY()
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
throw 'Vector2::add(): Invalid types ' + (typeof vec) + ' ' + (typeof y);
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
sub(vec, y) {
|
|
|
|
if(typeof vec === "number" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x - vec,
|
|
|
|
this.y - vec
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "number") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x - vec,
|
|
|
|
this.y - y
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "object" && vec.constructor == Vector2) {
|
|
|
|
return new Vector2(
|
|
|
|
this.x - vec.getX(),
|
|
|
|
this.y - vec.getY()
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
throw 'Vector2::sub(): Invalid types ' + (typeof vec) + ' ' + (typeof y);
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
mul(vec, y) {
|
|
|
|
if(typeof vec === "number" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x * vec,
|
|
|
|
this.y * vec
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "number") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x * vec,
|
|
|
|
this.y * y
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "object" && vec.constructor == Vector2) {
|
|
|
|
return new Vector2(
|
|
|
|
this.x * vec.getX(),
|
|
|
|
this.y * vec.getY()
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
throw 'Vector2::mul(): Invalid types ' + (typeof vec) + ' ' + (typeof y);
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
div(vec, y) {
|
|
|
|
if(typeof vec === "number" &&
|
|
|
|
typeof y === "undefined") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x / vec,
|
|
|
|
this.y / vec
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "number" &&
|
|
|
|
typeof y === "number") {
|
|
|
|
return new Vector2(
|
|
|
|
this.x / vec,
|
|
|
|
this.y / y
|
|
|
|
);
|
|
|
|
} else if(typeof vec === "object" && vec.constructor == Vector2) {
|
|
|
|
return new Vector2(
|
|
|
|
this.x / vec.getX(),
|
|
|
|
this.y / vec.getY()
|
|
|
|
);
|
|
|
|
} else
|
|
|
|
throw 'Vector2::div(): Invalid types ' + (typeof vec) + ' ' + (typeof y);
|
|
|
|
}
|
|
|
|
|
|
|
|
length() {
|
|
|
|
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
$(document).ready(function($) {
|
2016-11-30 11:52:10 +01:00
|
|
|
var entities = [];
|
2016-11-30 12:09:26 +01:00
|
|
|
|
|
|
|
var entityId = 0;
|
2016-11-30 11:52:10 +01:00
|
|
|
|
|
|
|
class Entity {
|
|
|
|
constructor() {
|
2016-11-30 12:09:26 +01:00
|
|
|
var entity = this;
|
|
|
|
this.id = entityId++;
|
2016-11-30 11:52:10 +01:00
|
|
|
this.position = new Vector2();
|
|
|
|
this.speed = new Vector2();
|
2016-11-30 12:09:26 +01:00
|
|
|
this.elem = $('<div>').addClass('point').appendTo('body');
|
|
|
|
this.row = $('<tr>').appendTo('#table_entities');
|
|
|
|
this.columns = {
|
|
|
|
id: $('<td>').text(this.id).appendTo(this.row),
|
|
|
|
position: $('<td>').appendTo(this.row),
|
|
|
|
speed: $('<td>').appendTo(this.row),
|
|
|
|
color: $('<td>').appendTo(this.row),
|
|
|
|
actions: $('<td>').appendTo(this.row),
|
|
|
|
}
|
2016-12-01 09:29:57 +01:00
|
|
|
this.colorPicker = $('<input />')
|
2016-11-30 12:09:26 +01:00
|
|
|
.attr('type', 'color')
|
|
|
|
.change(function(){
|
|
|
|
entity.elem.css('background-color', $(this).val());
|
|
|
|
})
|
|
|
|
.appendTo(this.columns.color)
|
|
|
|
.change();
|
|
|
|
$('<button>')
|
|
|
|
.addClass('btn btn-xs btn-danger')
|
|
|
|
.text(' Löschen')
|
|
|
|
.prepend($('<i>').addClass('glyphicon glyphicon-trash'))
|
|
|
|
.appendTo(this.columns.actions)
|
|
|
|
.click(function(){
|
|
|
|
entity.elem.remove();
|
|
|
|
entity.row.remove();
|
|
|
|
|
|
|
|
var index = entities.indexOf(entity);
|
|
|
|
if (index > -1) {
|
|
|
|
entities.splice(index, 1);
|
|
|
|
}
|
|
|
|
});
|
2016-11-30 11:52:10 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
$('#button_add').click(function(){
|
|
|
|
entities.push(new Entity());
|
|
|
|
});
|
2016-12-01 09:29:57 +01:00
|
|
|
|
|
|
|
$('#button_rainbow').click(function(){
|
|
|
|
var generateColors = function(count) {
|
|
|
|
var generateColor = function(position) {
|
|
|
|
var makeCode = function(r, g, b) {
|
|
|
|
return '#' +
|
2016-12-01 21:44:41 +01:00
|
|
|
(r < 16 ? '0' : '') + parseInt(r).toString(16) +
|
|
|
|
(g < 16 ? '0' : '') + parseInt(g).toString(16) +
|
|
|
|
(b < 16 ? '0' : '') + parseInt(b).toString(16);
|
2016-12-01 09:29:57 +01:00
|
|
|
}
|
|
|
|
|
2016-12-01 21:44:41 +01:00
|
|
|
if(position >= 0 && position < 256) return makeCode(255, position, 0);
|
|
|
|
else if(position >= 256 && position < 512) return makeCode(255 - (position - 256), 255, 0);
|
|
|
|
else if(position >= 512 && position < 768) return makeCode(0, 255, position - 512);
|
|
|
|
else if(position >= 768 && position < 1024) return makeCode(0, 255 - (position - 768), 255);
|
|
|
|
else if(position >= 1024 && position < 1280) return makeCode(position - 1024, 0, 255);
|
|
|
|
else if(position >= 1280 && position < 1536) return makeCode(255, 0, 255 - (position - 1280));
|
2016-12-01 09:29:57 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
var colors = [];
|
|
|
|
for(var position = 0; position <= 1535; position += (1536 / count))
|
|
|
|
colors.push(generateColor(position));
|
|
|
|
return colors;
|
|
|
|
};
|
|
|
|
|
|
|
|
var colors = generateColors(entities.length);
|
|
|
|
for(var i = 0; i < entities.length; i++) {
|
|
|
|
entities[i].elem.css('background-color', colors[i]);
|
|
|
|
entities[i].colorPicker.val(colors[i]);
|
|
|
|
}
|
|
|
|
});
|
2016-11-30 11:52:10 +01:00
|
|
|
|
|
|
|
for (var i = 0; i < 8; i++) {
|
|
|
|
$('#button_add').click();
|
|
|
|
}
|
|
|
|
|
|
|
|
var mousePosition = new Vector2;
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
$(document).mousemove(function(event) {
|
|
|
|
mousePosition = new Vector2(
|
|
|
|
event.pageX,
|
|
|
|
event.pageY
|
|
|
|
);
|
|
|
|
});
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
setInterval(function() {
|
|
|
|
var DELTAT = parseFloat($('#input_deltat').val());
|
|
|
|
var SEGLEN = parseFloat($('#input_seglen').val());
|
|
|
|
var SPRINGK = parseFloat($('#input_springk').val());
|
|
|
|
var MASS = parseFloat($('#input_mass').val());
|
|
|
|
var GRAVITY = parseFloat($('#input_gravity').val());
|
|
|
|
var RESISTANCE = parseFloat($('#input_resistance').val());
|
|
|
|
var STOPVEL = parseFloat($('#input_stopvel').val());
|
|
|
|
var STOPACC = parseFloat($('#input_stopacc').val());
|
|
|
|
var BOUNCE = parseFloat($('#input_bounce').val());
|
|
|
|
|
|
|
|
var collisionUp = $('#input_collisionUp').is(':checked');
|
|
|
|
var collisionLeft = $('#input_collisionLeft').is(':checked');
|
|
|
|
var collisionRight = $('#input_collisionRight').is(':checked');
|
|
|
|
var collisionDown = $('#input_collisionDown').is(':checked');
|
|
|
|
|
|
|
|
$('#display_deltat').text(DELTAT);
|
|
|
|
$('#display_seglen').text(SEGLEN);
|
|
|
|
$('#display_springk').text(SPRINGK);
|
|
|
|
$('#display_mass').text(MASS);
|
|
|
|
$('#display_gravity').text(GRAVITY);
|
|
|
|
$('#display_resistance').text(RESISTANCE);
|
|
|
|
$('#display_stopvel').text(STOPVEL);
|
|
|
|
$('#display_stopacc').text(STOPACC);
|
|
|
|
$('#display_bounce').text(BOUNCE);
|
2016-11-30 00:16:13 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
var windowSize = new Vector2($(window).width(), $(window).height());
|
|
|
|
|
|
|
|
$.each(entities, function(i, entity){
|
|
|
|
var springForce = function(i, j) {
|
|
|
|
var d = i.sub(j);
|
|
|
|
var len = d.length();
|
|
|
|
return len > SEGLEN ? d.div(len).mul(SPRINGK).mul(len - SEGLEN) : new Vector2();
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
var spring = springForce(i > 0 ? entities[i - 1].position : mousePosition, entity.position);
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if (i < (entities.length - 1)) {
|
|
|
|
spring = spring.add(springForce(entities[i + 1].position, entity.position));
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
var resist = entity.speed.mul(-RESISTANCE);
|
|
|
|
var accel = spring.add(resist).div(MASS).add(0, GRAVITY);
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
entity.speed = entity.speed.add(accel.mul(DELTAT));
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if (Math.abs(entity.speed.getX()) < STOPVEL &&
|
|
|
|
Math.abs(entity.speed.getY()) < STOPVEL &&
|
|
|
|
Math.abs(accel.getX()) < STOPACC &&
|
|
|
|
Math.abs(accel.getY()) < STOPACC) {
|
|
|
|
entity.speed = new Vector2();
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
entity.position = entity.position.add(entity.speed);
|
2016-11-30 00:16:13 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if(collisionLeft) {
|
|
|
|
if (entity.position.getX() < 0) {
|
|
|
|
if (entity.speed.getX() < 0) {
|
|
|
|
entity.speed.setX(BOUNCE * -entity.speed.getX());
|
|
|
|
}
|
|
|
|
entity.position.setX(0);
|
|
|
|
}
|
|
|
|
}
|
2016-11-30 11:20:46 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if(collisionUp) {
|
|
|
|
if (entity.position.getY() < 0) {
|
|
|
|
if (entity.speed.getY() < 0) {
|
|
|
|
entity.speed.setY(BOUNCE * -entity.speed.getY());
|
|
|
|
}
|
|
|
|
entity.position.setY(0);
|
|
|
|
}
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if(collisionRight) {
|
|
|
|
if (entity.position.getX() >= windowSize.getX() - entity.elem.width()) {
|
|
|
|
if (entity.speed.getX() > 0) {
|
|
|
|
entity.speed.setX(BOUNCE * -entity.speed.getX());
|
|
|
|
}
|
|
|
|
entity.position.setX(windowSize.getX() - entity.elem.width());
|
|
|
|
}
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
if(collisionDown) {
|
|
|
|
if (entity.position.getY() >= windowSize.getY() - entity.elem.height()) {
|
|
|
|
if (entity.speed.getY() > 0) {
|
|
|
|
entity.speed.setY(BOUNCE * -entity.speed.getY());
|
|
|
|
}
|
|
|
|
entity.position.setY(windowSize.getY() - entity.elem.height());
|
|
|
|
}
|
|
|
|
}
|
2016-11-29 23:55:31 +01:00
|
|
|
|
2016-11-30 11:52:10 +01:00
|
|
|
entity.elem.css({
|
|
|
|
'left': entity.position.getX(),
|
|
|
|
'top': entity.position.getY()
|
|
|
|
});
|
2016-11-30 12:09:26 +01:00
|
|
|
entity.columns.position.text(Math.round(entity.position.getX()) + ', ' + Math.round(entity.position.getY()));
|
|
|
|
entity.columns.speed.text(Math.round(entity.speed.getX()) + ', ' + Math.round(entity.speed.getY()));
|
2016-11-30 11:52:10 +01:00
|
|
|
});
|
|
|
|
}, 20);
|
2016-11-29 23:55:31 +01:00
|
|
|
});
|