Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
import { observable, computed, action } from 'mobx';
import { range } from 'd3-array';
import { timer } from 'd3-timer';
import { quadtree } from 'd3-quadtree';
class Physics {
@observable MarbleR = 25;
@observable width = 800;
@observable height = 600;
@observable marbles = [];
timer = null;
@computed get initialPositions() {
const { width, height, MarbleR } = this,
center = width/2;
const lines = 4,
maxY = 200;
let marbles = range(lines, 0, -1).map(y => {
if (y === lines) return [{ x: center, y: maxY,
vx: 0, vy: 0, r: this.MarbleR}];
const left = center - y*(MarbleR+5),
right = center + y*(MarbleR+5);
return range(left, right, MarbleR*2+5).map(x => ({
x: x,
y: maxY-y*(MarbleR*2+5),
vx: 0,
vy: 0,
r: this.MarbleR
}));
}).reduce((acc, pos) => acc.concat(pos), []);
marbles = [].concat(marbles, {
x: width/2,
y: height-150,
vx: 0,
vy: 0,
r: this.MarbleR
});
marbles.forEach((m, i) => marbles[i].id = i);
return marbles;
}
@action startGameLoop() {
this.marbles = this.initialPositions;
this.timer = timer(() => this.simulationStep());
}
@action simulationStep() {
const { width, height, MarbleR } = this;
const moveMarble = ({x, y, vx, vy, id}) => {
let _vx = ((x+vx < MarbleR) ? -vx : (x+vx > width-MarbleR) ? -vx : vx)*.99,
_vy = ((y+vy < MarbleR) ? -vy : (y+vy > height-MarbleR) ? -vy : vy)*.99;
// nearest marble is a collision candidate
const subdividedSpace = quadtree().extent([[-1, -1],
[this.width+1, this.height+1]])
.x(d => d.x)
.y(d => d.y)
.addAll(this.marbles
.filter(m => id !== m.id)),
candidate = subdividedSpace.find(x, y, MarbleR*2);
if (candidate) {
// borrowing @air_hadoken's implementation from here:
// https://github.com/airhadoken/game_of_circles/blob/master/circles.js#L64
const cx = candidate.x,
cy = candidate.y,
normx = cx - x,
normy = cy - y,
dist = (normx ** 2 + normy ** 2),
c = (_vx * normx + _vy * normy) / dist * 2.3;
_vx = (_vx - c * normx)/2.3;
_vy = (_vy - c * normy)/2.3;
candidate.vx += -_vx;
candidate.vy += -_vy;
candidate.x += -_vx;
candidate.y += -_vy;
}
return {
x: x + _vx,
y: y + _vy,
vx: _vx,
vy: _vy
}
};
this.marbles.forEach((marble, i) => {
const { x, y, vx, vy } = moveMarble(marble);
this.marbles[i].x = x;
this.marbles[i].y = y;
this.marbles[i].vx = vx;
this.marbles[i].vy = vy;
});
}
@action shoot({ x, y, vx, vy }, i) {
const maxSpeed = 20;
this.marbles[i].x = x;
this.marbles[i].y = y;
this.marbles[i].vx = vx < maxSpeed ? vx : maxSpeed;
this.marbles[i].vy = vy < maxSpeed ? vy : maxSpeed;
}
}
export default new Physics();