You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

272 lines
5.5 KiB

2 years ago
"use strict"
class Cube{
constructor(){
this.bricks = [];
for (let x = -1; x < 2; x++){
for (let y = -1; y < 2; y++){
for (let z = -1; z < 2; z++){
this.bricks.push(new Brick(x, y, z));
}
}
}
}
show(){
push();
if (this.rotation){
for (let i = -1; i < 2; i++){
if (i === this.rotation.index){
push();
eval("rotate" + this.rotation.axis.toUpperCase() + "(this.rotation.angle);");
for (let b of this.getLayer(this.rotation.axis, i)) b.show();
pop();
}
else {
for (let b of this.getLayer(this.rotation.axis, i)) b.show();
}
}
}
else {
for (let b of this.bricks) b.show();
}
pop();
}
update(){
if (this.rotation) this.rotation.update();
}
updatePos(){
let m = new Matrix();
m.rotate(this.rotation.angle);
let o = other(this.rotation.axis),
bricks = [],
fields = [],
resultBricks = [], iBricks = 0, pBricks,
resultFields = [], iFields = 0, pFields;
for (let b of this.getLayer(this.rotation.axis, this.rotation.index)){
eval("bricks.push({x: b.pos." + o[0] + ", y: b.pos." + o[1] + "});");
for (let f of b.fields){
for (let p of f.points){
eval("fields.push({x: p." + o[0] + ", y: p." + o[1] + "});");
}
}
}
// transform points
while(pBricks = bricks[iBricks++]) resultBricks.push(m.applyToPoint(pBricks));
while(pFields = fields[iFields++]) resultFields.push(m.applyToPoint(pFields));
iBricks = 0, iFields = 0;
for (let b of this.getLayer(this.rotation.axis, this.rotation.index)){
let p = resultBricks[iBricks];
eval("b.pos." + o[0] + " = p.x;");
eval("b.pos." + o[1] + " = p.y;");
iBricks++;
for (let f of b.fields){
for (let pt of f.points){
let pf = resultFields[iFields];
eval("pt." + o[0] + " = pf.x;");
eval("pt." + o[1] + " = pf.y;");
iFields++;
}
}
}
}
getLayer(axis, index){
let bricks = [];
for (let b of this.bricks){
if (eval("b.pos." + axis) === index){
bricks.push(b);
}
}
return bricks;
}
rotate(axis, index, dir, v){
if (!this.rotation)
this.rotation = new Rotation(axis, index, dir, v, () => {
cube.updatePos();
cube.rotation = null;
});
}
scramble(count){
let cube = this;
if (count === 0)
this.rotation = null;
else
this.rotation = new Rotation(random(["x", "y", "z"]), random([-1, 1]), random([-1, 1]), PI / 32, () => {
cube.updatePos();
cube.scramble(count - 1);
});
}
}
function other(axis){
switch(axis){
case "x":
return ["y", "z"];
case "y":
return ["z", "x"];
case "z":
return ["x", "y"];
}
}
class Brick{
constructor(x, y, z){
this.pos = createVector(x, y, z);
this.size = 85;
this.createFields();
}
show(){
this.pos.mult(this.size);
push();
translate(this.pos.x, this.pos.y, this.pos.z);
for (let f of this.fields) f.show();
pop();
this.pos.div(this.size);
}
createFields(){
this.fields = [];
let sides = [[],[],[],[],[],[]];
let c = [
"#F00",
"#F90",
"#FFF",
"#FF0",
"#00F",
"#0F0",
"#000"
];
for (let x = -1; x < 2; x++){
for (let y = -1; y < 2; y++){
for (let z = -1; z < 2; z++){
let arr = [];
if (x > 0 && y && z){
if (this.pos.x > 0) arr.push({i: 0, colored: true});
else arr.push({i: 0});
}
if (x < 0 && y && z){
if (this.pos.x < 0) arr.push({i: 1, colored: true});
else arr.push({i: 1});
}
if (y > 0 && x && z){
if (this.pos.y > 0) arr.push({i: 2, colored: true});
else arr.push({i: 2});
}
if (y < 0 && x && z){
if (this.pos.y < 0) arr.push({i: 3, colored: true});
else arr.push({i: 3});
}
if (z > 0 && x && y){
if (this.pos.z > 0) arr.push({i: 4, colored: true});
else arr.push({i: 4});
}
if (z < 0 && x && y){
if (this.pos.z < 0) arr.push({i: 5, colored: true});
else arr.push({i: 5});
}
for (let a of arr){
sides[a.i].push({p: createVector(x, y, z), colored: a.colored});
}
}
}
}
for (let s of sides){
let points = [];
for (let a of s) points.push(a.p);
let color = s[0].colored ? c[sides.indexOf(s)] : c[6];
this.fields.push(new Field(points, color, this.size));
}
}
hasColor(c){
for (let f of this.fields){
if (f.colorEquals(c)){
return true;
}
}
return false;
}
get isEdge(){
return this.coloredCount === 2;
}
get isCorner(){
return this.coloredCount === 3;
}
get isFlat(){
return this.coloredCount === 1;
}
get coloredCount(){
let count = 0;
for (let f of this.fields){
if (!f.colorEquals("#000")) {
count++;
}
}
return count;
}
}
class Field{
constructor(points, c, size){
//relative to brick
this.color = {
light: color(c),
dark: dark(color(c), 0.4)
};
this.bSize = size;
this.size = size * 0.95;
this.points = points;
}
show(){
for (let p of this.points) p.mult(this.size / 2);
let p = this.points;
if (this.dark) fill(this.color.dark);
else fill(this.color.light);
strokeWeight(8);
stroke(0);
beginShape();
vertex(p[0].x, p[0].y, p[0].z);
vertex(p[2].x, p[2].y, p[2].z);
vertex(p[3].x, p[3].y, p[3].z);
vertex(p[1].x, p[1].y, p[1].z);
endShape(CLOSE);
for (let p of this.points) p.div(this.size / 2);
}
colorEquals(c){
let equal = true;
for (let i = 0; i < 3; i++){
if (this.color.light.levels[i] !== color(c).levels[i]){
equal = false;
}
}
return equal;
}
}
function dark(c, val){
return color(red(c) * val, green(c) * val, blue(c) * val);
}