commit
93c8cd4fd8
60 changed files with 21956 additions and 0 deletions
@ -0,0 +1,2 @@ |
|||||||
|
.idea |
||||||
|
|
@ -0,0 +1,6 @@ |
|||||||
|
{ |
||||||
|
"display_name": "Christmas Tree", |
||||||
|
"info_text": "With this little nice tool you can have fun decorating your own Christmas Trees.", |
||||||
|
"visible": true, |
||||||
|
"tags": ["Tool"] |
||||||
|
} |
After Width: | Height: | Size: 204 KiB |
After Width: | Height: | Size: 311 KiB |
After Width: | Height: | Size: 318 B |
@ -0,0 +1,138 @@ |
|||||||
|
"use strict"; |
||||||
|
let snowflake_max_r = 12; |
||||||
|
let snowflake_min_r = 7; |
||||||
|
let snowflake_max_count = 500; |
||||||
|
class Background { |
||||||
|
constructor() { |
||||||
|
this.bgColor = p.color(100, 100, 255); |
||||||
|
this.wind_direction = 0; |
||||||
|
this.ground = new Ground(); |
||||||
|
this.snowflakes = []; |
||||||
|
for (let i = 0; i < snowflake_max_count; i++) { |
||||||
|
this.snowflakes.push(this.getNewSnowflake()); |
||||||
|
} |
||||||
|
this.snowflakes.sort((a, b) => { |
||||||
|
if (a.radius < b.radius) { |
||||||
|
return -1; |
||||||
|
} |
||||||
|
if (a.radius > b.radius) { |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
}); |
||||||
|
this.backgroundSnowflakes = this.snowflakes.slice(0, snowflake_max_count * 2 / 3); |
||||||
|
this.foregroundSnowflakes = this.snowflakes.slice(snowflake_max_count * 2 / 3, snowflake_max_count); |
||||||
|
this.updateSettings(); |
||||||
|
} |
||||||
|
getNewSnowflake() { |
||||||
|
return new Snowflake(p.random(p.width), p.random(-snowflake_max_r, p.height), p.random(snowflake_min_r, snowflake_max_r)); |
||||||
|
} |
||||||
|
updateSettings() { |
||||||
|
let allowed_snowflakes_count = $('#snow_intensity').val(); |
||||||
|
let visible_snowflakes = p.shuffle(this.snowflakes.filter(s => !s.hidden)); |
||||||
|
let hidden_snowflakes = p.shuffle(this.snowflakes.filter(s => s.hidden)); |
||||||
|
let snowflakes_to_add = allowed_snowflakes_count - visible_snowflakes.length; |
||||||
|
if (snowflakes_to_add > 0) { |
||||||
|
for (let i = 0; i < snowflakes_to_add; i++) { |
||||||
|
hidden_snowflakes[i].hidden = false; |
||||||
|
} |
||||||
|
} |
||||||
|
if (snowflakes_to_add < 0) { |
||||||
|
for (let i = 0; i < p.abs(snowflakes_to_add); i++) { |
||||||
|
visible_snowflakes[i].hidden = true; |
||||||
|
} |
||||||
|
} |
||||||
|
this.bgColor.setBlue(p.map(allowed_snowflakes_count, 0, snowflake_max_count, 255, 170)); |
||||||
|
} |
||||||
|
update() { |
||||||
|
this.ground.update(); |
||||||
|
this.wind_direction = p.sin(p.frameCount / 1000); |
||||||
|
this.snowflakes.forEach(s => s.update(this.wind_direction)); |
||||||
|
} |
||||||
|
display(asForeground) { |
||||||
|
if (asForeground) { |
||||||
|
this.foregroundSnowflakes.forEach(s => s.display()); |
||||||
|
} |
||||||
|
else { |
||||||
|
p.background(this.bgColor); |
||||||
|
this.ground.display(); |
||||||
|
this.backgroundSnowflakes.forEach(s => s.display()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
class Snowflake { |
||||||
|
constructor(x, y, r) { |
||||||
|
this.rotation = 0; |
||||||
|
this.pos = p.createVector(x, y); |
||||||
|
this.radius = r; |
||||||
|
this.hidden = false; |
||||||
|
this.alpha = 0; |
||||||
|
this.rotateDir = p.random([-1, 1]) * p.random(0.01, 0.03); |
||||||
|
this.peakCount = p.random([4, 5, 6]); |
||||||
|
} |
||||||
|
update(wind_direction) { |
||||||
|
let dir = p.createVector(p.map(this.radius, snowflake_min_r, snowflake_max_r, 0, 1) * wind_direction, p.map(this.radius, snowflake_min_r, snowflake_max_r, 0.5, 1) * 2); |
||||||
|
this.pos.add(dir); |
||||||
|
this.rotation += this.rotateDir; |
||||||
|
if (this.pos.y > p.height + this.radius) { |
||||||
|
this.pos.y = -this.radius; |
||||||
|
} |
||||||
|
if (this.pos.x > p.width + this.radius) { |
||||||
|
this.pos.x = -this.radius; |
||||||
|
} |
||||||
|
else if (this.pos.x < -this.radius) { |
||||||
|
this.pos.x = p.width + this.radius; |
||||||
|
} |
||||||
|
if (this.hidden && this.alpha > 0) { |
||||||
|
this.alpha -= 0.015; |
||||||
|
} |
||||||
|
else if (this.alpha < 1) { |
||||||
|
this.alpha += 0.015; |
||||||
|
} |
||||||
|
} |
||||||
|
display() { |
||||||
|
p.push(); |
||||||
|
p.strokeWeight(1); |
||||||
|
p.stroke(255, this.alpha * 255); |
||||||
|
p.fill(255, this.alpha * 255); |
||||||
|
p.translate(this.pos); |
||||||
|
p.rotate(this.rotation % p.TWO_PI); |
||||||
|
for (let rad = 0; rad < p.PI; rad += p.PI / this.peakCount) { |
||||||
|
let x1 = p.cos(rad) * this.radius; |
||||||
|
let y1 = p.sin(rad) * this.radius; |
||||||
|
let x2 = p.cos(rad + p.PI) * this.radius; |
||||||
|
let y2 = p.sin(rad + p.PI) * this.radius; |
||||||
|
p.line(x1, y1, x2, y2); |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
} |
||||||
|
class Ground { |
||||||
|
constructor() { |
||||||
|
this.createPoints(); |
||||||
|
} |
||||||
|
createPoints() { |
||||||
|
this.points = []; |
||||||
|
for (let x = 0; x < p.width; x++) { |
||||||
|
let vector = p.createVector(x, p.noise(x / 300) * 150); |
||||||
|
this.points.push(vector); |
||||||
|
} |
||||||
|
} |
||||||
|
update() { |
||||||
|
} |
||||||
|
display() { |
||||||
|
p.push(); |
||||||
|
p.fill(220, 220, 255); |
||||||
|
p.stroke(50, 50, 150); |
||||||
|
p.strokeWeight(2); |
||||||
|
p.beginShape(); |
||||||
|
for (let point of this.points) { |
||||||
|
p.vertex(point.x, point.y + p.height / 2); |
||||||
|
} |
||||||
|
p.vertex(p.width, p.height); |
||||||
|
p.vertex(0, p.height); |
||||||
|
p.endShape(p.CLOSE); |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=background.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,30 @@ |
|||||||
|
"use strict"; |
||||||
|
class Ball extends Decoration { |
||||||
|
constructor(properties) { |
||||||
|
super(properties); |
||||||
|
this.createGraphics(); |
||||||
|
} |
||||||
|
createGraphics() { |
||||||
|
let img = images['ball']; |
||||||
|
this.graphics = p.createGraphics(img.width, img.height); |
||||||
|
this.updateColor(); |
||||||
|
} |
||||||
|
updateColor() { |
||||||
|
let img = images['ball']; |
||||||
|
this.graphics.clear(); |
||||||
|
this.graphics.tint(this.colors[0]); |
||||||
|
this.graphics.image(img, 0, 0); |
||||||
|
} |
||||||
|
display(pos, dim) { |
||||||
|
super.display(pos, dim); |
||||||
|
p.image(this.graphics, 0, 0, this.radius * 2, this.radius * 2); |
||||||
|
if (this.mouseIsOver) { |
||||||
|
this.brightness(70); |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
update() { |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=ball.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"ball.js","sourceRoot":"","sources":["../ts/ball.ts"],"names":[],"mappings":";AAAA,MAAM,IAAK,SAAQ,UAAU;IAIzB,YAAY,UAAkB;QAC1B,KAAK,CAAC,UAAU,CAAC,CAAC;QAClB,IAAI,CAAC,cAAc,EAAE,CAAC;IAC1B,CAAC;IAED,cAAc;QACV,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QACxD,IAAI,CAAC,WAAW,EAAE,CAAC;IACvB,CAAC;IAED,WAAW;QACP,IAAI,GAAG,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;QACzB,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,CAAC;QACtB,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;QACnC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;IACnC,CAAC;IAGD,OAAO,CAAC,GAAe,EAAE,GAAe;QACpC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAExB,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAC/D,IAAI,IAAI,CAAC,WAAW,EAAC;YACjB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;SACvB;QAED,CAAC,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IAED,MAAM;QACF,KAAK,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC;CAEJ"} |
@ -0,0 +1,146 @@ |
|||||||
|
"use strict"; |
||||||
|
var has = Reflect.has; |
||||||
|
class Chain extends Decoration { |
||||||
|
constructor(properties) { |
||||||
|
super(properties); |
||||||
|
this.p1 = p.createVector(-0.65, 0); |
||||||
|
this.p2 = p.createVector(0.65, 0); |
||||||
|
this.p1IsBoundToMouse = false; |
||||||
|
this.p2IsBoundToMouse = false; |
||||||
|
this.placedOnce = false; |
||||||
|
this.points = []; |
||||||
|
this.lights = []; |
||||||
|
this.generate(); |
||||||
|
} |
||||||
|
get properties() { |
||||||
|
let obj = super.properties; |
||||||
|
obj['p1'] = this.p1; |
||||||
|
obj['p2'] = this.p2; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
generate() { |
||||||
|
let d = p.dist(this.p1.x, this.p1.y, this.p2.x, this.p2.y); |
||||||
|
let m = p.abs((this.p2.y - this.p1.y) / (this.p2.x - this.p1.x)); |
||||||
|
let a = -1 / d - m / 10; |
||||||
|
let b = (this.p1.y - this.p2.y + a * p.pow(this.p2.x, 2) - a * p.pow(this.p1.x, 2)) / |
||||||
|
(this.p1.x - this.p2.x); |
||||||
|
if (this.p1.x - this.p2.x === 0) |
||||||
|
b = 0; |
||||||
|
let c = this.p1.y - a * p.pow(this.p1.x, 2) - b * this.p1.x; |
||||||
|
let func = x => a * x * x + b * x + c; |
||||||
|
let detail = 40; |
||||||
|
let points = []; |
||||||
|
for (let i = 0; i <= detail; i++) { |
||||||
|
let point = { x: 0, y: 0 }; |
||||||
|
point.x = this.p1.x + (this.p2.x - this.p1.x) / detail * i; |
||||||
|
point.y = func(point.x); |
||||||
|
points.push(point); |
||||||
|
} |
||||||
|
let lightDist = 0.35; |
||||||
|
let lastLight = { x: Infinity, y: Infinity }; |
||||||
|
let lights = []; |
||||||
|
detail = 300; |
||||||
|
for (let i = 0; i <= detail; i++) { |
||||||
|
let point = { x: 0, y: 0, hasLight: false }; |
||||||
|
point.x = this.p1.x + (this.p2.x - this.p1.x) / detail * i; |
||||||
|
point.y = func(point.x); |
||||||
|
if (p.dist(point.x, point.y, lastLight.x, lastLight.y) >= lightDist) { |
||||||
|
lights.push(point); |
||||||
|
lastLight = point; |
||||||
|
} |
||||||
|
} |
||||||
|
this.points = points; |
||||||
|
this.lights = lights; |
||||||
|
} |
||||||
|
display(pos, dim) { |
||||||
|
super.display(pos, dim); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.stroke(0); |
||||||
|
p.noFill(); |
||||||
|
p.beginShape(); |
||||||
|
for (let point of this.points) |
||||||
|
p.vertex(point.x, point.y); |
||||||
|
p.endShape(); |
||||||
|
p.strokeWeight(0.01); |
||||||
|
let i = 0; |
||||||
|
for (let point of this.lights) { |
||||||
|
let colorIndex = (i + p.int(p.frameCount / 30)) % this.colors.length; |
||||||
|
p.fill(this.colors[colorIndex]); |
||||||
|
p.ellipse(point.x, point.y, 0.2, 0.2); |
||||||
|
i++; |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
get hasValidPosition() { |
||||||
|
return game.tree.containsPosition(this.realPosByAnchor(this.p1), true) |
||||||
|
&& game.tree.containsPosition(this.realPosByAnchor(this.p2), true); |
||||||
|
} |
||||||
|
realPosByAnchor(anchor) { |
||||||
|
return p5.Vector.add(p5.Vector.mult(p5.Vector.add(this.pos, anchor), game.tree.sizeMultiplier), game.center); |
||||||
|
} |
||||||
|
realPointDistToAnchor(point, anchor) { |
||||||
|
let pos = this.realPosByAnchor(anchor); |
||||||
|
return p.dist(pos.x, pos.y, point.x, point.y); |
||||||
|
} |
||||||
|
isMouseOverAnchor(anchor) { |
||||||
|
return this.realPointDistToAnchor(p.createVector(p.mouseX, p.mouseY), anchor) <= 0.5 * game.tree.sizeMultiplier; |
||||||
|
} |
||||||
|
get mouseIsOver() { |
||||||
|
return this.isTaken && (this.isMouseOverAnchor(this.p1) || this.isMouseOverAnchor(this.p2)); |
||||||
|
} |
||||||
|
//Mouse is over this
|
||||||
|
mousePressed() { |
||||||
|
super.mousePressed(); |
||||||
|
if (this.isMouseOverAnchor(this.p1)) { |
||||||
|
this.p1IsBoundToMouse = true; |
||||||
|
} |
||||||
|
else if (this.isMouseOverAnchor(this.p2)) { |
||||||
|
this.p2IsBoundToMouse = true; |
||||||
|
} |
||||||
|
} |
||||||
|
updateFromPoint(point, other, x, y) { |
||||||
|
if (this.placedOnce) { |
||||||
|
let pointRelative = p.createVector(x - this.pos.x, y - this.pos.y); |
||||||
|
point.set(pointRelative); |
||||||
|
let pointReal = p5.Vector.add(this.pos, point); |
||||||
|
let otherReal = p5.Vector.add(this.pos, other); |
||||||
|
let newPos = p5.Vector.div(p5.Vector.add(pointReal, otherReal), 2); |
||||||
|
point.set(p5.Vector.sub(pointReal, newPos)); |
||||||
|
other.set(p5.Vector.mult(point, -1)); |
||||||
|
this.pos.set(newPos); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.pos.set(x - point.x, y - point.y); |
||||||
|
} |
||||||
|
} |
||||||
|
update() { |
||||||
|
let x = (p.mouseX - game.center.x) / game.tree.sizeMultiplier, y = (p.mouseY - game.center.y) / game.tree.sizeMultiplier; |
||||||
|
if (this.isBoundToMouse) { |
||||||
|
if (this.p1IsBoundToMouse) { |
||||||
|
this.updateFromPoint(this.p1, this.p2, x, y); |
||||||
|
} |
||||||
|
if (this.p2IsBoundToMouse) { |
||||||
|
this.updateFromPoint(this.p2, this.p1, x, y); |
||||||
|
} |
||||||
|
this.generate(); |
||||||
|
} |
||||||
|
else { |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
if (this.isTaken && !this.isBoundToMouse) { |
||||||
|
this.placedOnce = true; |
||||||
|
} |
||||||
|
} |
||||||
|
toJSON(index) { |
||||||
|
let list = [ |
||||||
|
"p1", |
||||||
|
"p2" |
||||||
|
]; |
||||||
|
let obj = super.toJSON(index); |
||||||
|
for (let item of list) { |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=chain.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,67 @@ |
|||||||
|
"use strict"; |
||||||
|
class Container { |
||||||
|
constructor(index, content) { |
||||||
|
this.pos = p.createVector(); |
||||||
|
this.dim = p.createVector(); |
||||||
|
this.index = index; |
||||||
|
this.content = content; |
||||||
|
} |
||||||
|
get mouseIsOver() { |
||||||
|
return p.mouseX > this.pos.x && p.mouseX < this.pos.x + this.dim.x && |
||||||
|
p.mouseY > this.pos.y && p.mouseY < this.pos.y + this.dim.y; |
||||||
|
} |
||||||
|
get center() { |
||||||
|
return p5.Vector.add(this.pos, p5.Vector.div(this.dim, 2)); |
||||||
|
} |
||||||
|
display() { |
||||||
|
let w = this.dim.x, h = this.dim.y; |
||||||
|
let x = this.pos.x + w / 2, y = this.pos.y + h / 2; |
||||||
|
p.image(images['box'], x, y, w, h); |
||||||
|
if (this.content !== game.tree) { |
||||||
|
this.content.display(); |
||||||
|
} |
||||||
|
if (this.mouseIsOver) { |
||||||
|
p.fill(0, 50); |
||||||
|
p.noStroke(); |
||||||
|
p.rect(x - w / 2, y - h / 2, w, h); |
||||||
|
} |
||||||
|
} |
||||||
|
update() { |
||||||
|
let currentCount = game.currentContainers.length; |
||||||
|
let w = p.width / currentCount, h = w; |
||||||
|
let x = w * this.index, y = p.height - h; |
||||||
|
if (this.content instanceof Decoration) { |
||||||
|
let otherCount = game.containers.filter(c => game.currentContainers.find(ic => ic == c) == null).length; |
||||||
|
w = h = p.width / otherCount; |
||||||
|
x = w * this.index; |
||||||
|
y = p.height - h; |
||||||
|
x += p.width / 2 - w * currentCount / 2; |
||||||
|
} |
||||||
|
this.pos.set(x, y); |
||||||
|
this.dim.set(w, h); |
||||||
|
if (this.content !== game.tree) |
||||||
|
this.content.update(); |
||||||
|
} |
||||||
|
mousePressed() { |
||||||
|
if (this.content instanceof Tree) { |
||||||
|
game.tree.animationDirection = -1; |
||||||
|
if (this.content === game.tree) { |
||||||
|
game.tree = new Tree(null); |
||||||
|
} |
||||||
|
else { |
||||||
|
game.tree = this.content; |
||||||
|
game.tree.animationDirection = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.content instanceof Decoration && !game.tree.isPlaceholder) { |
||||||
|
let decoration = Decoration.Create(this.content.properties); |
||||||
|
decoration.isTaken = true; |
||||||
|
decoration.isBoundToMouse = true; |
||||||
|
game.tree.decorations.push(decoration); |
||||||
|
if (decoration instanceof Chain) { |
||||||
|
decoration.p1IsBoundToMouse = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=container.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"container.js","sourceRoot":"","sources":["../ts/container.ts"],"names":[],"mappings":"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"} |
@ -0,0 +1,167 @@ |
|||||||
|
"use strict"; |
||||||
|
class Decoration { |
||||||
|
constructor(properties) { |
||||||
|
this.pos = p.createVector(); |
||||||
|
this.isTaken = false; |
||||||
|
this.isBoundToMouse = false; |
||||||
|
this.isToDelete = false; |
||||||
|
this.needsValidation = false; |
||||||
|
this.isSelected = false; |
||||||
|
for (let key in properties) { |
||||||
|
if (properties.hasOwnProperty(key)) { |
||||||
|
if (Array.isArray(properties[key])) { |
||||||
|
this[key] = arrayCopy(properties[key]); |
||||||
|
} |
||||||
|
else { |
||||||
|
this[key] = properties[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
get properties() { |
||||||
|
let colors = []; |
||||||
|
for (let i = 0; i < this.colors.length; i++) { |
||||||
|
let color = []; |
||||||
|
for (let c of this.colors[i]) { |
||||||
|
color.push(c); |
||||||
|
} |
||||||
|
colors.push(color); |
||||||
|
} |
||||||
|
return { |
||||||
|
radius: this.radius, |
||||||
|
colors: colors, |
||||||
|
type: this.type |
||||||
|
}; |
||||||
|
} |
||||||
|
get mouseIsOver() { |
||||||
|
if (this.isTaken) { |
||||||
|
let pos = this.realPos; |
||||||
|
return p.dist(pos.x, pos.y, p.mouseX, p.mouseY) <= this.radius * game.tree.sizeMultiplier; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
get hasValidPosition() { |
||||||
|
return game.tree.containsPosition(this.realPos, true); |
||||||
|
} |
||||||
|
get realPos() { |
||||||
|
return p5.Vector.add(p5.Vector.mult(this.pos, game.tree.sizeMultiplier), game.center); |
||||||
|
} |
||||||
|
static Create(properties) { |
||||||
|
switch (properties['type']) { |
||||||
|
case 'ball': |
||||||
|
return new Ball(properties); |
||||||
|
case 'star': |
||||||
|
return new Star(properties); |
||||||
|
case 'chain': |
||||||
|
return new Chain(properties); |
||||||
|
} |
||||||
|
} |
||||||
|
display(pos, dim) { |
||||||
|
let sizeMultiplier = this.sizeMultiplier; |
||||||
|
if (pos || dim) { |
||||||
|
sizeMultiplier = dim.y * 0.6; |
||||||
|
} |
||||||
|
else { |
||||||
|
pos = this.pos; |
||||||
|
} |
||||||
|
p.push(); |
||||||
|
p.translate(pos); |
||||||
|
p.scale(sizeMultiplier); |
||||||
|
} |
||||||
|
brightness(value) { |
||||||
|
p.noStroke(); |
||||||
|
p.fill(0, 0, 0, value); |
||||||
|
p.ellipse(0, 0, this.radius * 2, this.radius * 2); |
||||||
|
} |
||||||
|
update() { |
||||||
|
if (!this.isTaken) { |
||||||
|
this.pos = this.container.center; |
||||||
|
this.sizeMultiplier = this.container.dim.y * 0.6; |
||||||
|
} |
||||||
|
else { |
||||||
|
this.sizeMultiplier = 1; |
||||||
|
} |
||||||
|
if (this.isBoundToMouse) { |
||||||
|
let x = (p.mouseX - game.center.x) / game.tree.sizeMultiplier, y = (p.mouseY - game.center.y) / game.tree.sizeMultiplier; |
||||||
|
this.pos.set(x, y); |
||||||
|
} |
||||||
|
} |
||||||
|
//Assumes mouse is over this
|
||||||
|
mousePressed() { |
||||||
|
this.isBoundToMouse = true; |
||||||
|
} |
||||||
|
//Always called
|
||||||
|
mouseReleased() { |
||||||
|
} |
||||||
|
toJSON(index) { |
||||||
|
let list = [ |
||||||
|
"pos", |
||||||
|
"colors", |
||||||
|
"radius", |
||||||
|
"type" |
||||||
|
]; |
||||||
|
let obj = {}; |
||||||
|
for (let item of list) { |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
static restoreFrom(rawDeco) { |
||||||
|
let props = {}; |
||||||
|
for (let key in rawDeco) { |
||||||
|
if (['pos', 'p1', 'p2'].find(s => s === key) === undefined) { |
||||||
|
props[key] = rawDeco[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
let deco = Decoration.Create(props); |
||||||
|
deco.isTaken = true; |
||||||
|
deco.pos.x = rawDeco['pos'].x; |
||||||
|
deco.pos.y = rawDeco['pos'].y; |
||||||
|
if (deco instanceof Chain) { |
||||||
|
deco.p1.set(rawDeco['p1'].x, rawDeco['p1'].y); |
||||||
|
deco.p2.set(rawDeco['p2'].x, rawDeco['p2'].y); |
||||||
|
deco.generate(); |
||||||
|
} |
||||||
|
return deco; |
||||||
|
} |
||||||
|
} |
||||||
|
function darker(c) { |
||||||
|
let newC = []; |
||||||
|
for (let v of c) { |
||||||
|
newC.push(p.constrain(v * 0.6, 0, 255)); |
||||||
|
} |
||||||
|
return newC; |
||||||
|
} |
||||||
|
function arrayCopy(a) { |
||||||
|
let newArr = []; |
||||||
|
for (let c of a) { |
||||||
|
let copy = c; |
||||||
|
if (Array.isArray(c)) { |
||||||
|
copy = arrayCopy(c); |
||||||
|
} |
||||||
|
newArr.push(copy); |
||||||
|
} |
||||||
|
return newArr; |
||||||
|
} |
||||||
|
function equals(a1, a2) { |
||||||
|
// if the other array is a falsy value, return
|
||||||
|
if (!a1) |
||||||
|
return false; |
||||||
|
// compare lengths - can save a lot of time
|
||||||
|
if (a2.length != a1.length) |
||||||
|
return false; |
||||||
|
for (let i = 0, l = a2.length; i < l; i++) { |
||||||
|
// Check if we have nested arrays
|
||||||
|
if (a2[i] instanceof Array && a1[i] instanceof Array) { |
||||||
|
// recurse into the nested arrays
|
||||||
|
if (!a2[i].equals(a1[i])) |
||||||
|
return false; |
||||||
|
} |
||||||
|
else if (a2[i] != a1[i]) { |
||||||
|
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
//# sourceMappingURL=decoration.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,27 @@ |
|||||||
|
'use strict'; |
||||||
|
p.keyPressed = () => { |
||||||
|
switch (p.keyCode) { |
||||||
|
//Ctrl + D
|
||||||
|
case 68: |
||||||
|
if (p.keyIsDown(17)) { |
||||||
|
debug = !debug; |
||||||
|
let msg = 'Debug mode turned ' + (debug ? 'ON' : 'OFF'); |
||||||
|
console.info(msg); |
||||||
|
return false; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
}; |
||||||
|
p.mousePressed = () => { |
||||||
|
game.mousePressed(); |
||||||
|
released = false; |
||||||
|
}; |
||||||
|
p.mouseReleased = () => { |
||||||
|
game.mouseReleased(); |
||||||
|
released = true; |
||||||
|
}; |
||||||
|
p.windowResized = () => { |
||||||
|
let w = $('#canvas_holder').width(), h = $('#canvas_holder').height(); |
||||||
|
p.resizeCanvas(w, h); |
||||||
|
}; |
||||||
|
//# sourceMappingURL=events.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"events.js","sourceRoot":"","sources":["../ts/events.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,CAAC,CAAC,UAAU,GAAG,GAAG,EAAE;IAChB,QAAQ,CAAC,CAAC,OAAO,EAAC;QACd,UAAU;QACV,KAAK,EAAE;YACH,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,CAAC,EAAC;gBAChB,KAAK,GAAG,CAAC,KAAK,CAAC;gBACf,IAAI,GAAG,GAAG,oBAAoB,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;gBACxD,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBAClB,OAAO,KAAK,CAAC;aAChB;YACD,MAAM;KACb;AACL,CAAC,CAAA;AAED,CAAC,CAAC,YAAY,GAAG,GAAG,EAAE;IAClB,IAAI,CAAC,YAAY,EAAE,CAAC;IACpB,QAAQ,GAAG,KAAK,CAAC;AACrB,CAAC,CAAA;AACD,CAAC,CAAC,aAAa,GAAG,GAAG,EAAE;IACnB,IAAI,CAAC,aAAa,EAAE,CAAC;IACrB,QAAQ,GAAG,IAAI,CAAC;AACpB,CAAC,CAAA;AAED,CAAC,CAAC,aAAa,GAAG,GAAG,EAAE;IACnB,IAAI,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,KAAK,EAAE,EACnC,CAAC,GAAG,CAAC,CAAC,gBAAgB,CAAC,CAAC,MAAM,EAAE,CAAC;IACjC,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACzB,CAAC,CAAA"} |
@ -0,0 +1,219 @@ |
|||||||
|
"use strict"; |
||||||
|
class Game { |
||||||
|
constructor() { |
||||||
|
this.trees = []; |
||||||
|
this.tree = new Tree(null); |
||||||
|
this.decorations = []; |
||||||
|
this.containers = []; |
||||||
|
this.isTreeMode = true; |
||||||
|
this.isDecorationMode = false; |
||||||
|
this.switchButton = new Button('switch'); |
||||||
|
this.downloadButton = new Button('download'); |
||||||
|
this.restoreButton = new Button('restore'); |
||||||
|
this.background = new Background(); |
||||||
|
settings.game.trees.forEach((s) => this.trees.push(new Tree(s))); |
||||||
|
let red = settings.game.colors.red; |
||||||
|
this.decorations = [ |
||||||
|
Decoration.Create({ |
||||||
|
type: "ball", radius: 0.45, colors: [red] |
||||||
|
}), |
||||||
|
Decoration.Create({ |
||||||
|
type: "star", radius: 0.45, colors: [red, darker(red)] |
||||||
|
}), |
||||||
|
Decoration.Create({ |
||||||
|
type: "chain", radius: 0.45, colors: [ |
||||||
|
settings.game.colors.gold, |
||||||
|
settings.game.colors.silver |
||||||
|
] |
||||||
|
}), |
||||||
|
]; |
||||||
|
$('#gold, #silver').attr('checked', 'checked'); |
||||||
|
this.trees.forEach((t, i) => { |
||||||
|
let c = new Container(i, t); |
||||||
|
this.containers.push(c); |
||||||
|
t.container = c; |
||||||
|
}); |
||||||
|
this.decorations.forEach((d, i) => { |
||||||
|
let c = new Container(i, d); |
||||||
|
this.containers.push(c); |
||||||
|
d.container = c; |
||||||
|
}); |
||||||
|
this.updateDecorationSettings(); |
||||||
|
this.updateStarSettings(); |
||||||
|
} |
||||||
|
updateDecorationSettings() { |
||||||
|
this.decorations.filter(d => d instanceof Ball || d instanceof Star).forEach(d => { |
||||||
|
d.radius = $('#radius').val() / 100 * 0.7; |
||||||
|
let colors = []; |
||||||
|
colors.push(JSON.parse($('#color').val())); |
||||||
|
if (d instanceof Ball) { |
||||||
|
d.colors = colors; |
||||||
|
d.updateColor(); |
||||||
|
} |
||||||
|
if (d instanceof Star) { |
||||||
|
d.innerRadius = $('#inner_radius').val() * d.radius; |
||||||
|
colors.push(darker(colors[0])); |
||||||
|
d.colors = colors; |
||||||
|
d.createTriangles(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
updateStarSettings() { |
||||||
|
this.decorations.filter(d => d instanceof Star).forEach((s) => { |
||||||
|
s.innerRadius = $('#inner_radius').val() * s.radius; |
||||||
|
s.raysCount = parseInt($('#rays_count').val()); |
||||||
|
s.createTriangles(); |
||||||
|
}); |
||||||
|
} |
||||||
|
updateChainSettings(element) { |
||||||
|
let chain = this.decorations.find(d => d instanceof Chain); |
||||||
|
let colorName = element.attr('id'); |
||||||
|
let colorValue = settings.game.colors[colorName]; |
||||||
|
let cvIndex = chain.colors.findIndex(c => equals(c, colorValue)); |
||||||
|
if (cvIndex >= 0) { |
||||||
|
chain.colors.splice(cvIndex, 1); |
||||||
|
} |
||||||
|
else { |
||||||
|
chain.colors.push(colorValue); |
||||||
|
} |
||||||
|
if (chain.colors.length == 0) { |
||||||
|
chain.colors.push(colorValue); |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
updateBackgroundSettings() { |
||||||
|
this.background.updateSettings(); |
||||||
|
} |
||||||
|
get center() { |
||||||
|
return p.createVector(p.width / 2, this.height / 2); |
||||||
|
} |
||||||
|
get height() { |
||||||
|
return p.height - this.containers[0].dim.y; |
||||||
|
} |
||||||
|
get currentContainers() { |
||||||
|
return this.containers.filter(c => { |
||||||
|
if (this.isTreeMode) |
||||||
|
return c.content instanceof Tree; |
||||||
|
if (this.isDecorationMode) |
||||||
|
return c.content instanceof Decoration; |
||||||
|
}); |
||||||
|
} |
||||||
|
update() { |
||||||
|
this.background.update(); |
||||||
|
this.switchButton.update(); |
||||||
|
this.downloadButton.update(); |
||||||
|
this.restoreButton.update(); |
||||||
|
this.currentContainers.forEach(c => c.update()); |
||||||
|
this.tree.update(); |
||||||
|
} |
||||||
|
display() { |
||||||
|
this.background.display(); |
||||||
|
this.switchButton.display(); |
||||||
|
this.downloadButton.display(); |
||||||
|
this.restoreButton.display(); |
||||||
|
this.currentContainers.forEach(c => c.display()); |
||||||
|
this.tree.display(); |
||||||
|
this.background.display(true); |
||||||
|
} |
||||||
|
//Always called
|
||||||
|
mousePressed() { |
||||||
|
this.tree.mousePressed(); |
||||||
|
this.currentContainers.forEach(c => c.mouseIsOver ? c.mousePressed() : null); |
||||||
|
this.switchButton.mouseIsOver ? this.switchButton.mousePressed() : null; |
||||||
|
this.downloadButton.mouseIsOver ? this.downloadButton.mousePressed() : null; |
||||||
|
this.restoreButton.mouseIsOver ? this.restoreButton.mousePressed() : null; |
||||||
|
} |
||||||
|
//Always called
|
||||||
|
mouseReleased() { |
||||||
|
this.tree.mouseReleased(); |
||||||
|
} |
||||||
|
restoreTrees(rawTrees) { |
||||||
|
this.trees.forEach((t, i) => { |
||||||
|
t.restoreFrom(rawTrees[i]); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
class Button { |
||||||
|
constructor(type) { |
||||||
|
this.pos = p.createVector(); |
||||||
|
this.dim = p.createVector(); |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
get mouseIsOver() { |
||||||
|
return p.mouseX > this.pos.x && p.mouseX < this.pos.x + this.dim.x && |
||||||
|
p.mouseY > this.pos.y && p.mouseY < this.pos.y + this.dim.y; |
||||||
|
} |
||||||
|
get center() { |
||||||
|
return p5.Vector.add(this.pos, p5.Vector.div(this.dim, 2)); |
||||||
|
} |
||||||
|
display() { |
||||||
|
let w = this.dim.x, h = this.dim.y; |
||||||
|
let x = this.pos.x + w / 2, y = this.pos.y + h / 2; |
||||||
|
p.image(images['box'], x, y, w, h); |
||||||
|
if (this.type === 'switch') { |
||||||
|
if (game.isTreeMode) { |
||||||
|
game.decorations[0].display(this.center, this.dim); |
||||||
|
} |
||||||
|
if (game.isDecorationMode) { |
||||||
|
let tree = game.tree; |
||||||
|
if (tree.isPlaceholder) |
||||||
|
tree = game.trees[0]; |
||||||
|
tree.display(this.center, this.dim); |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.type === 'download') { |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.textSize(25); |
||||||
|
p.fill(0); |
||||||
|
p.text("Save", this.pos.x, this.pos.y, this.dim.x, this.dim.y); |
||||||
|
} |
||||||
|
if (this.type === 'restore') { |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.textSize(20); |
||||||
|
p.fill(0); |
||||||
|
p.text("Restore", this.pos.x, this.pos.y, this.dim.x, this.dim.y); |
||||||
|
} |
||||||
|
if (this.mouseIsOver) { |
||||||
|
p.fill(0, 50); |
||||||
|
p.noStroke(); |
||||||
|
p.rect(x - w / 2, y - h / 2, w, h); |
||||||
|
} |
||||||
|
} |
||||||
|
update() { |
||||||
|
let w, h, x, y; |
||||||
|
if (this.type === 'switch') { |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = 0; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
if (this.type === 'download') { |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = p.width - w; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
if (this.type === 'restore') { |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = p.width - 2 * w; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
this.pos.set(x, y); |
||||||
|
this.dim.set(w, h); |
||||||
|
} |
||||||
|
mousePressed() { |
||||||
|
if (this.type === 'switch') { |
||||||
|
game.isDecorationMode = !game.isDecorationMode; |
||||||
|
game.isTreeMode = !game.isTreeMode; |
||||||
|
} |
||||||
|
if (this.type === 'download') { |
||||||
|
downloadTrees(); |
||||||
|
} |
||||||
|
if (this.type === 'restore') { |
||||||
|
$('#file_browser')[0].click(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=game.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,143 @@ |
|||||||
|
'use strict'; |
||||||
|
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { |
||||||
|
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } |
||||||
|
return new (P || (P = Promise))(function (resolve, reject) { |
||||||
|
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } |
||||||
|
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } |
||||||
|
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } |
||||||
|
step((generator = generator.apply(thisArg, _arguments || [])).next()); |
||||||
|
}); |
||||||
|
}; |
||||||
|
let debug = false, font, settings, loader; |
||||||
|
//Only for online games
|
||||||
|
let socket; |
||||||
|
let antiCacheQuery = '?_=' + new Date().getTime(); |
||||||
|
let game; |
||||||
|
let released = false; |
||||||
|
let images = {}; |
||||||
|
const p = new p5((p) => { |
||||||
|
p.preload = () => { |
||||||
|
settings = p.loadJSON('data/settings/settings.json' + antiCacheQuery, {}, 'json', (json) => { |
||||||
|
console.log('Local settings loaded: ', json); |
||||||
|
}, (error) => { |
||||||
|
console.log('Local settings failed: ', error); |
||||||
|
}); |
||||||
|
font = p.loadFont('data/styles/fonts/Tajawal/Tajawal-Regular.ttf' + antiCacheQuery, (font) => { |
||||||
|
console.log('Local font loaded: ', font); |
||||||
|
}, (error) => { |
||||||
|
console.log('Local font failed: ', error); |
||||||
|
}); |
||||||
|
images['ball'] = p.loadImage('data/images/ball.png' + antiCacheQuery, img => { |
||||||
|
console.log('Ball image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Ball image failed: ', error); |
||||||
|
}); |
||||||
|
images['box'] = p.loadImage('data/images/box.png' + antiCacheQuery, img => { |
||||||
|
console.log('Box image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Box image failed: ', error); |
||||||
|
}); |
||||||
|
}, |
||||||
|
p.setup = () => { |
||||||
|
interfaceSetup(); |
||||||
|
canvasSetup(); |
||||||
|
//loader = new Loader(p.createVector(p.width / 2, p.height / 2), Math.min(p.width, p.height) / 2);
|
||||||
|
loadDynamicScripts().then(() => { |
||||||
|
//Load other stuff, then =>
|
||||||
|
//loader = null;
|
||||||
|
game = new Game(); |
||||||
|
game.trees[0].container.mousePressed(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
p.draw = () => { |
||||||
|
p.clear(); |
||||||
|
if (game) { |
||||||
|
game.update(); |
||||||
|
game.display(); |
||||||
|
} |
||||||
|
if (loader) { |
||||||
|
loader.update(); |
||||||
|
loader.display(); |
||||||
|
} |
||||||
|
if (debug) |
||||||
|
debugInformation(); |
||||||
|
}; |
||||||
|
}); |
||||||
|
function debugInformation() { |
||||||
|
} |
||||||
|
function interfaceSetup() { |
||||||
|
let files_elem = $('#file_browser'); |
||||||
|
files_elem.on('change', () => { |
||||||
|
let file = files_elem.get(0).files[0]; |
||||||
|
file.text().then(text => { |
||||||
|
game.restoreTrees(JSON.parse(text)[0]); |
||||||
|
}); |
||||||
|
}); |
||||||
|
let colorSelect = $('#color'); |
||||||
|
let possibleColors = $('#possible_colors'); |
||||||
|
for (let colorName in settings.game.colors) { |
||||||
|
if (!settings.game.colors.hasOwnProperty(colorName)) |
||||||
|
continue; |
||||||
|
let publicName = colorName.substr(0, 1).toUpperCase() + colorName.substr(1); |
||||||
|
let option = $('<option></option>'); |
||||||
|
option.html(publicName); |
||||||
|
option.val("[" + settings.game.colors[colorName] + "]"); |
||||||
|
colorSelect.append(option); |
||||||
|
let checkbox = $('<input/>'); |
||||||
|
checkbox.attr({ |
||||||
|
type: 'checkbox', |
||||||
|
id: colorName |
||||||
|
}); |
||||||
|
checkbox.on('click', event => { |
||||||
|
if (game) { |
||||||
|
if (!game.updateChainSettings($(event.target))) { |
||||||
|
console.info('failed'); |
||||||
|
event.preventDefault(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
let label = $('<label></label>'); |
||||||
|
label.html(publicName); |
||||||
|
label.attr('for', colorName); |
||||||
|
possibleColors.append(checkbox, label); |
||||||
|
} |
||||||
|
} |
||||||
|
function downloadTrees() { |
||||||
|
let str = JSON.stringify(game.trees, (key, value) => { |
||||||
|
if (value instanceof p5.Vector) { |
||||||
|
return { |
||||||
|
x: value.x, |
||||||
|
y: value.y |
||||||
|
}; |
||||||
|
} |
||||||
|
return value; |
||||||
|
}); |
||||||
|
let data = 'data:application/json;charset=utf-8,[' + encodeURIComponent(str) + "]"; |
||||||
|
$("#save_link").attr("href", data); |
||||||
|
$("#save_link")[0].click(); |
||||||
|
} |
||||||
|
function canvasSetup() { |
||||||
|
p.frameRate(60); |
||||||
|
let w = $('#canvas_holder').width(), h = $('#canvas_holder').height(); |
||||||
|
let canvas = p.createCanvas(w, h); |
||||||
|
canvas.parent('canvas_holder'); |
||||||
|
p.textFont(font); |
||||||
|
p.imageMode(p.CENTER); |
||||||
|
} |
||||||
|
function loadDynamicScripts() { |
||||||
|
return __awaiter(this, void 0, void 0, function* () { |
||||||
|
const json = yield p.httpGet('data/settings/libraries.json' + antiCacheQuery, 'json'); |
||||||
|
let requests = []; |
||||||
|
for (let script in json) { |
||||||
|
if (json[script]) { |
||||||
|
let url = '/lib/benjocraeft/' + script + '.js'; |
||||||
|
requests.push($.getScript(url, () => { |
||||||
|
console.log('Successfully loaded script: ', url); |
||||||
|
})); |
||||||
|
} |
||||||
|
} |
||||||
|
yield $.when(...requests); |
||||||
|
console.log('All dynamic scripts have been loaded!'); |
||||||
|
}); |
||||||
|
} |
||||||
|
//# sourceMappingURL=init.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,40 @@ |
|||||||
|
"use strict"; |
||||||
|
class Loader { |
||||||
|
constructor(pos, radius) { |
||||||
|
this.pos = pos; |
||||||
|
this.c = p.createGraphics(radius * 2, radius * 2); |
||||||
|
this.radius = radius; |
||||||
|
this.center = p.createVector(radius, radius); |
||||||
|
this.message = 'Loading...'; |
||||||
|
this.progress = 0; |
||||||
|
this.angle = 0; |
||||||
|
} |
||||||
|
update() { |
||||||
|
this.angle += Math.PI / 10; |
||||||
|
} |
||||||
|
display() { |
||||||
|
let c = this.c; |
||||||
|
c.clear(); |
||||||
|
c.noFill(); |
||||||
|
c.stroke(20, 100, 200); |
||||||
|
c.strokeWeight(this.radius * 0.025); |
||||||
|
//c.arc(this.center.x, this.center.y, this.radius * 2, this.radius * 2, this.angle, this.angle + Math.PI * 1.5);
|
||||||
|
c.strokeWeight(2); |
||||||
|
c.rect(this.center.x - this.radius + 5, this.center.y - 25, this.radius * 2 - 50, 50); |
||||||
|
c.fill(50, 150, 255); |
||||||
|
c.rect(this.center.x - this.radius + 5, this.center.y - 25, (this.radius - 50) * this.progress, 50); |
||||||
|
c.textAlign(p.CENTER, p.CENTER); |
||||||
|
c.textSize(25); |
||||||
|
c.fill(220); |
||||||
|
c.strokeWeight(4); |
||||||
|
c.text(this.message, this.radius, this.radius * 1.5); |
||||||
|
c.textSize(40); |
||||||
|
c.text(Math.floor(this.progress * 100) + '%', this.radius, this.radius / 2); |
||||||
|
p.imageMode(p.CENTER); |
||||||
|
p.image(c, this.pos.x, this.pos.y); |
||||||
|
} |
||||||
|
destroy() { |
||||||
|
this.c.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=loader.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../ts/loader.ts"],"names":[],"mappings":";AAAA,MAAM,MAAM;IAUR,YAAY,GAAc,EAAE,MAAc;QACtC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;QACf,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;QAC7C,IAAI,CAAC,OAAO,GAAG,YAAY,CAAC;QAC5B,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC;QAClB,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,MAAM;QACF,IAAI,CAAC,KAAK,IAAI,IAAI,CAAC,EAAE,GAAG,EAAE,CAAC;IAC/B,CAAC;IAED,OAAO;QACH,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;QACf,CAAC,CAAC,KAAK,EAAE,CAAC;QACV,CAAC,CAAC,MAAM,EAAE,CAAC;QACX,CAAC,CAAC,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACvB,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,MAAM,GAAG,KAAK,CAAC,CAAC;QACpC,gHAAgH;QAChH,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC,CAAC;QACtF,CAAC,CAAC,IAAI,CAAC,EAAE,EAAE,GAAG,EAAE,GAAG,CAAC,CAAC;QACrB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,GAAG,EAAE,CAAC,GAAG,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC,CAAC;QAEpG,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAChC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACf,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACZ,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,GAAG,CAAC,CAAC;QAErD,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;QACf,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,GAAG,GAAG,CAAC,GAAG,GAAG,EAAE,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;QAE5E,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;QACtB,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACvC,CAAC;IAED,OAAO;QACH,IAAI,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACpB,CAAC;CAEJ"} |
@ -0,0 +1,9 @@ |
|||||||
|
'use strict'; |
||||||
|
function socketConnect(project, name = "noone") { |
||||||
|
let urlQueries = '?game=' + project.name + '&name=' + name; |
||||||
|
let port = 3000; |
||||||
|
let url = location.hostname + ":" + port + urlQueries; |
||||||
|
socket = io.connect(url); |
||||||
|
socket.on('connect', () => console.log('Connected to ', url)); |
||||||
|
} |
||||||
|
//# sourceMappingURL=online.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"online.js","sourceRoot":"","sources":["../ts/online.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,SAAS,aAAa,CAAC,OAAO,EAAE,IAAI,GAAG,OAAO;IAC1C,IAAI,UAAU,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,GAAG,IAAI,CAAC;IAC3D,IAAI,IAAI,GAAG,IAAI,CAAA;IACf,IAAI,GAAG,GAAG,QAAQ,CAAC,QAAQ,GAAG,GAAG,GAAG,IAAI,GAAG,UAAU,CAAC;IAEtD,MAAM,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,CAAC,EAAE,CAAC,SAAS,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,GAAG,CAAC,CAAC,CAAC;AAClE,CAAC"} |
@ -0,0 +1,72 @@ |
|||||||
|
"use strict"; |
||||||
|
class Star extends Decoration { |
||||||
|
constructor(properties) { |
||||||
|
super(properties); |
||||||
|
this.createTriangles(); |
||||||
|
} |
||||||
|
get properties() { |
||||||
|
let obj = super.properties; |
||||||
|
obj['raysCount'] = this.raysCount; |
||||||
|
obj['innerRadius'] = this.innerRadius; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
createTriangles() { |
||||||
|
this.triangles = []; |
||||||
|
let increment = p.TWO_PI / this.raysCount / 2, firstOuter = true; |
||||||
|
for (let i = 0; i < p.TWO_PI; i += increment) { |
||||||
|
let x1 = p.sin(i), y1 = -p.cos(i), x2 = p.sin(i + increment), y2 = -p.cos(i + increment); |
||||||
|
if (firstOuter) { |
||||||
|
x1 *= this.radius, |
||||||
|
y1 *= this.radius, |
||||||
|
x2 *= this.innerRadius, |
||||||
|
y2 *= this.innerRadius; |
||||||
|
} |
||||||
|
else { |
||||||
|
x2 *= this.radius, |
||||||
|
y2 *= this.radius, |
||||||
|
x1 *= this.innerRadius, |
||||||
|
y1 *= this.innerRadius; |
||||||
|
} |
||||||
|
firstOuter = !firstOuter; |
||||||
|
this.triangles.push([ |
||||||
|
p.createVector(x1, y1), |
||||||
|
p.createVector(x2, y2), |
||||||
|
p.createVector(0, 0) |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
brightness(value) { |
||||||
|
this.triangles.forEach((t, i) => { |
||||||
|
p.fill(0, 0, 0, value); |
||||||
|
p.triangle(t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y); |
||||||
|
}); |
||||||
|
} |
||||||
|
display(pos, dim) { |
||||||
|
super.display(pos, dim); |
||||||
|
p.noStroke(); |
||||||
|
this.triangles.forEach((t, i) => { |
||||||
|
let color = this.colors[i % this.colors.length]; |
||||||
|
p.fill(color); |
||||||
|
p.triangle(t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y); |
||||||
|
}); |
||||||
|
if (this.mouseIsOver) { |
||||||
|
this.brightness(70); |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
update() { |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
toJSON(index) { |
||||||
|
let list = [ |
||||||
|
"raysCount", |
||||||
|
"innerRadius" |
||||||
|
]; |
||||||
|
let obj = super.toJSON(index); |
||||||
|
for (let item of list) { |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=star.js.map
|
@ -0,0 +1 @@ |
|||||||
|
{"version":3,"file":"star.js","sourceRoot":"","sources":["../ts/star.ts"],"names":[],"mappings":";AAAA,MAAM,IAAK,SAAQ,UAAU;IAOzB,YAAY,UAAkB;QAC1B,KAAK,CAAC,UAAU,CAAC,CAAC;QAClB,IAAI,CAAC,eAAe,EAAE,CAAC;IAC3B,CAAC;IAED,IAAI,UAAU;QACV,IAAI,GAAG,GAAG,KAAK,CAAC,UAAU,CAAC;QAC3B,GAAG,CAAC,WAAW,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC;QAClC,GAAG,CAAC,aAAa,CAAC,GAAG,IAAI,CAAC,WAAW,CAAC;QACtC,OAAO,GAAG,CAAC;IACf,CAAC;IAED,eAAe;QACX,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACpB,IAAI,SAAS,GAAG,CAAC,CAAC,MAAM,GAAG,IAAI,CAAC,SAAS,GAAG,CAAC,EACzC,UAAU,GAAG,IAAI,CAAC;QACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,SAAS,EAAC;YACzC,IAAI,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EACb,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EACd,EAAE,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,EACzB,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAAG,SAAS,CAAC,CAAC;YAC/B,IAAI,UAAU,EAAC;gBACX,EAAE,IAAI,IAAI,CAAC,MAAM;oBACjB,EAAE,IAAI,IAAI,CAAC,MAAM;oBACjB,EAAE,IAAI,IAAI,CAAC,WAAW;oBACtB,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;aAC1B;iBAAM;gBACH,EAAE,IAAI,IAAI,CAAC,MAAM;oBACjB,EAAE,IAAI,IAAI,CAAC,MAAM;oBACjB,EAAE,IAAI,IAAI,CAAC,WAAW;oBACtB,EAAE,IAAI,IAAI,CAAC,WAAW,CAAC;aAC1B;YACD,UAAU,GAAG,CAAC,UAAU,CAAC;YACzB,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC;gBAChB,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC;gBACtB,CAAC,CAAC,YAAY,CAAC,EAAE,EAAE,EAAE,CAAC;gBACtB,CAAC,CAAC,YAAY,CAAC,CAAC,EAAE,CAAC,CAAC;aACvB,CAAC,CAAC;SACN;IACL,CAAC;IAED,UAAU,CAAC,KAAa;QACpB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5B,CAAC,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC;YACvB,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;IACP,CAAC;IAED,OAAO,CAAC,GAAe,EAAE,GAAe;QACpC,KAAK,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QAExB,CAAC,CAAC,QAAQ,EAAE,CAAC;QAEb,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;YAC5B,IAAI,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YACd,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC/D,CAAC,CAAC,CAAC;QACH,IAAI,IAAI,CAAC,WAAW,EAAC;YACjB,IAAI,CAAC,UAAU,CAAC,EAAE,CAAC,CAAC;SACvB;QAED,CAAC,CAAC,GAAG,EAAE,CAAC;IACZ,CAAC;IAED,MAAM;QACF,KAAK,CAAC,MAAM,EAAE,CAAC;IACnB,CAAC;IAED,MAAM,CAAC,KAAK;QACR,IAAI,IAAI,GAAG;YACP,WAAW;YACX,aAAa;SAChB,CAAA;QACD,IAAI,GAAG,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,KAAK,IAAI,IAAI,IAAI,IAAI,EAAC;YAClB,GAAG,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;SAC1B;QACD,OAAO,GAAG,CAAC;IACf,CAAC;CAEJ"} |
@ -0,0 +1,223 @@ |
|||||||
|
"use strict"; |
||||||
|
class Tree { |
||||||
|
constructor(properties) { |
||||||
|
this.pos = p.createVector(); |
||||||
|
this.sizeMultiplier = 1; |
||||||
|
this.animationProgress = 0; |
||||||
|
this.animationDirection = -1; |
||||||
|
this.decorations = []; |
||||||
|
if (properties == null) { |
||||||
|
this.isPlaceholder = true; |
||||||
|
} |
||||||
|
else { |
||||||
|
for (let key in properties) { |
||||||
|
this[key] = properties[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//Always called
|
||||||
|
mousePressed() { |
||||||
|
for (let d of [...this.decorations].reverse()) { |
||||||
|
if (d.mouseIsOver) { |
||||||
|
d.mousePressed(); |
||||||
|
let index = this.decorations.findIndex(deco => deco == d); |
||||||
|
this.decorations[index] = this.decorations[this.decorations.length - 1]; |
||||||
|
this.decorations[this.decorations.length - 1] = d; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//Always called
|
||||||
|
mouseReleased() { |
||||||
|
for (let d of this.decorations) { |
||||||
|
d.mouseReleased(); |
||||||
|
} |
||||||
|
} |
||||||
|
get smoothProgress() { |
||||||
|
return this.smoothStep(0, 1, this.animationProgress); |
||||||
|
} |
||||||
|
containsPosition(pos, excludeStem) { |
||||||
|
let size = game.height, x = (p.width - size) / 2; |
||||||
|
let px = pos.x, py = pos.y; |
||||||
|
let pixelColor = p.get(px, py).slice(0, 3); |
||||||
|
let colorIsValid = game.tree.getAllColors(excludeStem).find(c => equals(c, pixelColor)) != null; |
||||||
|
return colorIsValid && |
||||||
|
px > x && px < x + size && |
||||||
|
py > 0 && py < size - 20; |
||||||
|
} |
||||||
|
update() { |
||||||
|
this.animationProgress += 0.05 * this.animationDirection; |
||||||
|
this.animationProgress = this.animationProgress > 1 ? 1 : this.animationProgress < 0 ? 0 : this.animationProgress; |
||||||
|
if (this.isPlaceholder) { |
||||||
|
this.pos = game.center; |
||||||
|
this.sizeMultiplier = game.height * 0.05; |
||||||
|
} |
||||||
|
else { |
||||||
|
this.pos = p5.Vector.lerp(this.container.center, game.center, this.smoothProgress); |
||||||
|
this.sizeMultiplier = p.lerp(this.container.dim.y * 0.05, game.height * 0.05, this.smoothProgress); |
||||||
|
} |
||||||
|
this.decorations.forEach((d, i) => { |
||||||
|
if (d.isToDelete) { |
||||||
|
this.decorations.splice(i, 1); |
||||||
|
if (d instanceof Ball) { |
||||||
|
d.graphics.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
this.decorations.forEach(d => d.update()); |
||||||
|
} |
||||||
|
display(pos, dim) { |
||||||
|
let sizeMultiplier = this.sizeMultiplier; |
||||||
|
if (pos || dim) { |
||||||
|
sizeMultiplier = dim.y * 0.05; |
||||||
|
} |
||||||
|
else { |
||||||
|
pos = this.pos; |
||||||
|
} |
||||||
|
p.push(); |
||||||
|
p.translate(pos.x, pos.y); |
||||||
|
p.scale(sizeMultiplier); |
||||||
|
if (this.isPlaceholder) { |
||||||
|
p.fill(0); |
||||||
|
p.stroke(100, 220, 100); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.textSize(1); |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.text('Select your Christmas Tree!', 0, 0); |
||||||
|
} |
||||||
|
else { |
||||||
|
this.drawTree(); |
||||||
|
this.drawDecorations(); |
||||||
|
if (debug && this === game.tree) { |
||||||
|
p.stroke(255, 0, 0, 80); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
for (let i = -10; i <= 10; i++) { |
||||||
|
p.line(-10, i, 10, i); |
||||||
|
p.line(i, -10, i, 10); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
drawTree() { |
||||||
|
p.push(); |
||||||
|
p.translate(0, 1); |
||||||
|
p.fill(this.stemColor); |
||||||
|
p.stroke(0); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.rect(-this.stemRadius, 0, this.stemRadius * 2, this.stemHeight); |
||||||
|
let drawLeaf = (r, h) => { |
||||||
|
if (this.isSmooth) { |
||||||
|
let cps = [ |
||||||
|
p.createVector(40, 70), |
||||||
|
p.createVector(60, 90), |
||||||
|
p.createVector(100, 130), |
||||||
|
p.createVector(-100, 130), |
||||||
|
p.createVector(-60, 90), |
||||||
|
p.createVector(-40, 70) |
||||||
|
]; |
||||||
|
cps.forEach(c => { |
||||||
|
c.x *= r / 100; |
||||||
|
c.y *= h / 100; |
||||||
|
}); |
||||||
|
p.beginShape(); |
||||||
|
p.vertex(0, 0); |
||||||
|
p.bezierVertex(cps[0].x, cps[0].y, cps[1].x, cps[1].y, r, h); |
||||||
|
p.bezierVertex(cps[2].x, cps[2].y, cps[3].x, cps[3].y, -r, h); |
||||||
|
p.bezierVertex(cps[4].x, cps[4].y, cps[5].x, cps[5].y, 0, 0); |
||||||
|
p.endShape(); |
||||||
|
if (debug) { |
||||||
|
p.stroke(255, 0, 0); |
||||||
|
cps.forEach(c => p.ellipse(c.x, c.y, 0)); |
||||||
|
} |
||||||
|
} |
||||||
|
else { |
||||||
|
p.triangle(0, 0, r, h, -r, h); |
||||||
|
} |
||||||
|
}; |
||||||
|
for (let i = 0; i < this.leafCount; i++) { |
||||||
|
let y = -i * this.leafHeight / 2; |
||||||
|
let lr = this.leafRadius * (this.leafCount - i) / this.leafCount; |
||||||
|
p.push(); |
||||||
|
p.translate(0, y); |
||||||
|
p.fill(this.leafColors[i % this.leafColors.length]); |
||||||
|
drawLeaf(lr, this.leafHeight); |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
drawDecorations() { |
||||||
|
for (let d of this.decorations) { |
||||||
|
if (d.needsValidation) { |
||||||
|
if (!d.hasValidPosition) { |
||||||
|
d.isToDelete = true; |
||||||
|
} |
||||||
|
d.needsValidation = false; |
||||||
|
} |
||||||
|
} |
||||||
|
for (let d of this.decorations) { |
||||||
|
if (released && d.isBoundToMouse) { |
||||||
|
d.needsValidation = true; |
||||||
|
d.isBoundToMouse = false; |
||||||
|
if (d instanceof Chain) { |
||||||
|
d.p1IsBoundToMouse = false; |
||||||
|
d.p2IsBoundToMouse = false; |
||||||
|
} |
||||||
|
} |
||||||
|
d.display(); |
||||||
|
} |
||||||
|
} |
||||||
|
getAllColors(withoutStem) { |
||||||
|
let colors = []; |
||||||
|
colors.push(...this.leafColors, [0, 0, 0]); |
||||||
|
if (!withoutStem) { |
||||||
|
colors.push(this.stemColor); |
||||||
|
} |
||||||
|
return colors; |
||||||
|
} |
||||||
|
smoothStep(start, end, t) { |
||||||
|
function clamp(x, lowLimit, upLimit) { |
||||||
|
if (x < lowLimit) |
||||||
|
x = lowLimit; |
||||||
|
if (x > upLimit) |
||||||
|
x = upLimit; |
||||||
|
return x; |
||||||
|
} |
||||||
|
t = clamp((t - start) / (end - start), 0, 1); |
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10); |
||||||
|
} |
||||||
|
toJSON(index) { |
||||||
|
let list = [ |
||||||
|
"stemRadius", |
||||||
|
"leafCount", |
||||||
|
"leafColors", |
||||||
|
"stemColor", |
||||||
|
"stemHeight", |
||||||
|
"leafHeight", |
||||||
|
"leafRadius", |
||||||
|
"isSmooth", |
||||||
|
"isPlaceholder", |
||||||
|
"decorations" |
||||||
|
]; |
||||||
|
let obj = {}; |
||||||
|
for (let item of list) { |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
restoreFrom(rawTree) { |
||||||
|
for (let key in rawTree) { |
||||||
|
if (key === 'decorations') { |
||||||
|
this[key] = []; |
||||||
|
rawTree[key].forEach(rawDeco => { |
||||||
|
let deco = Decoration.restoreFrom(rawDeco); |
||||||
|
this[key].push(deco); |
||||||
|
}); |
||||||
|
} |
||||||
|
else { |
||||||
|
this[key] = rawTree[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
//# sourceMappingURL=tree.js.map
|
File diff suppressed because one or more lines are too long
@ -0,0 +1,189 @@ |
|||||||
|
let snowflake_max_r = 12; |
||||||
|
let snowflake_min_r = 7; |
||||||
|
let snowflake_max_count = 500; |
||||||
|
|
||||||
|
class Background{ |
||||||
|
|
||||||
|
bgColor: p5.Color = p.color(100, 100, 255); |
||||||
|
|
||||||
|
snowflakes: Snowflake[] |
||||||
|
foregroundSnowflakes: Snowflake[] |
||||||
|
backgroundSnowflakes: Snowflake[] |
||||||
|
wind_direction: number = 0 |
||||||
|
|
||||||
|
ground: Ground = new Ground() |
||||||
|
|
||||||
|
constructor() { |
||||||
|
this.snowflakes = []; |
||||||
|
for (let i = 0; i < snowflake_max_count; i++){ |
||||||
|
this.snowflakes.push(this.getNewSnowflake()); |
||||||
|
} |
||||||
|
this.snowflakes.sort((a, b) => { |
||||||
|
if (a.radius < b.radius){ |
||||||
|
return -1; |
||||||
|
} |
||||||
|
if (a.radius > b.radius){ |
||||||
|
return 1; |
||||||
|
} |
||||||
|
return 0; |
||||||
|
}); |
||||||
|
this.backgroundSnowflakes = this.snowflakes.slice(0, snowflake_max_count * 2 / 3); |
||||||
|
this.foregroundSnowflakes = this.snowflakes.slice(snowflake_max_count * 2 / 3, snowflake_max_count); |
||||||
|
this.updateSettings(); |
||||||
|
} |
||||||
|
|
||||||
|
getNewSnowflake(){ |
||||||
|
return new Snowflake( |
||||||
|
p.random(p.width), |
||||||
|
p.random(-snowflake_max_r, p.height), |
||||||
|
p.random(snowflake_min_r, snowflake_max_r), |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
updateSettings(){ |
||||||
|
let allowed_snowflakes_count = $('#snow_intensity').val() as number; |
||||||
|
let visible_snowflakes = p.shuffle(this.snowflakes.filter(s => !s.hidden)); |
||||||
|
let hidden_snowflakes = p.shuffle(this.snowflakes.filter(s => s.hidden)); |
||||||
|
let snowflakes_to_add = allowed_snowflakes_count - visible_snowflakes.length; |
||||||
|
if (snowflakes_to_add > 0){ |
||||||
|
for (let i = 0; i < snowflakes_to_add; i++){ |
||||||
|
hidden_snowflakes[i].hidden = false; |
||||||
|
} |
||||||
|
} |
||||||
|
if (snowflakes_to_add < 0){ |
||||||
|
for (let i = 0; i < p.abs(snowflakes_to_add); i++){ |
||||||
|
visible_snowflakes[i].hidden = true; |
||||||
|
} |
||||||
|
} |
||||||
|
this.bgColor.setBlue( |
||||||
|
p.map( |
||||||
|
allowed_snowflakes_count, |
||||||
|
0, snowflake_max_count, |
||||||
|
255, 170 |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
this.ground.update(); |
||||||
|
this.wind_direction = p.sin(p.frameCount / 1000); |
||||||
|
this.snowflakes.forEach(s => s.update(this.wind_direction)); |
||||||
|
} |
||||||
|
|
||||||
|
display(asForeground?: boolean){ |
||||||
|
if (asForeground){ |
||||||
|
this.foregroundSnowflakes.forEach(s => s.display()); |
||||||
|
} else { |
||||||
|
p.background(this.bgColor); |
||||||
|
this.ground.display(); |
||||||
|
this.backgroundSnowflakes.forEach(s => s.display()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class Snowflake{ |
||||||
|
|
||||||
|
pos: p5.Vector |
||||||
|
radius: number |
||||||
|
alpha: number |
||||||
|
hidden: boolean |
||||||
|
rotateDir: number |
||||||
|
rotation: number = 0 |
||||||
|
peakCount: number |
||||||
|
|
||||||
|
constructor(x, y, r) { |
||||||
|
this.pos = p.createVector(x, y); |
||||||
|
this.radius = r; |
||||||
|
this.hidden = false; |
||||||
|
this.alpha = 0; |
||||||
|
this.rotateDir = p.random([-1, 1]) * p.random(0.01, 0.03); |
||||||
|
this.peakCount = p.random([4, 5, 6]); |
||||||
|
} |
||||||
|
|
||||||
|
update(wind_direction: number){ |
||||||
|
let dir = p.createVector( |
||||||
|
p.map(this.radius, snowflake_min_r, snowflake_max_r, 0, 1) * wind_direction, |
||||||
|
p.map(this.radius, snowflake_min_r, snowflake_max_r, 0.5, 1) * 2 |
||||||
|
); |
||||||
|
this.pos.add(dir); |
||||||
|
this.rotation += this.rotateDir; |
||||||
|
if (this.pos.y > p.height + this.radius){ |
||||||
|
this.pos.y = -this.radius; |
||||||
|
} |
||||||
|
if (this.pos.x > p.width + this.radius){ |
||||||
|
this.pos.x = -this.radius; |
||||||
|
} else if (this.pos.x < -this.radius){ |
||||||
|
this.pos.x = p.width + this.radius; |
||||||
|
} |
||||||
|
if (this.hidden && this.alpha > 0){ |
||||||
|
this.alpha -= 0.015; |
||||||
|
} else if (this.alpha < 1){ |
||||||
|
this.alpha += 0.015; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
p.push(); |
||||||
|
p.strokeWeight(1); |
||||||
|
p.stroke(255, this.alpha * 255); |
||||||
|
p.fill(255, this.alpha * 255); |
||||||
|
p.translate(this.pos); |
||||||
|
p.rotate(this.rotation % p.TWO_PI); |
||||||
|
|
||||||
|
for (let rad = 0; rad < p.PI; rad += p.PI / this.peakCount){ |
||||||
|
let x1 = p.cos(rad) * this.radius; |
||||||
|
let y1 = p.sin(rad) * this.radius; |
||||||
|
let x2 = p.cos(rad + p.PI) * this.radius; |
||||||
|
let y2 = p.sin(rad + p.PI) * this.radius; |
||||||
|
p.line(x1, y1, x2, y2); |
||||||
|
} |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class Ground{ |
||||||
|
|
||||||
|
points: p5.Vector[] |
||||||
|
|
||||||
|
constructor() { |
||||||
|
this.createPoints(); |
||||||
|
} |
||||||
|
|
||||||
|
createPoints(){ |
||||||
|
this.points = []; |
||||||
|
for (let x = 0; x < p.width; x++){ |
||||||
|
let vector = p.createVector( |
||||||
|
x, |
||||||
|
p.noise(x / 300) * 150 |
||||||
|
); |
||||||
|
this.points.push(vector); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
p.push(); |
||||||
|
p.fill(220, 220, 255); |
||||||
|
p.stroke(50, 50, 150); |
||||||
|
p.strokeWeight(2); |
||||||
|
p.beginShape(); |
||||||
|
|
||||||
|
for (let point of this.points){ |
||||||
|
p.vertex(point.x, point.y + p.height / 2); |
||||||
|
} |
||||||
|
p.vertex(p.width, p.height); |
||||||
|
p.vertex(0, p.height); |
||||||
|
|
||||||
|
p.endShape(p.CLOSE); |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
@ -0,0 +1,39 @@ |
|||||||
|
class Ball extends Decoration{ |
||||||
|
|
||||||
|
graphics: p5.Graphics |
||||||
|
|
||||||
|
constructor(properties: object){ |
||||||
|
super(properties); |
||||||
|
this.createGraphics(); |
||||||
|
} |
||||||
|
|
||||||
|
createGraphics(){ |
||||||
|
let img = images['ball']; |
||||||
|
this.graphics = p.createGraphics(img.width, img.height); |
||||||
|
this.updateColor(); |
||||||
|
} |
||||||
|
|
||||||
|
updateColor(){ |
||||||
|
let img = images['ball']; |
||||||
|
this.graphics.clear(); |
||||||
|
this.graphics.tint(this.colors[0]); |
||||||
|
this.graphics.image(img, 0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
display(pos?: p5.Vector, dim?: p5.Vector){ |
||||||
|
super.display(pos, dim); |
||||||
|
|
||||||
|
p.image(this.graphics, 0, 0, this.radius * 2, this.radius * 2); |
||||||
|
if (this.mouseIsOver){ |
||||||
|
this.brightness(70); |
||||||
|
} |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,167 @@ |
|||||||
|
import has = Reflect.has; |
||||||
|
|
||||||
|
class Chain extends Decoration{ |
||||||
|
|
||||||
|
p1: p5.Vector = p.createVector(-0.65, 0) |
||||||
|
p2: p5.Vector = p.createVector(0.65, 0) |
||||||
|
|
||||||
|
p1IsBoundToMouse: boolean = false |
||||||
|
p2IsBoundToMouse: boolean = false |
||||||
|
|
||||||
|
placedOnce: boolean = false |
||||||
|
|
||||||
|
points: {x: number, y: number}[] = [] |
||||||
|
lights: {x: number, y: number}[] = [] |
||||||
|
|
||||||
|
constructor(properties: object){ |
||||||
|
super(properties); |
||||||
|
this.generate(); |
||||||
|
} |
||||||
|
|
||||||
|
get properties(): object{ |
||||||
|
let obj = super.properties; |
||||||
|
obj['p1'] = this.p1; |
||||||
|
obj['p2'] = this.p2; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
generate(){ |
||||||
|
let d = p.dist(this.p1.x, this.p1.y, this.p2.x, this.p2.y); |
||||||
|
let m = p.abs((this.p2.y - this.p1.y) / (this.p2.x - this.p1.x)); |
||||||
|
let a = -1 / d - m / 10; |
||||||
|
|
||||||
|
let b = (this.p1.y - this.p2.y + a * p.pow(this.p2.x, 2) - a * p.pow(this.p1.x, 2)) / |
||||||
|
(this.p1.x - this.p2.x); |
||||||
|
if (this.p1.x - this.p2.x === 0) |
||||||
|
b = 0; |
||||||
|
let c = this.p1.y - a * p.pow(this.p1.x, 2) - b * this.p1.x; |
||||||
|
let func = x => a * x * x + b * x + c; |
||||||
|
|
||||||
|
let detail = 40; |
||||||
|
let points = []; |
||||||
|
for (let i = 0; i <= detail; i++){ |
||||||
|
let point = {x: 0, y: 0}; |
||||||
|
point.x = this.p1.x + (this.p2.x - this.p1.x) / detail * i; |
||||||
|
point.y = func(point.x); |
||||||
|
points.push(point); |
||||||
|
} |
||||||
|
let lightDist = 0.35; |
||||||
|
let lastLight = {x: Infinity, y: Infinity}; |
||||||
|
let lights = [] |
||||||
|
detail = 300; |
||||||
|
for (let i = 0; i <= detail; i++){ |
||||||
|
let point = {x: 0, y: 0, hasLight: false}; |
||||||
|
point.x = this.p1.x + (this.p2.x - this.p1.x) / detail * i; |
||||||
|
point.y = func(point.x); |
||||||
|
if (p.dist(point.x, point.y, lastLight.x, lastLight.y) >= lightDist){ |
||||||
|
lights.push(point); |
||||||
|
lastLight = point; |
||||||
|
} |
||||||
|
} |
||||||
|
this.points = points; |
||||||
|
this.lights = lights; |
||||||
|
} |
||||||
|
|
||||||
|
display(pos?: p5.Vector, dim?: p5.Vector){ |
||||||
|
super.display(pos, dim); |
||||||
|
|
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.stroke(0); |
||||||
|
p.noFill(); |
||||||
|
p.beginShape(); |
||||||
|
for (let point of this.points) |
||||||
|
p.vertex(point.x, point.y); |
||||||
|
p.endShape(); |
||||||
|
|
||||||
|
p.strokeWeight(0.01); |
||||||
|
let i = 0; |
||||||
|
for (let point of this.lights){ |
||||||
|
let colorIndex = (i + p.int(p.frameCount / 30)) % this.colors.length; |
||||||
|
p.fill(this.colors[colorIndex]); |
||||||
|
p.ellipse(point.x, point.y, 0.2, 0.2); |
||||||
|
i++; |
||||||
|
} |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
get hasValidPosition(): boolean{ |
||||||
|
return game.tree.containsPosition(this.realPosByAnchor(this.p1), true) |
||||||
|
&& game.tree.containsPosition(this.realPosByAnchor(this.p2), true); |
||||||
|
} |
||||||
|
|
||||||
|
realPosByAnchor(anchor): p5.Vector{ |
||||||
|
return p5.Vector.add(p5.Vector.mult(p5.Vector.add(this.pos, anchor), game.tree.sizeMultiplier), game.center); |
||||||
|
} |
||||||
|
|
||||||
|
realPointDistToAnchor(point, anchor){ |
||||||
|
let pos = this.realPosByAnchor(anchor); |
||||||
|
return p.dist(pos.x, pos.y, point.x, point.y); |
||||||
|
} |
||||||
|
|
||||||
|
isMouseOverAnchor(anchor){ |
||||||
|
return this.realPointDistToAnchor(p.createVector(p.mouseX, p.mouseY), anchor) <= 0.5 * game.tree.sizeMultiplier; |
||||||
|
} |
||||||
|
|
||||||
|
get mouseIsOver(): boolean{ |
||||||
|
return this.isTaken && (this.isMouseOverAnchor(this.p1) || this.isMouseOverAnchor(this.p2)); |
||||||
|
} |
||||||
|
|
||||||
|
//Mouse is over this
|
||||||
|
mousePressed() { |
||||||
|
super.mousePressed(); |
||||||
|
if (this.isMouseOverAnchor(this.p1)){ |
||||||
|
this.p1IsBoundToMouse = true; |
||||||
|
} else if (this.isMouseOverAnchor(this.p2)){ |
||||||
|
this.p2IsBoundToMouse = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
updateFromPoint(point, other, x, y){ |
||||||
|
if (this.placedOnce){ |
||||||
|
let pointRelative = p.createVector(x - this.pos.x, y - this.pos.y); |
||||||
|
point.set(pointRelative); |
||||||
|
let pointReal = p5.Vector.add(this.pos, point); |
||||||
|
let otherReal = p5.Vector.add(this.pos, other); |
||||||
|
let newPos = p5.Vector.div(p5.Vector.add(pointReal, otherReal), 2); |
||||||
|
point.set(p5.Vector.sub(pointReal, newPos)); |
||||||
|
other.set(p5.Vector.mult(point, -1)); |
||||||
|
this.pos.set(newPos); |
||||||
|
} else { |
||||||
|
this.pos.set(x - point.x, y - point.y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
let x = (p.mouseX - game.center.x) / game.tree.sizeMultiplier, |
||||||
|
y = (p.mouseY - game.center.y) / game.tree.sizeMultiplier; |
||||||
|
if (this.isBoundToMouse){ |
||||||
|
if (this.p1IsBoundToMouse){ |
||||||
|
this.updateFromPoint(this.p1, this.p2, x, y); |
||||||
|
} |
||||||
|
if (this.p2IsBoundToMouse){ |
||||||
|
this.updateFromPoint(this.p2, this.p1, x, y); |
||||||
|
} |
||||||
|
this.generate(); |
||||||
|
} else { |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.isTaken && !this.isBoundToMouse){ |
||||||
|
this.placedOnce = true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
toJSON(index){ |
||||||
|
let list = [ |
||||||
|
"p1", |
||||||
|
"p2" |
||||||
|
] |
||||||
|
let obj = super.toJSON(index); |
||||||
|
for (let item of list){ |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,84 @@ |
|||||||
|
class Container{ |
||||||
|
|
||||||
|
index: number |
||||||
|
pos: p5.Vector = p.createVector() |
||||||
|
dim: p5.Vector = p.createVector() |
||||||
|
|
||||||
|
content: Tree | Decoration |
||||||
|
|
||||||
|
constructor(index: number, content: Tree | Decoration){ |
||||||
|
this.index = index; |
||||||
|
this.content = content; |
||||||
|
} |
||||||
|
|
||||||
|
get mouseIsOver(): boolean{ |
||||||
|
return p.mouseX > this.pos.x && p.mouseX < this.pos.x + this.dim.x && |
||||||
|
p.mouseY > this.pos.y && p.mouseY < this.pos.y + this.dim.y; |
||||||
|
} |
||||||
|
|
||||||
|
get center(): p5.Vector{ |
||||||
|
return p5.Vector.add(this.pos, p5.Vector.div(this.dim, 2)); |
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
let w = this.dim.x, |
||||||
|
h = this.dim.y; |
||||||
|
let x = this.pos.x + w / 2, |
||||||
|
y = this.pos.y + h / 2; |
||||||
|
p.image(images['box'], x, y, w, h); |
||||||
|
|
||||||
|
if (this.content !== game.tree){ |
||||||
|
this.content.display(); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.mouseIsOver){ |
||||||
|
p.fill(0, 50); |
||||||
|
p.noStroke(); |
||||||
|
p.rect(x - w / 2, y - h / 2, w , h); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
let currentCount = game.currentContainers.length; |
||||||
|
let w = p.width / currentCount, |
||||||
|
h = w; |
||||||
|
let x = w * this.index, |
||||||
|
y = p.height - h; |
||||||
|
if (this.content instanceof Decoration){ |
||||||
|
let otherCount = game.containers.filter(c => game.currentContainers.find(ic => ic == c) == null).length; |
||||||
|
w = h = p.width / otherCount; |
||||||
|
x = w * this.index; |
||||||
|
y = p.height - h; |
||||||
|
x += p.width / 2 - w * currentCount / 2; |
||||||
|
} |
||||||
|
this.pos.set(x, y); |
||||||
|
this.dim.set(w, h); |
||||||
|
|
||||||
|
if (this.content !== game.tree) |
||||||
|
this.content.update(); |
||||||
|
} |
||||||
|
|
||||||
|
mousePressed(){ |
||||||
|
if (this.content instanceof Tree){ |
||||||
|
game.tree.animationDirection = -1; |
||||||
|
if (this.content === game.tree){ |
||||||
|
game.tree = new Tree(null); |
||||||
|
} else { |
||||||
|
game.tree = this.content; |
||||||
|
game.tree.animationDirection = 1; |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.content instanceof Decoration && !game.tree.isPlaceholder){ |
||||||
|
let decoration = Decoration.Create(this.content.properties); |
||||||
|
decoration.isTaken = true; |
||||||
|
decoration.isBoundToMouse = true; |
||||||
|
game.tree.decorations.push(decoration); |
||||||
|
|
||||||
|
if (decoration instanceof Chain){ |
||||||
|
decoration.p1IsBoundToMouse = true; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,194 @@ |
|||||||
|
class Decoration{ |
||||||
|
|
||||||
|
pos: p5.Vector = p.createVector() |
||||||
|
colors: number[][] |
||||||
|
radius: number |
||||||
|
|
||||||
|
sizeMultiplier: number |
||||||
|
container: Container |
||||||
|
|
||||||
|
isTaken: boolean = false |
||||||
|
isBoundToMouse: boolean = false; |
||||||
|
isToDelete: boolean = false; |
||||||
|
needsValidation: boolean = false; |
||||||
|
|
||||||
|
isSelected: boolean = false; |
||||||
|
|
||||||
|
type: string |
||||||
|
|
||||||
|
constructor(properties: object){ |
||||||
|
for (let key in properties){ |
||||||
|
if (properties.hasOwnProperty(key)){ |
||||||
|
if (Array.isArray(properties[key])){ |
||||||
|
this[key] = arrayCopy(properties[key]); |
||||||
|
} else { |
||||||
|
this[key] = properties[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
get properties(): object{ |
||||||
|
let colors = []; |
||||||
|
for (let i = 0; i < this.colors.length; i++){ |
||||||
|
let color = []; |
||||||
|
for (let c of this.colors[i]){ |
||||||
|
color.push(c); |
||||||
|
} |
||||||
|
colors.push(color); |
||||||
|
} |
||||||
|
return { |
||||||
|
radius: this.radius, |
||||||
|
colors: colors, |
||||||
|
type: this.type |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
get mouseIsOver(): boolean{ |
||||||
|
if (this.isTaken){ |
||||||
|
let pos = this.realPos; |
||||||
|
return p.dist(pos.x, pos.y, p.mouseX, p.mouseY) <= this.radius * game.tree.sizeMultiplier; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
get hasValidPosition(): boolean{ |
||||||
|
return game.tree.containsPosition(this.realPos, true); |
||||||
|
} |
||||||
|
|
||||||
|
get realPos(): p5.Vector{ |
||||||
|
return p5.Vector.add(p5.Vector.mult(this.pos, game.tree.sizeMultiplier), game.center); |
||||||
|
} |
||||||
|
|
||||||
|
static Create(properties: object): Decoration{ |
||||||
|
switch (properties['type']){ |
||||||
|
case 'ball': |
||||||
|
return new Ball(properties); |
||||||
|
case 'star': |
||||||
|
return new Star(properties); |
||||||
|
case 'chain': |
||||||
|
return new Chain(properties); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
display(pos?: p5.Vector, dim?: p5.Vector){ |
||||||
|
let sizeMultiplier = this.sizeMultiplier; |
||||||
|
if (pos || dim){ |
||||||
|
sizeMultiplier = dim.y * 0.6; |
||||||
|
} else { |
||||||
|
pos = this.pos; |
||||||
|
} |
||||||
|
p.push(); |
||||||
|
p.translate(pos); |
||||||
|
p.scale(sizeMultiplier); |
||||||
|
} |
||||||
|
|
||||||
|
brightness(value: number){ |
||||||
|
p.noStroke(); |
||||||
|
p.fill(0, 0, 0, value); |
||||||
|
p.ellipse(0, 0, this.radius * 2, this.radius * 2); |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
if (!this.isTaken){ |
||||||
|
this.pos = this.container.center; |
||||||
|
this.sizeMultiplier = this.container.dim.y * 0.6; |
||||||
|
} else { |
||||||
|
this.sizeMultiplier = 1; |
||||||
|
} |
||||||
|
if (this.isBoundToMouse){ |
||||||
|
let x = (p.mouseX - game.center.x) / game.tree.sizeMultiplier, |
||||||
|
y = (p.mouseY - game.center.y) / game.tree.sizeMultiplier; |
||||||
|
this.pos.set(x, y); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//Assumes mouse is over this
|
||||||
|
mousePressed(){ |
||||||
|
this.isBoundToMouse = true; |
||||||
|
} |
||||||
|
|
||||||
|
//Always called
|
||||||
|
mouseReleased(){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
toJSON(index){ |
||||||
|
let list = [ |
||||||
|
"pos", |
||||||
|
"colors", |
||||||
|
"radius", |
||||||
|
"type" |
||||||
|
] |
||||||
|
let obj = {}; |
||||||
|
for (let item of list){ |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
static restoreFrom(rawDeco: object){ |
||||||
|
let props = {}; |
||||||
|
for (let key in rawDeco){ |
||||||
|
if (['pos', 'p1', 'p2'].find(s => s === key) === undefined){ |
||||||
|
props[key] = rawDeco[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
let deco = Decoration.Create(props); |
||||||
|
deco.isTaken = true; |
||||||
|
deco.pos.x = rawDeco['pos'].x; |
||||||
|
deco.pos.y = rawDeco['pos'].y; |
||||||
|
|
||||||
|
if (deco instanceof Chain){ |
||||||
|
deco.p1.set(rawDeco['p1'].x, rawDeco['p1'].y); |
||||||
|
deco.p2.set(rawDeco['p2'].x, rawDeco['p2'].y); |
||||||
|
deco.generate(); |
||||||
|
} |
||||||
|
|
||||||
|
return deco; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function darker(c){ |
||||||
|
let newC = [] |
||||||
|
for (let v of c){ |
||||||
|
newC.push(p.constrain(v * 0.6, 0, 255)); |
||||||
|
} |
||||||
|
return newC; |
||||||
|
} |
||||||
|
|
||||||
|
function arrayCopy(a){ |
||||||
|
let newArr = []; |
||||||
|
for (let c of a){ |
||||||
|
let copy = c; |
||||||
|
if (Array.isArray(c)){ |
||||||
|
copy = arrayCopy(c); |
||||||
|
} |
||||||
|
newArr.push(copy); |
||||||
|
} |
||||||
|
return newArr; |
||||||
|
} |
||||||
|
|
||||||
|
function equals(a1, a2){ |
||||||
|
// if the other array is a falsy value, return
|
||||||
|
if (!a1) |
||||||
|
return false; |
||||||
|
|
||||||
|
// compare lengths - can save a lot of time
|
||||||
|
if (a2.length != a1.length) |
||||||
|
return false; |
||||||
|
|
||||||
|
for (let i = 0, l=a2.length; i < l; i++) { |
||||||
|
// Check if we have nested arrays
|
||||||
|
if (a2[i] instanceof Array && a1[i] instanceof Array) { |
||||||
|
// recurse into the nested arrays
|
||||||
|
if (!a2[i].equals(a1[i])) |
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else if (a2[i] != a1[i]) {
|
||||||
|
// Warning - two different object instances will never be equal: {x:20} != {x:20}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true; |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,30 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
p.keyPressed = () => { |
||||||
|
switch (p.keyCode){ |
||||||
|
//Ctrl + D
|
||||||
|
case 68: |
||||||
|
if (p.keyIsDown(17)){ |
||||||
|
debug = !debug; |
||||||
|
let msg = 'Debug mode turned ' + (debug ? 'ON' : 'OFF'); |
||||||
|
console.info(msg); |
||||||
|
return false; |
||||||
|
} |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
p.mousePressed = () => { |
||||||
|
game.mousePressed(); |
||||||
|
released = false; |
||||||
|
} |
||||||
|
p.mouseReleased = () => { |
||||||
|
game.mouseReleased(); |
||||||
|
released = true; |
||||||
|
} |
||||||
|
|
||||||
|
p.windowResized = () => { |
||||||
|
let w = $('#canvas_holder').width(), |
||||||
|
h = $('#canvas_holder').height(); |
||||||
|
p.resizeCanvas(w, h); |
||||||
|
} |
@ -0,0 +1,261 @@ |
|||||||
|
class Game{ |
||||||
|
|
||||||
|
trees: Tree[] = [] |
||||||
|
tree: Tree = new Tree(null) |
||||||
|
|
||||||
|
decorations: Decoration[] = [] |
||||||
|
|
||||||
|
containers: Container[] = [] |
||||||
|
|
||||||
|
isTreeMode: boolean = true |
||||||
|
isDecorationMode: boolean = false |
||||||
|
|
||||||
|
barHeight: number |
||||||
|
|
||||||
|
switchButton: Button = new Button('switch') |
||||||
|
downloadButton: Button = new Button('download') |
||||||
|
restoreButton: Button = new Button('restore') |
||||||
|
|
||||||
|
background: Background = new Background() |
||||||
|
|
||||||
|
constructor(){ |
||||||
|
settings.game.trees.forEach((s: object) => this.trees.push(new Tree(s))); |
||||||
|
let red = settings.game.colors.red; |
||||||
|
this.decorations = [ |
||||||
|
Decoration.Create({ |
||||||
|
type: "ball", radius: 0.45, colors: [red] |
||||||
|
}), |
||||||
|
Decoration.Create({ |
||||||
|
type: "star", radius: 0.45, colors: [red, darker(red)] |
||||||
|
}), |
||||||
|
Decoration.Create({ |
||||||
|
type: "chain", radius: 0.45, colors: [ |
||||||
|
settings.game.colors.gold, |
||||||
|
settings.game.colors.silver |
||||||
|
] |
||||||
|
}), |
||||||
|
]; |
||||||
|
$('#gold, #silver').attr('checked', 'checked'); |
||||||
|
this.trees.forEach((t, i) => { |
||||||
|
let c = new Container(i, t); |
||||||
|
this.containers.push(c); |
||||||
|
t.container = c; |
||||||
|
}); |
||||||
|
this.decorations.forEach((d, i) => { |
||||||
|
let c = new Container(i, d); |
||||||
|
this.containers.push(c); |
||||||
|
d.container = c; |
||||||
|
}); |
||||||
|
this.updateDecorationSettings(); |
||||||
|
this.updateStarSettings(); |
||||||
|
} |
||||||
|
|
||||||
|
updateDecorationSettings(){ |
||||||
|
this.decorations.filter(d => d instanceof Ball || d instanceof Star).forEach(d => { |
||||||
|
d.radius = $('#radius').val() as number / 100 * 0.7; |
||||||
|
let colors = []; |
||||||
|
colors.push(JSON.parse($('#color').val() as string)); |
||||||
|
if (d instanceof Ball){ |
||||||
|
d.colors = colors; |
||||||
|
d.updateColor(); |
||||||
|
} |
||||||
|
if (d instanceof Star){ |
||||||
|
d.innerRadius = $('#inner_radius').val() as number * d.radius; |
||||||
|
colors.push(darker(colors[0])); |
||||||
|
d.colors = colors; |
||||||
|
d.createTriangles(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
updateStarSettings(){ |
||||||
|
this.decorations.filter(d => d instanceof Star).forEach((s: Star) => { |
||||||
|
s.innerRadius = $('#inner_radius').val() as number * s.radius; |
||||||
|
s.raysCount = parseInt($('#rays_count').val() as string); |
||||||
|
s.createTriangles(); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
updateChainSettings(element: JQuery): boolean{ |
||||||
|
let chain = this.decorations.find(d => d instanceof Chain); |
||||||
|
let colorName = element.attr('id'); |
||||||
|
let colorValue = settings.game.colors[colorName]; |
||||||
|
|
||||||
|
let cvIndex = chain.colors.findIndex(c => equals(c, colorValue)); |
||||||
|
if (cvIndex >= 0){ |
||||||
|
chain.colors.splice(cvIndex, 1); |
||||||
|
} else { |
||||||
|
chain.colors.push(colorValue); |
||||||
|
} |
||||||
|
|
||||||
|
if (chain.colors.length == 0){ |
||||||
|
chain.colors.push(colorValue); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
updateBackgroundSettings(){ |
||||||
|
this.background.updateSettings(); |
||||||
|
} |
||||||
|
|
||||||
|
get center(): p5.Vector{ |
||||||
|
return p.createVector(p.width / 2, this.height / 2); |
||||||
|
} |
||||||
|
|
||||||
|
get height(): number{ |
||||||
|
return p.height - this.containers[0].dim.y; |
||||||
|
} |
||||||
|
|
||||||
|
get currentContainers(): Container[]{ |
||||||
|
return this.containers.filter(c => { |
||||||
|
if (this.isTreeMode) |
||||||
|
return c.content instanceof Tree |
||||||
|
if (this.isDecorationMode) |
||||||
|
return c.content instanceof Decoration |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
this.background.update(); |
||||||
|
this.switchButton.update(); |
||||||
|
this.downloadButton.update(); |
||||||
|
this.restoreButton.update(); |
||||||
|
this.currentContainers.forEach(c => c.update()); |
||||||
|
this.tree.update(); |
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
this.background.display(); |
||||||
|
this.switchButton.display(); |
||||||
|
this.downloadButton.display(); |
||||||
|
this.restoreButton.display(); |
||||||
|
this.currentContainers.forEach(c => c.display()); |
||||||
|
this.tree.display(); |
||||||
|
this.background.display(true); |
||||||
|
} |
||||||
|
|
||||||
|
//Always called
|
||||||
|
mousePressed(){ |
||||||
|
this.tree.mousePressed(); |
||||||
|
this.currentContainers.forEach(c => c.mouseIsOver ? c.mousePressed() : null); |
||||||
|
this.switchButton.mouseIsOver ? this.switchButton.mousePressed() : null; |
||||||
|
this.downloadButton.mouseIsOver ? this.downloadButton.mousePressed() : null; |
||||||
|
this.restoreButton.mouseIsOver ? this.restoreButton.mousePressed() : null; |
||||||
|
} |
||||||
|
|
||||||
|
//Always called
|
||||||
|
mouseReleased(){ |
||||||
|
this.tree.mouseReleased(); |
||||||
|
} |
||||||
|
|
||||||
|
restoreTrees(rawTrees: object[]){ |
||||||
|
this.trees.forEach((t, i) => { |
||||||
|
t.restoreFrom(rawTrees[i]); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
class Button{ |
||||||
|
|
||||||
|
pos: p5.Vector = p.createVector() |
||||||
|
dim: p5.Vector = p.createVector() |
||||||
|
|
||||||
|
type: string |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
constructor(type: string){ |
||||||
|
this.type = type; |
||||||
|
} |
||||||
|
|
||||||
|
get mouseIsOver(): boolean{ |
||||||
|
return p.mouseX > this.pos.x && p.mouseX < this.pos.x + this.dim.x && |
||||||
|
p.mouseY > this.pos.y && p.mouseY < this.pos.y + this.dim.y; |
||||||
|
} |
||||||
|
|
||||||
|
get center(): p5.Vector{ |
||||||
|
return p5.Vector.add(this.pos, p5.Vector.div(this.dim, 2)); |
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
let w = this.dim.x, |
||||||
|
h = this.dim.y; |
||||||
|
let x = this.pos.x + w / 2, |
||||||
|
y = this.pos.y + h / 2; |
||||||
|
p.image(images['box'], x, y, w, h); |
||||||
|
|
||||||
|
if (this.type === 'switch'){ |
||||||
|
if (game.isTreeMode){ |
||||||
|
game.decorations[0].display(this.center, this.dim); |
||||||
|
} |
||||||
|
if (game.isDecorationMode){ |
||||||
|
let tree = game.tree; |
||||||
|
if (tree.isPlaceholder) |
||||||
|
tree = game.trees[0]; |
||||||
|
tree.display(this.center, this.dim); |
||||||
|
} |
||||||
|
} |
||||||
|
if (this.type === 'download'){ |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.textSize(25); |
||||||
|
p.fill(0); |
||||||
|
p.text("Save", this.pos.x, this.pos.y, this.dim.x, this.dim.y); |
||||||
|
} |
||||||
|
if (this.type === 'restore'){ |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.textSize(20); |
||||||
|
p.fill(0); |
||||||
|
p.text("Restore", this.pos.x, this.pos.y, this.dim.x, this.dim.y); |
||||||
|
} |
||||||
|
|
||||||
|
if (this.mouseIsOver){ |
||||||
|
p.fill(0, 50); |
||||||
|
p.noStroke(); |
||||||
|
p.rect(x - w / 2, y - h / 2, w , h); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
let w, h, x, y; |
||||||
|
if (this.type === 'switch'){ |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = 0; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
if (this.type === 'download'){ |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = p.width - w; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
if (this.type === 'restore'){ |
||||||
|
w = game.containers[0].dim.x / 2; |
||||||
|
h = w; |
||||||
|
x = p.width - 2 * w; |
||||||
|
y = game.containers[0].pos.y - h; |
||||||
|
} |
||||||
|
|
||||||
|
this.pos.set(x, y); |
||||||
|
this.dim.set(w, h); |
||||||
|
} |
||||||
|
|
||||||
|
mousePressed(){ |
||||||
|
if (this.type === 'switch'){ |
||||||
|
game.isDecorationMode = !game.isDecorationMode; |
||||||
|
game.isTreeMode = !game.isTreeMode; |
||||||
|
} |
||||||
|
if (this.type === 'download'){ |
||||||
|
downloadTrees(); |
||||||
|
} |
||||||
|
if (this.type === 'restore'){ |
||||||
|
$('#file_browser')[0].click(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,168 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
let debug = false, |
||||||
|
font, |
||||||
|
settings: any, |
||||||
|
loader: any; |
||||||
|
|
||||||
|
//Only for online games
|
||||||
|
let socket: SocketIOClient.Socket; |
||||||
|
|
||||||
|
let antiCacheQuery = '?_=' + new Date().getTime(); |
||||||
|
|
||||||
|
let game: Game; |
||||||
|
|
||||||
|
let released = false; |
||||||
|
|
||||||
|
let images: object = { |
||||||
|
|
||||||
|
}; |
||||||
|
|
||||||
|
const p = new p5((p: p5) => { |
||||||
|
|
||||||
|
p.preload = () => { |
||||||
|
settings = p.loadJSON('data/settings/settings.json' + antiCacheQuery, {}, 'json', (json: any) => { |
||||||
|
console.log('Local settings loaded: ', json); |
||||||
|
}, (error: any) => { |
||||||
|
console.log('Local settings failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
font = p.loadFont('data/styles/fonts/Tajawal/Tajawal-Regular.ttf' + antiCacheQuery, (font) => { |
||||||
|
console.log('Local font loaded: ', font); |
||||||
|
}, (error: any) => { |
||||||
|
console.log('Local font failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
images['ball'] = p.loadImage('data/images/ball.png' + antiCacheQuery, img => { |
||||||
|
console.log('Ball image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Ball image failed: ', error); |
||||||
|
}); |
||||||
|
|
||||||
|
images['box'] = p.loadImage('data/images/box.png' + antiCacheQuery, img => { |
||||||
|
console.log('Box image loaded: ', img); |
||||||
|
}, error => { |
||||||
|
console.log('Box image failed: ', error); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
p.setup = () => { |
||||||
|
interfaceSetup(); |
||||||
|
canvasSetup(); |
||||||
|
//loader = new Loader(p.createVector(p.width / 2, p.height / 2), Math.min(p.width, p.height) / 2);
|
||||||
|
loadDynamicScripts().then(() => { |
||||||
|
//Load other stuff, then =>
|
||||||
|
//loader = null;
|
||||||
|
|
||||||
|
game = new Game(); |
||||||
|
game.trees[0].container.mousePressed(); |
||||||
|
}); |
||||||
|
}, |
||||||
|
|
||||||
|
p.draw = () => { |
||||||
|
p.clear(); |
||||||
|
|
||||||
|
if (game){ |
||||||
|
game.update(); |
||||||
|
game.display(); |
||||||
|
} |
||||||
|
|
||||||
|
if (loader){ |
||||||
|
loader.update(); |
||||||
|
loader.display(); |
||||||
|
} |
||||||
|
|
||||||
|
if (debug) debugInformation(); |
||||||
|
} |
||||||
|
}) |
||||||
|
|
||||||
|
function debugInformation(){ |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
function interfaceSetup(){ |
||||||
|
let files_elem = $('#file_browser'); |
||||||
|
files_elem.on('change', () => { |
||||||
|
let file = (files_elem.get(0) as HTMLInputElement).files[0]; |
||||||
|
file.text().then(text => { |
||||||
|
game.restoreTrees(JSON.parse(text)[0]); |
||||||
|
}); |
||||||
|
}); |
||||||
|
|
||||||
|
let colorSelect = $('#color'); |
||||||
|
let possibleColors = $('#possible_colors'); |
||||||
|
for (let colorName in settings.game.colors){ |
||||||
|
if (!settings.game.colors.hasOwnProperty(colorName)) |
||||||
|
continue; |
||||||
|
|
||||||
|
let publicName = colorName.substr(0, 1).toUpperCase() + colorName.substr(1); |
||||||
|
|
||||||
|
let option = $('<option></option>'); |
||||||
|
option.html(publicName); |
||||||
|
option.val("[" + settings.game.colors[colorName] + "]"); |
||||||
|
colorSelect.append(option); |
||||||
|
|
||||||
|
let checkbox = $('<input/>'); |
||||||
|
checkbox.attr({ |
||||||
|
type: 'checkbox', |
||||||
|
id: colorName |
||||||
|
}); |
||||||
|
checkbox.on('click', event => { |
||||||
|
if (game){ |
||||||
|
if (!game.updateChainSettings($(event.target))){ |
||||||
|
console.info('failed'); |
||||||
|
event.preventDefault(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
let label = $('<label></label>'); |
||||||
|
label.html(publicName); |
||||||
|
label.attr('for', colorName); |
||||||
|
|
||||||
|
possibleColors.append(checkbox, label); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
function downloadTrees(){ |
||||||
|
let str = JSON.stringify(game.trees, (key, value) => { |
||||||
|
if (value instanceof p5.Vector){ |
||||||
|
return { |
||||||
|
x: value.x, |
||||||
|
y: value.y |
||||||
|
}; |
||||||
|
} |
||||||
|
return value; |
||||||
|
}); |
||||||
|
let data = 'data:application/json;charset=utf-8,['+ encodeURIComponent(str) + "]"; |
||||||
|
$("#save_link").attr("href", data); |
||||||
|
$("#save_link")[0].click(); |
||||||
|
} |
||||||
|
|
||||||
|
function canvasSetup(){ |
||||||
|
p.frameRate(60); |
||||||
|
let w = $('#canvas_holder').width(), |
||||||
|
h = $('#canvas_holder').height(); |
||||||
|
let canvas = p.createCanvas(w, h); |
||||||
|
canvas.parent('canvas_holder'); |
||||||
|
p.textFont(font); |
||||||
|
p.imageMode(p.CENTER); |
||||||
|
} |
||||||
|
|
||||||
|
async function loadDynamicScripts(){ |
||||||
|
const json = await p.httpGet('data/settings/libraries.json' + antiCacheQuery, 'json'); |
||||||
|
let requests = []; |
||||||
|
for (let script in json) { |
||||||
|
if (json[script]) { |
||||||
|
let url = '/lib/benjocraeft/' + script + '.js'; |
||||||
|
requests.push($.getScript(url, () => { |
||||||
|
console.log('Successfully loaded script: ', url); |
||||||
|
})); |
||||||
|
} |
||||||
|
} |
||||||
|
await $.when(...requests); |
||||||
|
console.log('All dynamic scripts have been loaded!'); |
||||||
|
} |
@ -0,0 +1,54 @@ |
|||||||
|
class Loader{ |
||||||
|
|
||||||
|
pos: p5.Vector |
||||||
|
c: any |
||||||
|
radius: number |
||||||
|
center: p5.Vector |
||||||
|
angle: number |
||||||
|
progress: number |
||||||
|
message: string |
||||||
|
|
||||||
|
constructor(pos: p5.Vector, radius: number){ |
||||||
|
this.pos = pos; |
||||||
|
this.c = p.createGraphics(radius * 2, radius * 2); |
||||||
|
this.radius = radius; |
||||||
|
this.center = p.createVector(radius, radius); |
||||||
|
this.message = 'Loading...'; |
||||||
|
this.progress = 0; |
||||||
|
this.angle = 0; |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
this.angle += Math.PI / 10; |
||||||
|
} |
||||||
|
|
||||||
|
display(){ |
||||||
|
let c = this.c; |
||||||
|
c.clear(); |
||||||
|
c.noFill(); |
||||||
|
c.stroke(20, 100, 200); |
||||||
|
c.strokeWeight(this.radius * 0.025); |
||||||
|
//c.arc(this.center.x, this.center.y, this.radius * 2, this.radius * 2, this.angle, this.angle + Math.PI * 1.5);
|
||||||
|
c.strokeWeight(2); |
||||||
|
c.rect(this.center.x - this.radius + 5, this.center.y - 25, this.radius * 2 - 50, 50); |
||||||
|
c.fill(50, 150, 255); |
||||||
|
c.rect(this.center.x - this.radius + 5, this.center.y - 25, (this.radius - 50) * this.progress, 50); |
||||||
|
|
||||||
|
c.textAlign(p.CENTER, p.CENTER); |
||||||
|
c.textSize(25); |
||||||
|
c.fill(220); |
||||||
|
c.strokeWeight(4); |
||||||
|
c.text(this.message, this.radius, this.radius * 1.5); |
||||||
|
|
||||||
|
c.textSize(40); |
||||||
|
c.text(Math.floor(this.progress * 100) + '%', this.radius, this.radius / 2); |
||||||
|
|
||||||
|
p.imageMode(p.CENTER); |
||||||
|
p.image(c, this.pos.x, this.pos.y); |
||||||
|
} |
||||||
|
|
||||||
|
destroy(){ |
||||||
|
this.c.remove(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,10 @@ |
|||||||
|
'use strict'; |
||||||
|
|
||||||
|
function socketConnect(project, name = "noone"){ |
||||||
|
let urlQueries = '?game=' + project.name + '&name=' + name; |
||||||
|
let port = 3000 |
||||||
|
let url = location.hostname + ":" + port + urlQueries; |
||||||
|
|
||||||
|
socket = io.connect(url); |
||||||
|
socket.on('connect', () => console.log('Connected to ', url)); |
||||||
|
} |
@ -0,0 +1,89 @@ |
|||||||
|
class Star extends Decoration{ |
||||||
|
|
||||||
|
raysCount: number |
||||||
|
triangles: p5.Vector[][] |
||||||
|
innerRadius: number |
||||||
|
|
||||||
|
|
||||||
|
constructor(properties: object){ |
||||||
|
super(properties); |
||||||
|
this.createTriangles(); |
||||||
|
} |
||||||
|
|
||||||
|
get properties(): object{ |
||||||
|
let obj = super.properties; |
||||||
|
obj['raysCount'] = this.raysCount; |
||||||
|
obj['innerRadius'] = this.innerRadius; |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
createTriangles(){ |
||||||
|
this.triangles = []; |
||||||
|
let increment = p.TWO_PI / this.raysCount / 2, |
||||||
|
firstOuter = true; |
||||||
|
for (let i = 0; i < p.TWO_PI; i += increment){ |
||||||
|
let x1 = p.sin(i), |
||||||
|
y1 = -p.cos(i), |
||||||
|
x2 = p.sin(i + increment), |
||||||
|
y2 = -p.cos(i + increment); |
||||||
|
if (firstOuter){ |
||||||
|
x1 *= this.radius, |
||||||
|
y1 *= this.radius, |
||||||
|
x2 *= this.innerRadius, |
||||||
|
y2 *= this.innerRadius; |
||||||
|
} else { |
||||||
|
x2 *= this.radius, |
||||||
|
y2 *= this.radius, |
||||||
|
x1 *= this.innerRadius, |
||||||
|
y1 *= this.innerRadius; |
||||||
|
} |
||||||
|
firstOuter = !firstOuter; |
||||||
|
this.triangles.push([ |
||||||
|
p.createVector(x1, y1), |
||||||
|
p.createVector(x2, y2), |
||||||
|
p.createVector(0, 0) |
||||||
|
]); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
brightness(value: number) { |
||||||
|
this.triangles.forEach((t, i) => { |
||||||
|
p.fill(0, 0, 0, value); |
||||||
|
p.triangle(t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y); |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
display(pos?: p5.Vector, dim?: p5.Vector){ |
||||||
|
super.display(pos, dim); |
||||||
|
|
||||||
|
p.noStroke(); |
||||||
|
|
||||||
|
this.triangles.forEach((t, i) => { |
||||||
|
let color = this.colors[i % this.colors.length]; |
||||||
|
p.fill(color); |
||||||
|
p.triangle(t[0].x, t[0].y, t[1].x, t[1].y, t[2].x, t[2].y); |
||||||
|
}); |
||||||
|
if (this.mouseIsOver){ |
||||||
|
this.brightness(70); |
||||||
|
} |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
super.update(); |
||||||
|
} |
||||||
|
|
||||||
|
toJSON(index){ |
||||||
|
let list = [ |
||||||
|
"raysCount", |
||||||
|
"innerRadius" |
||||||
|
] |
||||||
|
let obj = super.toJSON(index); |
||||||
|
for (let item of list){ |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,256 @@ |
|||||||
|
class Tree{ |
||||||
|
|
||||||
|
pos: p5.Vector = p.createVector() |
||||||
|
sizeMultiplier: number = 1 |
||||||
|
|
||||||
|
stemRadius: number |
||||||
|
leafCount: number |
||||||
|
leafColors: number[][] |
||||||
|
stemColor: number[] |
||||||
|
stemHeight: number |
||||||
|
leafHeight: number |
||||||
|
leafRadius: number |
||||||
|
isSmooth: boolean |
||||||
|
|
||||||
|
isPlaceholder: boolean |
||||||
|
|
||||||
|
container: Container |
||||||
|
|
||||||
|
animationProgress: number = 0 |
||||||
|
animationDirection: number = -1 |
||||||
|
|
||||||
|
decorations: Decoration[] = [] |
||||||
|
|
||||||
|
constructor(properties: object){ |
||||||
|
if (properties == null){ |
||||||
|
this.isPlaceholder = true; |
||||||
|
} else { |
||||||
|
for (let key in properties){ |
||||||
|
this[key] = properties[key]; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//Always called
|
||||||
|
mousePressed(){ |
||||||
|
for (let d of [...this.decorations].reverse()){ |
||||||
|
if (d.mouseIsOver){ |
||||||
|
d.mousePressed(); |
||||||
|
let index = this.decorations.findIndex(deco => deco == d); |
||||||
|
this.decorations[index] = this.decorations[this.decorations.length - 1]; |
||||||
|
this.decorations[this.decorations.length - 1] = d; |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
//Always called
|
||||||
|
mouseReleased(){ |
||||||
|
for (let d of this.decorations){ |
||||||
|
d.mouseReleased(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
get smoothProgress(): number{ |
||||||
|
return this.smoothStep(0, 1, this.animationProgress); |
||||||
|
} |
||||||
|
|
||||||
|
containsPosition(pos: p5.Vector, excludeStem?: boolean){ |
||||||
|
let size = game.height, |
||||||
|
x = (p.width - size) / 2; |
||||||
|
|
||||||
|
let px = pos.x, |
||||||
|
py = pos.y; |
||||||
|
|
||||||
|
let pixelColor = (p.get(px, py) as number[]).slice(0, 3); |
||||||
|
let colorIsValid = game.tree.getAllColors(excludeStem).find(c => equals(c, pixelColor)) != null; |
||||||
|
return colorIsValid && |
||||||
|
px > x && px < x + size && |
||||||
|
py > 0 && py < size - 20; |
||||||
|
} |
||||||
|
|
||||||
|
update(){ |
||||||
|
this.animationProgress += 0.05 * this.animationDirection; |
||||||
|
this.animationProgress = this.animationProgress > 1 ? 1 : this.animationProgress < 0 ? 0 : this.animationProgress; |
||||||
|
if (this.isPlaceholder){ |
||||||
|
this.pos = game.center; |
||||||
|
this.sizeMultiplier = game.height * 0.05; |
||||||
|
} else { |
||||||
|
this.pos = p5.Vector.lerp(this.container.center, game.center, this.smoothProgress); |
||||||
|
this.sizeMultiplier = p.lerp(this.container.dim.y * 0.05, game.height * 0.05, this.smoothProgress); |
||||||
|
} |
||||||
|
|
||||||
|
this.decorations.forEach((d, i) => { |
||||||
|
if (d.isToDelete){ |
||||||
|
this.decorations.splice(i, 1); |
||||||
|
if (d instanceof Ball){ |
||||||
|
d.graphics.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
this.decorations.forEach(d => d.update()); |
||||||
|
} |
||||||
|
|
||||||
|
display(pos?: p5.Vector, dim?: p5.Vector){ |
||||||
|
let sizeMultiplier = this.sizeMultiplier; |
||||||
|
if (pos || dim){ |
||||||
|
sizeMultiplier = dim.y * 0.05; |
||||||
|
} else { |
||||||
|
pos = this.pos; |
||||||
|
} |
||||||
|
p.push(); |
||||||
|
p.translate(pos.x, pos.y); |
||||||
|
p.scale(sizeMultiplier); |
||||||
|
if (this.isPlaceholder){ |
||||||
|
p.fill(0); |
||||||
|
p.stroke(100, 220, 100); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.textSize(1); |
||||||
|
p.textAlign(p.CENTER, p.CENTER); |
||||||
|
p.text('Select your Christmas Tree!', 0, 0); |
||||||
|
} else { |
||||||
|
this.drawTree(); |
||||||
|
this.drawDecorations(); |
||||||
|
if (debug && this === game.tree){ |
||||||
|
p.stroke(255, 0, 0, 80); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
for (let i = -10; i <= 10; i++){ |
||||||
|
p.line(-10, i, 10, i); |
||||||
|
p.line(i, -10, i, 10); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
drawTree(){ |
||||||
|
p.push(); |
||||||
|
p.translate(0, 1); |
||||||
|
|
||||||
|
p.fill(this.stemColor); |
||||||
|
p.stroke(0); |
||||||
|
p.strokeWeight(0.05); |
||||||
|
p.rect(-this.stemRadius, 0, this.stemRadius * 2, this.stemHeight); |
||||||
|
let drawLeaf = (r: number, h: number) => { |
||||||
|
if (this.isSmooth){ |
||||||
|
let cps = [ |
||||||
|
p.createVector(40, 70), |
||||||
|
p.createVector(60, 90), |
||||||
|
p.createVector(100, 130), |
||||||
|
p.createVector(-100, 130), |
||||||
|
p.createVector(-60, 90), |
||||||
|
p.createVector(-40, 70) |
||||||
|
]; |
||||||
|
cps.forEach(c => { |
||||||
|
c.x *= r / 100; |
||||||
|
c.y *= h / 100; |
||||||
|
}); |
||||||
|
|
||||||
|
p.beginShape(); |
||||||
|
p.vertex(0, 0); |
||||||
|
p.bezierVertex(cps[0].x, cps[0].y, cps[1].x, cps[1].y, r, h); |
||||||
|
p.bezierVertex(cps[2].x, cps[2].y, cps[3].x, cps[3].y, -r, h); |
||||||
|
p.bezierVertex(cps[4].x, cps[4].y, cps[5].x, cps[5].y, 0, 0); |
||||||
|
p.endShape(); |
||||||
|
|
||||||
|
if (debug){ |
||||||
|
p.stroke(255, 0, 0); |
||||||
|
cps.forEach(c => p.ellipse(c.x, c.y, 0)); |
||||||
|
} |
||||||
|
} else { |
||||||
|
p.triangle(0, 0, r, h, -r, h); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
for (let i = 0; i < this.leafCount; i++){ |
||||||
|
let y = -i * this.leafHeight / 2; |
||||||
|
let lr = this.leafRadius * (this.leafCount - i) / this.leafCount; |
||||||
|
p.push(); |
||||||
|
p.translate(0, y); |
||||||
|
p.fill(this.leafColors[i % this.leafColors.length]); |
||||||
|
drawLeaf(lr, this.leafHeight); |
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
p.pop(); |
||||||
|
} |
||||||
|
|
||||||
|
drawDecorations(){ |
||||||
|
for (let d of this.decorations){ |
||||||
|
if (d.needsValidation){ |
||||||
|
if (!d.hasValidPosition){ |
||||||
|
d.isToDelete = true; |
||||||
|
} |
||||||
|
d.needsValidation = false; |
||||||
|
} |
||||||
|
} |
||||||
|
for (let d of this.decorations){ |
||||||
|
if (released && d.isBoundToMouse){ |
||||||
|
d.needsValidation = true; |
||||||
|
d.isBoundToMouse = false; |
||||||
|
if (d instanceof Chain){ |
||||||
|
d.p1IsBoundToMouse = false; |
||||||
|
d.p2IsBoundToMouse = false; |
||||||
|
} |
||||||
|
} |
||||||
|
d.display(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
getAllColors(withoutStem?: boolean): number[][]{ |
||||||
|
let colors = []; |
||||||
|
colors.push(...this.leafColors, [0, 0, 0]); |
||||||
|
if (!withoutStem){ |
||||||
|
colors.push(this.stemColor); |
||||||
|
} |
||||||
|
return colors; |
||||||
|
} |
||||||
|
|
||||||
|
smoothStep(start: number, end: number, t: number): number{ |
||||||
|
function clamp(x: number, lowLimit: number, upLimit: number): number{ |
||||||
|
if (x < lowLimit) |
||||||
|
x = lowLimit; |
||||||
|
if (x > upLimit) |
||||||
|
x = upLimit; |
||||||
|
return x; |
||||||
|
} |
||||||
|
t = clamp((t - start) / (end - start), 0, 1); |
||||||
|
return t * t * t * (t * (t * 6 - 15) + 10); |
||||||
|
} |
||||||
|
|
||||||
|
toJSON(index){ |
||||||
|
let list = [ |
||||||
|
"stemRadius", |
||||||
|
"leafCount", |
||||||
|
"leafColors", |
||||||
|
"stemColor", |
||||||
|
"stemHeight", |
||||||
|
"leafHeight", |
||||||
|
"leafRadius", |
||||||
|
"isSmooth", |
||||||
|
"isPlaceholder", |
||||||
|
"decorations" |
||||||
|
] |
||||||
|
let obj = {}; |
||||||
|
for (let item of list){ |
||||||
|
obj[item] = this[item]; |
||||||
|
} |
||||||
|
return obj; |
||||||
|
} |
||||||
|
|
||||||
|
restoreFrom(rawTree: object){ |
||||||
|
for (let key in rawTree){ |
||||||
|
if (key === 'decorations'){ |
||||||
|
this[key] = [] |
||||||
|
rawTree[key].forEach(rawDeco => { |
||||||
|
let deco = Decoration.restoreFrom(rawDeco); |
||||||
|
this[key].push(deco); |
||||||
|
}); |
||||||
|
} else { |
||||||
|
this[key] = rawTree[key]; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
{ |
||||||
|
"collision": false, |
||||||
|
"colorPicker": false, |
||||||
|
"cookie": false, |
||||||
|
"prototypes": true, |
||||||
|
"technical": false |
||||||
|
} |
@ -0,0 +1,202 @@ |
|||||||
|
{ |
||||||
|
"project": { |
||||||
|
"name": "christmas_tree", |
||||||
|
"author": "BenjoCraeft", |
||||||
|
"version": "0.0.0", |
||||||
|
"playerCounts": [], |
||||||
|
"online": { |
||||||
|
"iceServers": [ |
||||||
|
{"urls": "stun:stun.l.google.com:19302"}, |
||||||
|
{ |
||||||
|
"urls": "turn:numb.viagenie.ca", |
||||||
|
"credential": "muazkh", |
||||||
|
"username": "webrtc@live.com" |
||||||
|
} |
||||||
|
] |
||||||
|
} |
||||||
|
}, |
||||||
|
"frameWork": { |
||||||
|
"frameRate": 60, |
||||||
|
"width": null, |
||||||
|
"height": null |
||||||
|
}, |
||||||
|
"game":{ |
||||||
|
"trees": [ |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 7, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 6, |
||||||
|
"leafHeight": 4, |
||||||
|
"leafRadius": 6, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 0.7, |
||||||
|
"stemHeight": 8, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 3, |
||||||
|
"leafHeight": 5, |
||||||
|
"leafRadius": 4, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1.3, |
||||||
|
"stemHeight": 8, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 7, |
||||||
|
"leafHeight": 3.5, |
||||||
|
"leafRadius": 7, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 7, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 5, |
||||||
|
"leafHeight": 4, |
||||||
|
"leafRadius": 6, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 0.7, |
||||||
|
"stemHeight": 5, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 9, |
||||||
|
"leafHeight": 2, |
||||||
|
"leafRadius": 3, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 0.5, |
||||||
|
"stemHeight": 4, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 3, |
||||||
|
"leafHeight": 2, |
||||||
|
"leafRadius": 2.5, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 7, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 5, |
||||||
|
"leafHeight": 4.3, |
||||||
|
"leafRadius": 5, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 6, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 7, |
||||||
|
"leafHeight": 3.2, |
||||||
|
"leafRadius": 5.5, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1.2, |
||||||
|
"stemHeight": 6.5, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 6, |
||||||
|
"leafHeight": 4, |
||||||
|
"leafRadius": 8, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 8, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 5, |
||||||
|
"leafHeight": 4, |
||||||
|
"leafRadius": 6, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 0.5, |
||||||
|
"stemHeight": 6, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 2, |
||||||
|
"leafHeight": 3.5, |
||||||
|
"leafRadius": 4, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
}, |
||||||
|
{ |
||||||
|
"stemRadius": 1, |
||||||
|
"stemHeight": 6, |
||||||
|
"stemColor": [80, 60, 10], |
||||||
|
"leafCount": 6, |
||||||
|
"leafHeight": 3.8, |
||||||
|
"leafRadius": 4, |
||||||
|
"leafColors": [ |
||||||
|
[50, 100, 50], |
||||||
|
[75, 150, 75], |
||||||
|
[100, 200, 100] |
||||||
|
], |
||||||
|
"isSmooth": true |
||||||
|
} |
||||||
|
], |
||||||
|
"colors": { |
||||||
|
"gold": [255, 215, 0], |
||||||
|
"silver": [230, 230, 230], |
||||||
|
"red": [255, 0, 0], |
||||||
|
"pink": [255, 20, 147], |
||||||
|
"blue": [0, 0, 255] |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
#color_picker{ |
||||||
|
width: 300px; |
||||||
|
height: 25%; |
||||||
|
margin: 20px; |
||||||
|
margin-top: 50px; |
||||||
|
border: 5px solid #000; |
||||||
|
background-color: #000; |
||||||
|
-webkit-user-select: none; |
||||||
|
-moz-user-select: none; |
||||||
|
-ms-user-select: none; |
||||||
|
user-select: none; |
||||||
|
position: relative; |
||||||
|
} |
||||||
|
#color_picker_numeric{ |
||||||
|
width: 80%; |
||||||
|
padding: 5%; |
||||||
|
margin: 5%; |
||||||
|
background-color: #888; |
||||||
|
border-radius: 10px; |
||||||
|
overflow: hidden; |
||||||
|
} |
||||||
|
.color_picker_rgb{ |
||||||
|
float: left; |
||||||
|
width: 22%; |
||||||
|
height: 35px; |
||||||
|
font-size: 25px; |
||||||
|
color: #000; |
||||||
|
} |
||||||
|
.color_picker_rgb:nth-child(1){ |
||||||
|
margin-right: 10%; |
||||||
|
margin-left: 3%; |
||||||
|
background-color: #F00; |
||||||
|
|
||||||
|
} |
||||||
|
.color_picker_rgb:nth-child(2){ |
||||||
|
background-color: #0F0; |
||||||
|
} |
||||||
|
.color_picker_rgb:nth-child(3){ |
||||||
|
margin-left: 10%; |
||||||
|
background-color: #00F; |
||||||
|
color: #FFF; |
||||||
|
} |
||||||
|
#color_picker_hex{ |
||||||
|
width: 50%; |
||||||
|
height: 30px; |
||||||
|
font-size: 25px; |
||||||
|
margin: 10% 25% 0 25%; |
||||||
|
} |
||||||
|
#saturation{ |
||||||
|
position: relative; |
||||||
|
width: calc(100% - 33px); |
||||||
|
height: 100%; |
||||||
|
background: linear-gradient(to right, #FFF 0%, #F00 100%); |
||||||
|
float: left; |
||||||
|
margin-right: 6px; |
||||||
|
} |
||||||
|
#value { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
background: linear-gradient(to top, #000 0%, rgba(255,255,255,0) 100%); |
||||||
|
} |
||||||
|
#sb_picker{ |
||||||
|
border: 2px solid; |
||||||
|
border-color: #FFF; |
||||||
|
position: absolute; |
||||||
|
width: 14px; |
||||||
|
height: 14px; |
||||||
|
border-radius: 10px; |
||||||
|
bottom: 50px; |
||||||
|
left: 50px; |
||||||
|
box-sizing: border-box; |
||||||
|
z-index: 10; |
||||||
|
} |
||||||
|
#hue { |
||||||
|
width: 27px; |
||||||
|
height: 100%; |
||||||
|
position: relative; |
||||||
|
float: left; |
||||||
|
background: linear-gradient(to bottom, #F00 0%, #F0F 17%, #00F 34%, #0FF 50%, #0F0 67%, #FF0 84%, #F00 100%); |
||||||
|
} |
||||||
|
#hue_picker { |
||||||
|
position: absolute; |
||||||
|
background: #000; |
||||||
|
border-bottom: 1px solid #000; |
||||||
|
top: 0; |
||||||
|
width: 27px; |
||||||
|
height: 2px; |
||||||
|
} |
Binary file not shown.
@ -0,0 +1,93 @@ |
|||||||
|
Copyright 2018 Boutros International. (https://www.boutrosfonts.com) |
||||||
|
|
||||||
|
This Font Software is licensed under the SIL Open Font License, Version 1.1. |
||||||
|
This license is copied below, and is also available with a FAQ at: |
||||||
|
https://scripts.sil.org/OFL |
||||||
|
|
||||||
|
|
||||||
|
----------------------------------------------------------- |
||||||
|
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 |
||||||
|
----------------------------------------------------------- |
||||||
|
|
||||||
|
PREAMBLE |
||||||
|
The goals of the Open Font License (OFL) are to stimulate worldwide |
||||||
|
development of collaborative font projects, to support the font creation |
||||||
|
efforts of academic and linguistic communities, and to provide a free and |
||||||
|
open framework in which fonts may be shared and improved in partnership |
||||||
|
with others. |
||||||
|
|
||||||
|
The OFL allows the licensed fonts to be used, studied, modified and |
||||||
|
redistributed freely as long as they are not sold by themselves. The |
||||||
|
fonts, including any derivative works, can be bundled, embedded, |
||||||
|
redistributed and/or sold with any software provided that any reserved |
||||||
|
names are not used by derivative works. The fonts and derivatives, |
||||||
|
however, cannot be released under any other type of license. The |
||||||
|
requirement for fonts to remain under this license does not apply |
||||||
|
to any document created using the fonts or their derivatives. |
||||||
|
|
||||||
|
DEFINITIONS |
||||||
|
"Font Software" refers to the set of files released by the Copyright |
||||||
|
Holder(s) under this license and clearly marked as such. This may |
||||||
|
include source files, build scripts and documentation. |
||||||
|
|
||||||
|
"Reserved Font Name" refers to any names specified as such after the |
||||||
|
copyright statement(s). |
||||||
|
|
||||||
|
"Original Version" refers to the collection of Font Software components as |
||||||
|
distributed by the Copyright Holder(s). |
||||||
|
|
||||||
|
"Modified Version" refers to any derivative made by adding to, deleting, |
||||||
|
or substituting -- in part or in whole -- any of the components of the |
||||||
|
Original Version, by changing formats or by porting the Font Software to a |
||||||
|
new environment. |
||||||
|
|
||||||
|
"Author" refers to any designer, engineer, programmer, technical |
||||||
|
writer or other person who contributed to the Font Software. |
||||||
|
|
||||||
|
PERMISSION & CONDITIONS |
||||||
|
Permission is hereby granted, free of charge, to any person obtaining |
||||||
|
a copy of the Font Software, to use, study, copy, merge, embed, modify, |
||||||
|
redistribute, and sell modified and unmodified copies of the Font |
||||||
|
Software, subject to the following conditions: |
||||||
|
|
||||||
|
1) Neither the Font Software nor any of its individual components, |
||||||
|
in Original or Modified Versions, may be sold by itself. |
||||||
|
|
||||||
|
2) Original or Modified Versions of the Font Software may be bundled, |
||||||
|
redistributed and/or sold with any software, provided that each copy |
||||||
|
contains the above copyright notice and this license. These can be |
||||||
|
included either as stand-alone text files, human-readable headers or |
||||||
|
in the appropriate machine-readable metadata fields within text or |
||||||
|
binary files as long as those fields can be easily viewed by the user. |
||||||
|
|
||||||
|
3) No Modified Version of the Font Software may use the Reserved Font |
||||||
|
Name(s) unless explicit written permission is granted by the corresponding |
||||||
|
Copyright Holder. This restriction only applies to the primary font name as |
||||||
|
presented to the users. |
||||||
|
|
||||||
|
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font |
||||||
|
Software shall not be used to promote, endorse or advertise any |
||||||
|
Modified Version, except to acknowledge the contribution(s) of the |
||||||
|
Copyright Holder(s) and the Author(s) or with their explicit written |
||||||
|
permission. |
||||||
|
|
||||||
|
5) The Font Software, modified or unmodified, in part or in whole, |
||||||
|
must be distributed entirely under this license, and must not be |
||||||
|
distributed under any other license. The requirement for fonts to |
||||||
|
remain under this license does not apply to any document created |
||||||
|
using the Font Software. |
||||||
|
|
||||||
|
TERMINATION |
||||||
|
This license becomes null and void if any of the above conditions are |
||||||
|
not met. |
||||||
|
|
||||||
|
DISCLAIMER |
||||||
|
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF |
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT |
||||||
|
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE |
||||||
|
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
||||||
|
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL |
||||||
|
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM |
||||||
|
OTHER DEALINGS IN THE FONT SOFTWARE. |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1,89 @@ |
|||||||
|
input[type=range] { |
||||||
|
-webkit-appearance: none; |
||||||
|
margin: 18px 0; |
||||||
|
width: 100%; |
||||||
|
background: none; |
||||||
|
} |
||||||
|
input[type=range]:focus { |
||||||
|
outline: none; |
||||||
|
} |
||||||
|
input[type=range]::-webkit-slider-runnable-track { |
||||||
|
width: 100%; |
||||||
|
height: 8.4px; |
||||||
|
cursor: pointer; |
||||||
|
animate: 0.2s; |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
background: var(--range-input-track-color); |
||||||
|
border-radius: 1.3px; |
||||||
|
border: 0.2px solid #010101; |
||||||
|
} |
||||||
|
input[type=range]::-webkit-slider-thumb { |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
border: 1px solid #000000; |
||||||
|
height: 36px; |
||||||
|
width: 16px; |
||||||
|
border-radius: 3px; |
||||||
|
background: var(--range-input-thumb-color); |
||||||
|
cursor: pointer; |
||||||
|
-webkit-appearance: none; |
||||||
|
margin-top: -14px; |
||||||
|
} |
||||||
|
input[type=range]:focus::-webkit-slider-runnable-track { |
||||||
|
background: #367ebd; |
||||||
|
} |
||||||
|
input[type=range]::-moz-range-track { |
||||||
|
width: 100%; |
||||||
|
height: 8.4px; |
||||||
|
cursor: pointer; |
||||||
|
animate: 0.2s; |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
background: var(--range-input-track-color); |
||||||
|
border-radius: 1.3px; |
||||||
|
border: 0.2px solid #010101; |
||||||
|
} |
||||||
|
input[type=range]::-moz-range-thumb { |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
border: 1px solid #000000; |
||||||
|
height: 36px; |
||||||
|
width: 16px; |
||||||
|
border-radius: 3px; |
||||||
|
background: var(--range-input-thumb-color); |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
input[type=range]::-ms-track { |
||||||
|
width: 100%; |
||||||
|
height: 8.4px; |
||||||
|
cursor: pointer; |
||||||
|
animate: 0.2s; |
||||||
|
background: transparent; |
||||||
|
border-color: transparent; |
||||||
|
border-width: 16px 0; |
||||||
|
color: transparent; |
||||||
|
} |
||||||
|
input[type=range]::-ms-fill-lower { |
||||||
|
background: #2a6495; |
||||||
|
border: 0.2px solid #010101; |
||||||
|
border-radius: 2.6px; |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
} |
||||||
|
input[type=range]::-ms-fill-upper { |
||||||
|
background: var(--range-input-track-color); |
||||||
|
border: 0.2px solid #010101; |
||||||
|
border-radius: 2.6px; |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
} |
||||||
|
input[type=range]::-ms-thumb { |
||||||
|
box-shadow: 1px 1px 1px #000000, 0px 0px 1px #0d0d0d; |
||||||
|
border: 1px solid #000000; |
||||||
|
height: 36px; |
||||||
|
width: 16px; |
||||||
|
border-radius: 3px; |
||||||
|
background: var(--range-input-thumb-color); |
||||||
|
cursor: pointer; |
||||||
|
} |
||||||
|
input[type=range]:focus::-ms-fill-lower { |
||||||
|
background: var(--range-input-track-color); |
||||||
|
} |
||||||
|
input[type=range]:focus::-ms-fill-upper { |
||||||
|
background: var(--range-input-track-color); |
||||||
|
} |
@ -0,0 +1,67 @@ |
|||||||
|
<!-- Web project created by Benjo Craeft (alias) --> |
||||||
|
<!DOCTYPE html> |
||||||
|
<html lang="en"> |
||||||
|
<head> |
||||||
|
<meta charset="utf-8"> |
||||||
|
<script src="/lib/socket.io/socket.io.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/socket.io/socket.io-p2p.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/p5/p5.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/p5/p5.sound.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/jquery/jquery.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/jquery/jq-ajax-progress.min.js" type="text/javascript"></script> |
||||||
|
<script src="/lib/vue/vue.min.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/init.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/events.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/online.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/loader.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/game.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/tree.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/container.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/decoration.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/chain.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/ball.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/star.js" type="text/javascript"></script> |
||||||
|
<script src="data/scripts/js/background.js" type="text/javascript"></script> |
||||||
|
<link href="data/styles/color_picker.css" rel="stylesheet"> |
||||||
|
<link href="data/styles/range_input.css" rel="stylesheet"> |
||||||
|
<link href="styles.css" rel="stylesheet"> |
||||||
|
<link href="data/images/favicon.ico" rel="icon" type="image/x-icon"> |
||||||
|
<title>Christmas Tree</title> |
||||||
|
</head> |
||||||
|
<body> |
||||||
|
<div id="p5_loading"></div> |
||||||
|
<div id="content"> |
||||||
|
<div id="canvas_holder"></div> |
||||||
|
<div id="settings_holder"> |
||||||
|
<fieldset oninput="game.updateDecorationSettings();"> |
||||||
|
<legend>Decoration Settings</legend> |
||||||
|
<label for="radius">Radius</label> |
||||||
|
<input id="radius" type="range" min="10" max="100" step="1" value="50"> |
||||||
|
<label for="color">Color</label><br/> |
||||||
|
<select id="color"> |
||||||
|
</select> |
||||||
|
</fieldset> |
||||||
|
<fieldset oninput="game.updateStarSettings();"> |
||||||
|
<legend>Star Settings</legend> |
||||||
|
<label for="rays_count">Peaks</label> |
||||||
|
<input id="rays_count" type="range" min="3" max="10" step="1" value="5"> |
||||||
|
<label for="inner_radius">Second Radius</label> |
||||||
|
<input id="inner_radius" type="range" min="0.2" max="0.7" step="0.01" value="0.4"> |
||||||
|
</fieldset> |
||||||
|
<fieldset> |
||||||
|
<legend>Chain Settings</legend> |
||||||
|
<label for="possible_colors">Colors</label> |
||||||
|
<div id="possible_colors"> |
||||||
|
</div> |
||||||
|
</fieldset> |
||||||
|
<fieldset oninput="game.updateBackgroundSettings();"> |
||||||
|
<legend>Background Settings</legend> |
||||||
|
<label for="snow_intensity">Snow</label> |
||||||
|
<input id="snow_intensity" type="range" min="0" max="500" step="1" value="200"> |
||||||
|
</fieldset> |
||||||
|
</div> |
||||||
|
<a id="save_link" download="christmas_trees.json"></a> |
||||||
|
<input style="display: none;" type="file" id="file_browser" accept=".json"> |
||||||
|
</div> |
||||||
|
</body> |
||||||
|
</html> |
@ -0,0 +1,86 @@ |
|||||||
|
a:link, a:hover, a:active, a:visited{color: #000;} |
||||||
|
|
||||||
|
html, body{margin: 0; padding: 0; height: 100%; width: 100%;} |
||||||
|
|
||||||
|
canvas{margin: 0; padding: 0; border: none; display: block;} |
||||||
|
|
||||||
|
button:hover{cursor: pointer;} |
||||||
|
|
||||||
|
@font-face{ |
||||||
|
font-family: "Tajawal"; |
||||||
|
src: url("data/styles/fonts/Tajawal/Tajawal-Regular.ttf"); |
||||||
|
} |
||||||
|
@font-face{ |
||||||
|
font-family: "Elronet"; |
||||||
|
src: url("data/styles/fonts/Elronet/Elronmonospace.ttf"); |
||||||
|
} |
||||||
|
|
||||||
|
*{ |
||||||
|
font-family: "Tajawal", serif; |
||||||
|
color: #000; |
||||||
|
font-size: 17px; |
||||||
|
} |
||||||
|
|
||||||
|
:root{ |
||||||
|
--width: 100vw; |
||||||
|
--height: 100vh; |
||||||
|
--range-input-track-color: #3071a9; |
||||||
|
--range-input-thumb-color: #6eaae2; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Standard styles |
||||||
|
*/ |
||||||
|
|
||||||
|
#canvas_holder{ |
||||||
|
position: relative; |
||||||
|
width: var(--width); |
||||||
|
height: var(--height); |
||||||
|
} |
||||||
|
#canvas_holder canvas{ |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
bottom: 0; |
||||||
|
border-radius: inherit; |
||||||
|
} |
||||||
|
#p5_loading{ |
||||||
|
display: none; |
||||||
|
} |
||||||
|
|
||||||
|
#settings_holder{ |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
right: 0; |
||||||
|
width: 300px; |
||||||
|
background-color: rgba(90, 127, 171, 0.5); |
||||||
|
border-width: 0 0 5px 5px; |
||||||
|
border-style: solid; |
||||||
|
border-color: #000; |
||||||
|
border-bottom-left-radius: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
#settings_holder > fieldset{ |
||||||
|
margin: 5px; |
||||||
|
border-color: #000; |
||||||
|
border-style: solid; |
||||||
|
border-width: 2px; |
||||||
|
border-radius: 5px; |
||||||
|
} |
||||||
|
#settings_holder > fieldset > legend{ |
||||||
|
font-size: 110%; |
||||||
|
} |
||||||
|
#settings_holder > fieldset > label{ |
||||||
|
font-size: 100%; |
||||||
|
} |
||||||
|
select, option{ |
||||||
|
color: #fff; |
||||||
|
} |
||||||
|
select{ |
||||||
|
background: rgba(90, 127, 171, 0.5); |
||||||
|
} |
||||||
|
|
||||||
|
input[type=range]{ |
||||||
|
margin: 10px 0; |
||||||
|
} |
After Width: | Height: | Size: 536 KiB |
@ -0,0 +1,9 @@ |
|||||||
|
{ |
||||||
|
"compilerOptions": { |
||||||
|
"target": "es6", |
||||||
|
"module": "commonjs", |
||||||
|
"sourceMap": true, |
||||||
|
"alwaysStrict": true, |
||||||
|
"outDir": "./data/scripts/js/" |
||||||
|
} |
||||||
|
} |
Loading…
Reference in new issue