class Dot extends Phaser.Geom.Point {
constructor(scene, x, y, vx, vy) {
super(x, y);
this.scene = scene;
this.pos = new Phaser.Math.Vector2(x, y);
this.oldpos = new Phaser.Math.Vector2(x + (vx||0), y + (vy||0)); // velocity x, y
this.friction = 0.97;
this.groundFriction = 0.7;
this.gravity = new Phaser.Math.Vector2(0, 1);
this.radius = 5;
this.color = '0xe62a4f';
this.mass = 1;
}
update() {
let vel = this.pos.clone().subtract(this.oldpos);
vel.scale(this.friction);
// if the point touches the ground set groundFriction
if (this.pos.y >= CANVAS_HEIGHT - this.radius && vel.lengthSq() > 0.000001) {
var m = vel.length();
vel.x /= m;
vel.y /= m;
vel.scale(m * this.groundFriction);
}
this.oldpos.set(this.pos.x, this.pos.y);
this.pos.add(vel);
this.pos.add(this.gravity);
}
constrain() {
if (this.pos.x > CANVAS_WIDTH - this.radius) {
this.pos.x = CANVAS_WIDTH - this.radius;
}
if (this.pos.x < this.radius) {
this.pos.x = this.radius;
}
if (this.pos.y > CANVAS_HEIGHT - this.radius) {
this.pos.y = CANVAS_HEIGHT - this.radius;
}
if (this.pos.y < this.radius) {
this.pos.y = this.radius;
}
};
render() {
this.graphics.fillStyle(this.color);
this.graphics.fillCircle(this.pos.x, this.pos.y, this.radius)
}
}
class Stick {
constructor(scene, p1, p2, length) {
this.scene = scene;
this.startPoint = p1;
this.endPoint = p2;
this.stiffness = 2;
this.color = '#f5476a';
// if the length is not given then calculate the distance based on position
if (!length) {
this.length = Phaser.Math.Distance.BetweenPoints(this.startPoint.pos, this.endPoint.pos);
} else {
this.length = length;
}
}
update() {
// calculate the distance between two dots
let dx = this.endPoint.pos.x - this.startPoint.pos.x;
let dy = this.endPoint.pos.y - this.startPoint.pos.y;
// pythagoras theorem
let dist = Math.sqrt(dx dx + dy dy);
// calculate the resting distance betwen the dots
let diff = (this.length - dist) / dist * this.stiffness;
// getting the offset of the points
let offsetx = dx diff 0.5;
let offsety = dy diff 0.5;
// calculate mass
let m1 = this.startPoint.mass + this.endPoint.mass;
let m2 = this.startPoint.mass / m1;
m1 = this.endPoint.mass / m1;
// and finally apply the offset with calculated mass
if (!this.startPoint.pinned) {
this.startPoint.pos.x -= offsetx * m1;
this.startPoint.pos.y -= offsety * m1;
}
if (!this.endPoint.pinned) {
this.endPoint.pos.x += offsetx * m2;
this.endPoint.pos.y += offsety * m2;
}
}
render() {
this.graphics.lineStyle(1,this.color).lineBetween(this.startPoint.pos.x, this.startPoint.pos.y, this.endPoint.pos.x, this.endPoint.pos.y);
}
}
class Game extends Phaser.Scene {
constructor() {
super({key: "Game"});
this.dots = [];
this.sticks = [];
this.ITERATION = 100;
}
create() {
// forming a BOX
this.dots.push(new Dot(this, 100, 100, (Math.random() - 0.5) * 100.0)); // x, y, vx, vy
this.dots.push(new Dot(this, 200, 100));
this.dots.push(new Dot(this, 200, 200));
this.dots.push(new Dot(this, 100, 200));
// sticks
this.sticks.push(new Stick(this, this.dots[0], this.dots[1]))
this.sticks.push(new Stick(this, this.dots[1], this.dots[2]))
this.sticks.push(new Stick(this, this.dots[2], this.dots[3]))
this.sticks.push(new Stick(this, this.dots[3], this.dots[0]))
this.sticks.push(new Stick(this, this.dots[3], this.dots[1]))
}
update(t, dt) {
this.graphics.clear()
// update
for (let i = 0; i < this.ITERATION; i++) {
for (let d of this.dots) {
d.constrain();
}
for (let s of this.sticks) {
s.update();
}
}
for (let d of this.dots) {
d.update();
d.render();
}
for (let s of this.sticks) {
s.update();
s.render();
}
}
}
Useful References
Comments