mirror of
https://github.com/Sheldan/canvas.git
synced 2026-04-05 01:02:57 +00:00
balls: adding initial version of balls
This commit is contained in:
1293
balls/package-lock.json
generated
Normal file
1293
balls/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
19
balls/package.json
Normal file
19
balls/package.json
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"name": "balls",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"canvas-common": "file:../canvas-common"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vite": "^5.1.5"
|
||||||
|
}
|
||||||
|
}
|
||||||
22
balls/src/index.html
Normal file
22
balls/src/index.html
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="no-js" lang="">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="x-ua-compatible" content="ie=edge">
|
||||||
|
<title>balls</title>
|
||||||
|
<meta name="description" content="">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
<style>
|
||||||
|
html, body, div, canvas {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
html, body { width:100%; height:100%; }
|
||||||
|
canvas { display:block; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<script type="module" src="js/main.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
858
balls/src/js/main.js
Normal file
858
balls/src/js/main.js
Normal file
@@ -0,0 +1,858 @@
|
|||||||
|
import {
|
||||||
|
toRad, getMousePos, addRGBStyle, docReady, createNormalizedVector, angleBetweenTwoVectors, dotProduct
|
||||||
|
} from "canvas-common";
|
||||||
|
|
||||||
|
var imageData = {};
|
||||||
|
var ctx = {};
|
||||||
|
var canvas = {};
|
||||||
|
var mousePos = {}
|
||||||
|
|
||||||
|
|
||||||
|
var config = {
|
||||||
|
size: {
|
||||||
|
width: window.innerWidth,
|
||||||
|
height: window.innerHeight
|
||||||
|
},
|
||||||
|
balls: {
|
||||||
|
rowElements: window.innerWidth/(window.innerHeight/10),
|
||||||
|
rows: 10,
|
||||||
|
horizontalSize: window.innerHeight / 10,
|
||||||
|
verticalSize: window.innerHeight / 10,
|
||||||
|
balls: 10,
|
||||||
|
speed: 10,
|
||||||
|
reboundBuffChance: 0.25,
|
||||||
|
portalChance: 0.07,
|
||||||
|
simulationDepth: 5000,
|
||||||
|
restartTaps: 3,
|
||||||
|
tapsFactor: 2,
|
||||||
|
resetTapsDecreaseInterval: 2
|
||||||
|
},
|
||||||
|
general: {
|
||||||
|
fps: 30
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var mobile = 'ontouchstart' in window;
|
||||||
|
|
||||||
|
|
||||||
|
if(mobile){
|
||||||
|
config.balls.tapsFactor = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
var timeouts = [];
|
||||||
|
|
||||||
|
var toSpawn = 0;
|
||||||
|
var spawning = false;
|
||||||
|
var newSpawnSet = false;
|
||||||
|
|
||||||
|
var mouseStart = {};
|
||||||
|
var mouseStop = {};
|
||||||
|
var animationId = {};
|
||||||
|
|
||||||
|
var balls = [];
|
||||||
|
|
||||||
|
var rects = [];
|
||||||
|
var gameOver = false;
|
||||||
|
|
||||||
|
var buffs = [];
|
||||||
|
var portals = [];
|
||||||
|
var reboundBalls = 0;
|
||||||
|
var mouseDown = false;
|
||||||
|
var newStartPoint;
|
||||||
|
|
||||||
|
var fourtyFiveDegrees = toRad(45);
|
||||||
|
var portalCounter = 1;
|
||||||
|
var oneHundredThirtyFriveDegrees = toRad(135);
|
||||||
|
var oneHundredEightyDegrees = toRad(180);
|
||||||
|
|
||||||
|
var colors = [
|
||||||
|
{
|
||||||
|
r: 0xf2, g: 0x69, b: 0x12
|
||||||
|
}, {
|
||||||
|
r: 0xf3, g: 0x8c, b: 0x14
|
||||||
|
}, {
|
||||||
|
r: 0xf4, g: 0xaf, b: 0x16
|
||||||
|
}, {
|
||||||
|
r: 0xf4, g: 0xd1, b: 0x17
|
||||||
|
}, {
|
||||||
|
r: 0xf5, g: 0xf3, b: 0x19
|
||||||
|
}, {
|
||||||
|
r: 0xd7, g: 0xf6, b: 0x1b
|
||||||
|
}, {
|
||||||
|
r: 0xb7, g: 0xf6, b: 0x1d
|
||||||
|
}, {
|
||||||
|
r: 0x98, g: 0xf7, b: 0x1f
|
||||||
|
}, {
|
||||||
|
r: 0x79, g: 0xf8, b: 0x21
|
||||||
|
}, {
|
||||||
|
r: 0x5a, g: 0xf8, b: 0x23
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
colors.forEach(addRGBStyle);
|
||||||
|
|
||||||
|
var restartRect = {
|
||||||
|
x: 0, y: 0, width: config.size.width * 0.2, height: config.size.height * 0.2
|
||||||
|
};
|
||||||
|
|
||||||
|
function isInRect(point, rect){
|
||||||
|
return point.x > rect.x && point.x < (rect.x + rect.width) && point.y > rect.y && rect.y < (rect.y + rect.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
var doRestart = 0;
|
||||||
|
var restarting = false;
|
||||||
|
|
||||||
|
function setPoint(event){
|
||||||
|
|
||||||
|
var point = getMousePos(canvas, event);
|
||||||
|
if(isInRect(point, restartRect)){
|
||||||
|
doRestart++;
|
||||||
|
console.log(doRestart)
|
||||||
|
if(doRestart >= config.balls.restartTaps * config.balls.tapsFactor){
|
||||||
|
console.log('Restarting');
|
||||||
|
timeouts.forEach(function(timeout){
|
||||||
|
clearTimeout(timeout);
|
||||||
|
});
|
||||||
|
timeouts = [];
|
||||||
|
restarting = true;
|
||||||
|
rects = [];
|
||||||
|
buffs = [];
|
||||||
|
portals = [];
|
||||||
|
balls = [];
|
||||||
|
portalCounter = 1;
|
||||||
|
config.balls.balls = 10;
|
||||||
|
mouseDown = false;
|
||||||
|
mouseStop = {};
|
||||||
|
spawnStuff();
|
||||||
|
doRestart = 0;
|
||||||
|
// verrrrry cheap hack
|
||||||
|
// I couldnt get the mouse events to stop, because on mobile twice as much are sent
|
||||||
|
// so after resetting it, balls still spawned, because the event was triggered and therefore came into the lower
|
||||||
|
// lines of code... and spawned balls
|
||||||
|
timeouts.push(setTimeout(function(){
|
||||||
|
restarting = false;
|
||||||
|
spawning = false;
|
||||||
|
console.log('reseting restarting flag...')
|
||||||
|
}, 250));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//setShaft(event)
|
||||||
|
mouseStart = newStartPoint;
|
||||||
|
if(spawning) return;
|
||||||
|
if(!mouseDown){
|
||||||
|
mouseDown = true;
|
||||||
|
mouseStop = point;
|
||||||
|
} else {
|
||||||
|
mouseDown = false;
|
||||||
|
spawning = true;
|
||||||
|
setTip(event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function startBall(cnt){
|
||||||
|
toSpawn = cnt;
|
||||||
|
if(cnt == 0) return;
|
||||||
|
var vec = createNormalizedVector(mouseStop, mouseStart);
|
||||||
|
var ball = {
|
||||||
|
x: mouseStart.x,
|
||||||
|
y: mouseStart.y,
|
||||||
|
radius: 4,
|
||||||
|
vec: vec,
|
||||||
|
simulation: false,
|
||||||
|
maxBounces: -1
|
||||||
|
};
|
||||||
|
if(!restarting) {
|
||||||
|
balls.push(ball);
|
||||||
|
timeouts.push(setTimeout(function(){
|
||||||
|
if(restarting) return;
|
||||||
|
startBall(cnt - 1);
|
||||||
|
}, 250))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setShaft(event) {
|
||||||
|
mouseStart = getMousePos(canvas, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
function setTip(event) {
|
||||||
|
|
||||||
|
toSpawn = config.balls.balls;
|
||||||
|
startBall(config.balls.balls);
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCanvas() {
|
||||||
|
ctx.clearRect(0, 0, config.size.width, config.size.height);
|
||||||
|
if(gameOver){
|
||||||
|
ctx.fillText('gameover: ' + config.balls.balls, config.size.width / 2, config.size.height / 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
var caseApplied = false;
|
||||||
|
objectsToDisplay.forEach(function(object){
|
||||||
|
if(object.startCondition()){
|
||||||
|
caseApplied = true;
|
||||||
|
object.running = true;
|
||||||
|
object.applied = true;
|
||||||
|
}
|
||||||
|
if(object.condition() && object.running){
|
||||||
|
caseApplied = true;
|
||||||
|
object.fun();
|
||||||
|
object.applied = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
object.running = false;
|
||||||
|
if(object.applied){
|
||||||
|
object.postFun();
|
||||||
|
}
|
||||||
|
object.applied = false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!caseApplied){
|
||||||
|
if(!gameOver && !restarting){
|
||||||
|
paintRects();
|
||||||
|
paintPortals();
|
||||||
|
paintBuffs();
|
||||||
|
paintBalls();
|
||||||
|
paintIndicator();
|
||||||
|
ballsAct();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setTimeout(function () {
|
||||||
|
animationId = requestAnimationFrame(updateCanvas);
|
||||||
|
}, 1000 / config.general.fps)
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintPortals(){
|
||||||
|
portals.forEach(paintPortal)
|
||||||
|
}
|
||||||
|
function paintPortal(portal){
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'orange';
|
||||||
|
ctx.rect(portal.source.xPos, portal.source.yPos, portal.source.width, portal.source.height);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'lightBlue';
|
||||||
|
ctx.rect(portal.target.xPos, portal.target.yPos, portal.target.width, portal.target.height);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText(portal.source.linkedWith, portal.source.xPos, portal.source.yPos + portal.source.height / 2);
|
||||||
|
ctx.fillText(portal.target.linkedWith, portal.target.xPos, portal.target.yPos + portal.target.height / 2);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var objectsToDisplay = [];
|
||||||
|
objectsToDisplay.push({
|
||||||
|
fun: drawPlaceHolder,
|
||||||
|
startCondition: function(){
|
||||||
|
return rects.length == 0
|
||||||
|
},
|
||||||
|
condition: function(){
|
||||||
|
return placeHolder.y > 0
|
||||||
|
},
|
||||||
|
applied: false,
|
||||||
|
running: false,
|
||||||
|
postFun: function(){
|
||||||
|
rectsAct();
|
||||||
|
newStartPoint = {x: balls[0].x, y: config.size.height - 25};
|
||||||
|
balls = [];
|
||||||
|
},
|
||||||
|
reset: function(){
|
||||||
|
placeHolder = {x: config.size.width / 2, y: config.size.height}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
function paintBuffs(){
|
||||||
|
buffs.forEach(paintBuff);
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintBuff(buff){
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.moveTo(buff.xPos, buff.yPos);
|
||||||
|
ctx.fillStyle = buildBuffGradient(buff);
|
||||||
|
ctx.rect(buff.xPos, buff.yPos, buff.width, buff.height);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText(buff.duration, buff.xPos + 20, buff.yPos + 20);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintPrediction(){
|
||||||
|
var vec = createNormalizedVector(mouseStop, mouseStart);
|
||||||
|
var prediction = {
|
||||||
|
x: mouseStart.x,
|
||||||
|
y: mouseStart.y,
|
||||||
|
radius: 4,
|
||||||
|
vec: vec,
|
||||||
|
simulation: true,
|
||||||
|
bounces: 2
|
||||||
|
};
|
||||||
|
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = 'black';
|
||||||
|
ctx.moveTo(prediction.x, prediction.y);
|
||||||
|
var cnt = 0;
|
||||||
|
while(prediction.bounces > 0 && cnt < config.balls.simulationDepth) {
|
||||||
|
ballAct(prediction);
|
||||||
|
ctx.lineTo(prediction.x, prediction.y);
|
||||||
|
cnt++;
|
||||||
|
}
|
||||||
|
ctx.stroke();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintIndicator(){
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle='black';
|
||||||
|
ctx.fillStyle='black';
|
||||||
|
|
||||||
|
if(mouseDown){
|
||||||
|
paintPrediction();
|
||||||
|
}
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'lightBlue';
|
||||||
|
ctx.rect(0, config.size.height - 30, (balls.length / config.balls.balls) * config.size.width / 2, 10);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText(toSpawn, 0, config.size.height - 20);
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
if(reboundBalls > 0){
|
||||||
|
ctx.fillStyle = 'yellow';
|
||||||
|
ctx.rect(0, config.size.height - 50, reboundBalls * 10, 10);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText(reboundBalls, 0, config.size.height - 40);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function rectsAct(){
|
||||||
|
rects.forEach(function(rect){
|
||||||
|
rect.yPos += config.balls.verticalSize;
|
||||||
|
if(rect.yPos > config.size.height - 50){
|
||||||
|
gameOver = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
portals.forEach(function(portal, index, array){
|
||||||
|
portal.source.yPos += config.balls.verticalSize;
|
||||||
|
portal.target.yPos += config.balls.verticalSize;
|
||||||
|
if(portal.source.yPos > config.size.height - 50){
|
||||||
|
array.splice(index, 1);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(portal.target.yPos > config.size.height - 50){
|
||||||
|
array.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
buffs.forEach(function(buff, index, array){
|
||||||
|
buff.yPos += config.balls.verticalSize;
|
||||||
|
if(buff.yPos > config.size.height - 50){
|
||||||
|
array.splice(index, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
config.balls.balls++;
|
||||||
|
toSpawn = config.balls.balls;
|
||||||
|
spawnStuff();
|
||||||
|
updateCookieStorage();
|
||||||
|
spawning = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function updateCookieStorage(){
|
||||||
|
var objectToStore = {
|
||||||
|
rects: rects,
|
||||||
|
balls: config.balls.balls,
|
||||||
|
buffs: buffs,
|
||||||
|
portals: portals
|
||||||
|
};
|
||||||
|
|
||||||
|
Cookies.remove('balls');
|
||||||
|
Cookies.set('balls', objectToStore);
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintBalls(){
|
||||||
|
balls.forEach(paintBall)
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintRects(){
|
||||||
|
rects.forEach(paintRect)
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintRect(rect){
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle="#ffffff";
|
||||||
|
var col = getColor(rect.points, rect.maxPoints);
|
||||||
|
if(col == undefined){
|
||||||
|
ctx.fillStyle = 'white'
|
||||||
|
} else {
|
||||||
|
ctx.fillStyle = col.styleRGB;
|
||||||
|
}
|
||||||
|
ctx.rect(rect.xPos, rect.yPos, rect.width, rect.height);
|
||||||
|
ctx.fill();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.fillText(rect.points, rect.xPos + 20, rect.yPos + 20);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
|
||||||
|
function getColor(value, maxValue){
|
||||||
|
var percent = value / maxValue;
|
||||||
|
return colors[(colors.length * percent - 1)<<0];
|
||||||
|
}
|
||||||
|
|
||||||
|
function paintBall(ball){
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.fillStyle = 'black';
|
||||||
|
ctx.arc(ball.x,ball.y,ball.radius,0,2*Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
|
||||||
|
function ballsAct(){
|
||||||
|
balls.forEach(ballAct);
|
||||||
|
newSpawnSet = false;
|
||||||
|
if(rects.length == 0){
|
||||||
|
objectsToDisplay[0].reset();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
balls.forEach(function(ball, index, array){
|
||||||
|
if(ball.done){
|
||||||
|
array.splice(index, 1);
|
||||||
|
}
|
||||||
|
if(array.length == 0 && spawning){
|
||||||
|
rectsAct();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
var placeHolder = {x: config.size.width / 2, y: config.size.height};
|
||||||
|
|
||||||
|
function drawPlaceHolder(){
|
||||||
|
ctx.fillText('Any idea for a better animation?', placeHolder.x, placeHolder.y);
|
||||||
|
ctx.fill();
|
||||||
|
placeHolder.y -= 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
function ballAct(ball){
|
||||||
|
ball.x = ball.x + ball.vec.x * config.balls.speed;
|
||||||
|
ball.y = ball.y + ball.vec.y * config.balls.speed;
|
||||||
|
|
||||||
|
if ((ball.x + ball.radius) > config.size.width || (ball.x - ball.radius) < 0) {
|
||||||
|
ball.vec.x *= -1;
|
||||||
|
if(ball.bounces > 0){
|
||||||
|
ball.bounces--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ball.y - ball.radius < 0) {
|
||||||
|
ball.vec.y *= -1;
|
||||||
|
if(ball.bounces > 0){
|
||||||
|
ball.bounces--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((ball.y + ball.radius) > config.size.height && !ball.simulation) {
|
||||||
|
if(reboundBalls <= 0){
|
||||||
|
if(!newSpawnSet){
|
||||||
|
newStartPoint = {x: ball.x, y: config.size.height - 25};
|
||||||
|
newSpawnSet = true;
|
||||||
|
}
|
||||||
|
ball.done = true;
|
||||||
|
} else {
|
||||||
|
reboundBalls--;
|
||||||
|
ball.vec.y *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var nextX = ball.x;
|
||||||
|
var nextY = ball.y;
|
||||||
|
|
||||||
|
var ballBottomY = nextY + ball.radius;
|
||||||
|
var ballLeftX = nextX - ball.radius;
|
||||||
|
var ballTopY = nextY - ball.radius;
|
||||||
|
var ballRightX = nextX + ball.radius;
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
rects.forEach(function(rect, index, array){
|
||||||
|
var topRightX = rect.xPos + rect.width;
|
||||||
|
//var bottomRightX = rect.xPos + rect.width;
|
||||||
|
//var bottomRightY = rect.yPos + rect.height;
|
||||||
|
var bottomLeftY = rect.yPos + rect.height;
|
||||||
|
|
||||||
|
if(ballLeftX < topRightX && ballRightX > rect.xPos && ballBottomY > rect.yPos && ballTopY < bottomLeftY) {
|
||||||
|
var centerX = rect.xPos + rect.width / 2;
|
||||||
|
var centerY = rect.yPos + rect.height / 2;
|
||||||
|
var rectCenterToBallCenter = createNormalizedVector(ball, {x: centerX, y: centerY});
|
||||||
|
var normalLevel = createNormalizedVector({x: centerX + 10, y: centerY}, {x: centerX, y: centerY});
|
||||||
|
var angle = angleBetweenTwoVectors(rectCenterToBallCenter, normalLevel);
|
||||||
|
if(angle < fourtyFiveDegrees){
|
||||||
|
ball.vec.x *= -1;
|
||||||
|
} else if(angle < oneHundredThirtyFriveDegrees){
|
||||||
|
ball.vec.y *= -1;
|
||||||
|
} else if(angle < oneHundredEightyDegrees){
|
||||||
|
ball.vec.x *= -1;
|
||||||
|
}
|
||||||
|
if(ball.bounces > 0){
|
||||||
|
ball.bounces--;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
nextX = ball.x + ball.vec.x * config.balls.speed;
|
||||||
|
nextY = ball.y + ball.vec.y * config.balls.speed;
|
||||||
|
|
||||||
|
ballBottomY = nextY + ball.radius;
|
||||||
|
ballLeftX = nextX - ball.radius;
|
||||||
|
ballTopY = nextY - ball.radius;
|
||||||
|
ballRightX = nextX + ball.radius;
|
||||||
|
|
||||||
|
if(ballLeftX < topRightX && ballRightX > rect.xPos && ballBottomY > rect.yPos && ballTopY < bottomLeftY) {
|
||||||
|
var centerX2 = rect.xPos + rect.width / 2;
|
||||||
|
var centerY2 = rect.yPos + rect.height / 2;
|
||||||
|
var rectCenterToBallCenter2 = createNormalizedVector(ball, {x: centerX2, y: centerY2});
|
||||||
|
var normalLevel2 = createNormalizedVector({x: centerX2 + 10, y: centerY2}, {x: centerX2, y: centerY2});
|
||||||
|
var angle2 = angleBetweenTwoVectors(rectCenterToBallCenter2, normalLevel2);
|
||||||
|
|
||||||
|
if (angle2 < fourtyFiveDegrees) {
|
||||||
|
ball.vec.y *= -1;
|
||||||
|
} else if (angle2 < oneHundredThirtyFriveDegrees) {
|
||||||
|
ball.vec.y *= -1;
|
||||||
|
} else if (angle2 < oneHundredEightyDegrees) {
|
||||||
|
ball.vec.x *= -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!ball.simulation) {
|
||||||
|
rect.points--;
|
||||||
|
}
|
||||||
|
found = true;
|
||||||
|
if(rect.points <= 0 && !ball.simulation){
|
||||||
|
array.splice(index, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
found = false;
|
||||||
|
|
||||||
|
buffs.forEach(function(buff, index, array){
|
||||||
|
if(found || buff.points == 0) return;
|
||||||
|
var topRightX = buff.xPos + buff.width;
|
||||||
|
//var bottomRightX = buff.xPos + buff.width;
|
||||||
|
//var bottomRightY = buff.yPos + buff.height;
|
||||||
|
var bottomLeftY = buff.yPos + buff.height;
|
||||||
|
|
||||||
|
if(ballLeftX < topRightX && ballRightX > buff.xPos && ballBottomY > buff.yPos && ballTopY < bottomLeftY && !ball.simulation) {
|
||||||
|
buff.points--;
|
||||||
|
found = true;
|
||||||
|
buff.effect(ball);
|
||||||
|
array.splice(index, 1);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
found = false;
|
||||||
|
portals.forEach(function(portal, index, array){
|
||||||
|
function portalCollision(portal, ball){
|
||||||
|
if(found) return;
|
||||||
|
var topRightX = portal.xPos + portal.width;
|
||||||
|
//var bottomRightX = portal.xPos + portal.width;
|
||||||
|
//var bottomRightY = portal.yPos + portal.height;
|
||||||
|
var bottomLeftY = portal.yPos + portal.height;
|
||||||
|
if(ballLeftX < topRightX && ballRightX > portal.xPos && ballBottomY > portal.yPos && ballTopY < bottomLeftY) {
|
||||||
|
found = true;
|
||||||
|
portal.effect(ball);
|
||||||
|
} else {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
portalCollision(portal.source, ball);
|
||||||
|
if(!found){
|
||||||
|
portalCollision(portal.target, ball)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function spawnStuff(){
|
||||||
|
if(Math.random() < config.balls.reboundBuffChance){
|
||||||
|
var buff = {
|
||||||
|
xPos: ((Math.random() * config.balls.rowElements) << 0) * config.balls.horizontalSize,
|
||||||
|
yPos: 1 * config.balls.verticalSize,
|
||||||
|
height: config.balls.verticalSize - 5,
|
||||||
|
width: config.balls.horizontalSize - 5,
|
||||||
|
duration: (Math.random() * config.balls.balls + 1) << 0,
|
||||||
|
effect: function(ball) {
|
||||||
|
reboundBalls += buff.duration;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
buffs.push(buff);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(Math.random() < config.balls.portalChance)
|
||||||
|
{
|
||||||
|
var source = {
|
||||||
|
xPos: ((Math.random() * config.balls.rowElements) << 0) * config.balls.horizontalSize,
|
||||||
|
yPos: ((Math.random() * config.balls.rows) << 0) * config.balls.verticalSize + config.balls.verticalSize / 2 - 7.5,
|
||||||
|
height: 15,
|
||||||
|
width: config.balls.verticalSize - 5,
|
||||||
|
linkedWith: portalCounter
|
||||||
|
};
|
||||||
|
var target = {
|
||||||
|
xPos: ((Math.random() * config.balls.rowElements) << 0) * config.balls.horizontalSize,
|
||||||
|
yPos: ((Math.random() * config.balls.rows) << 0) * config.balls.verticalSize + config.balls.verticalSize / 2 - 7.5,
|
||||||
|
height: 15,
|
||||||
|
width: config.balls.verticalSize - 5,
|
||||||
|
linkedWith: portalCounter
|
||||||
|
};
|
||||||
|
|
||||||
|
portalCounter++;
|
||||||
|
var centerX = target.xPos + target.width / 2;
|
||||||
|
var centerY = target.yPos + target.height / 2;
|
||||||
|
var base = createNormalizedVector({x: centerX, y: centerY}, {x : centerX + 10, y: centerY});
|
||||||
|
var lowerRight = createNormalizedVector({x: centerX, y: centerY}, {x: target.xPos + target.width, y: target.yPos + target.height});
|
||||||
|
var lowerLeft = createNormalizedVector({x: centerX, y: centerY}, {x: target.xPos, y: target.yPos + target.height});
|
||||||
|
target.angles = [angleBetweenTwoVectors(base, lowerRight), angleBetweenTwoVectors(base, lowerLeft)];
|
||||||
|
source.angles = [angleBetweenTwoVectors(base, lowerRight), angleBetweenTwoVectors(base, lowerLeft)];
|
||||||
|
|
||||||
|
var blocked = false;
|
||||||
|
if(target.yPos == source.yPos && target.xPos == source.xPos){
|
||||||
|
blocked = true;
|
||||||
|
}
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysRect(source);
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysBuff(source);
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysPortal(source);
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysRect(target);
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysBuff(target);
|
||||||
|
if(!blocked)
|
||||||
|
blocked = blocked || overlaysPortal(target);
|
||||||
|
|
||||||
|
// orange
|
||||||
|
source.effect = function(ball) {
|
||||||
|
collisionWithPortal(ball, source, target);
|
||||||
|
};
|
||||||
|
|
||||||
|
//blue
|
||||||
|
target.effect = function(ball) {
|
||||||
|
collisionWithPortal(ball, target, source);
|
||||||
|
};
|
||||||
|
|
||||||
|
var portal = {
|
||||||
|
source: source,
|
||||||
|
target: target
|
||||||
|
};
|
||||||
|
if(!blocked){
|
||||||
|
portals.push(portal)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var rectAmount = ((Math.random() * 9) << 0) + 1;
|
||||||
|
for(var i = 0; i < rectAmount; i++){
|
||||||
|
var rect = {
|
||||||
|
xPos: ((Math.random() * config.balls.rowElements) << 0) * config.balls.horizontalSize,
|
||||||
|
yPos: 1 * config.balls.verticalSize,
|
||||||
|
height: config.balls.verticalSize - 5,
|
||||||
|
width: config.balls.horizontalSize - 5,
|
||||||
|
points: config.balls.balls,
|
||||||
|
maxPoints: config.balls.balls
|
||||||
|
};
|
||||||
|
var exists = false;
|
||||||
|
exists = exists || overlaysRect(rect);
|
||||||
|
exists = exists || overlaysBuff(rect);
|
||||||
|
exists = exists || overlaysPortal(rect);
|
||||||
|
|
||||||
|
|
||||||
|
if(!exists){
|
||||||
|
rects.push(rect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function setEndPoint(event){
|
||||||
|
if(mouseDown){
|
||||||
|
mouseStop = getMousePos(canvas, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function overlaysRect(rect){
|
||||||
|
var exists = false;
|
||||||
|
rects.forEach(function(rectToTest){
|
||||||
|
if(exists) return;
|
||||||
|
if(rectToTest.xPos == rect.xPos && rectToTest.yPos == rect.yPos){
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function overlaysBuff(rect){
|
||||||
|
var exists = false;
|
||||||
|
buffs.forEach(function(buffToTest){
|
||||||
|
if(exists) return;
|
||||||
|
if(buffToTest.xPos == rect.xPos && buffToTest.yPos == rect.yPos){
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function overlaysPortal(rect){
|
||||||
|
var exists = false;
|
||||||
|
portals.forEach(function (portalToTest){
|
||||||
|
if(exists) return;
|
||||||
|
var sourceCenter = {
|
||||||
|
x: portalToTest.source.xPos + portalToTest.source.width / 2,
|
||||||
|
y: portalToTest.source.yPos + portalToTest.source.height / 2
|
||||||
|
};
|
||||||
|
if(sourceCenter.x > rect.xPos && sourceCenter.x < (rect.xPos + rect.width) && sourceCenter.y > rect.yPos && sourceCenter.y < (rect.yPos + rect.height)){
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
var targetCenter = {
|
||||||
|
x: portalToTest.target.xPos + portalToTest.target.width / 2,
|
||||||
|
y: portalToTest.target.yPos + portalToTest.target.height / 2
|
||||||
|
};
|
||||||
|
if(targetCenter.x > rect.xPos && targetCenter.x < (rect.xPos + rect.width) && targetCenter.y > rect.yPos && targetCenter.y < (rect.yPos + rect.height)){
|
||||||
|
exists = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return exists;
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildBuffGradient(buff){
|
||||||
|
var yellowMagenta = ctx.createRadialGradient(buff.xPos + buff.width / 2, buff.yPos + buff.height / 2, 0, buff.xPos + buff.width / 2, buff.yPos + buff.height / 2, buff.width / 2);
|
||||||
|
yellowMagenta.addColorStop(0 ,"yellow");
|
||||||
|
yellowMagenta.addColorStop(1, "DarkMagenta");
|
||||||
|
return yellowMagenta;
|
||||||
|
}
|
||||||
|
|
||||||
|
function collisionWithPortal(ball, thisOne, partner){
|
||||||
|
var centerX = thisOne.xPos + thisOne.width / 2;
|
||||||
|
var centerY = thisOne.yPos + thisOne.height / 2;
|
||||||
|
|
||||||
|
var xOffset = ball.x - thisOne.xPos;
|
||||||
|
var yOffset = ball.y - thisOne.yPos;
|
||||||
|
var rectCenterToBallCenter = createNormalizedVector(ball, {x: centerX, y: centerY});
|
||||||
|
var normalLevel = createNormalizedVector({x: centerX + 10, y: centerY}, {x: centerX, y: centerY});
|
||||||
|
var angle = angleBetweenTwoVectors(rectCenterToBallCenter, normalLevel);
|
||||||
|
if(angle < thisOne.angles[0]){
|
||||||
|
ball.x = partner.xPos - ball.radius;
|
||||||
|
ball.y = partner.yPos + yOffset;
|
||||||
|
} else if(angle < thisOne.angles[1]){
|
||||||
|
if(ball.vec.y > 0){
|
||||||
|
ball.y = partner.yPos + partner.height + ball.radius;
|
||||||
|
ball.x = partner.xPos + xOffset;
|
||||||
|
} else {
|
||||||
|
ball.y = partner.yPos - ball.radius;
|
||||||
|
ball.x = partner.xPos + xOffset;
|
||||||
|
}
|
||||||
|
} else if(angle < oneHundredEightyDegrees){
|
||||||
|
ball.x = partner.xPos + partner.width + ball.radius;
|
||||||
|
ball.y = partner.yPos + yOffset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
docReady(function () {
|
||||||
|
newStartPoint = {x: config.size.width / 2, y: config.size.height - 25};
|
||||||
|
toSpawn = config.balls.balls;
|
||||||
|
canvas = document.getElementById('canvas')
|
||||||
|
ctx = canvas.getContext("2d");
|
||||||
|
canvas.width = config.size.width;
|
||||||
|
canvas.height = config.size.height;
|
||||||
|
canvas.addEventListener("mousedown", setPoint, false);
|
||||||
|
canvas.addEventListener("mouseup", setPoint, false);
|
||||||
|
canvas.addEventListener("mousemove", setEndPoint, false);
|
||||||
|
// Set up touch events for mobile, etc
|
||||||
|
canvas.addEventListener("touchstart", function (e) {
|
||||||
|
if(restarting) return;
|
||||||
|
mousePos = getTouchPos(canvas, e);
|
||||||
|
var touch = e.touches[0];
|
||||||
|
var mouseEvent = new MouseEvent("mousedown", {
|
||||||
|
clientX: touch.clientX,
|
||||||
|
clientY: touch.clientY
|
||||||
|
});
|
||||||
|
canvas.dispatchEvent(mouseEvent);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
canvas.addEventListener("touchend", function (e) {
|
||||||
|
if(restarting) return;
|
||||||
|
var mouseEvent = new MouseEvent("mouseup", {
|
||||||
|
});
|
||||||
|
canvas.dispatchEvent(mouseEvent);
|
||||||
|
}, false);
|
||||||
|
canvas.addEventListener("touchmove", function (e) {
|
||||||
|
if(restarting) return;
|
||||||
|
var touch = e.touches[0];
|
||||||
|
|
||||||
|
mousePos = getTouchPos(canvas, e);
|
||||||
|
var mouseEvent = new MouseEvent("mousemove", {
|
||||||
|
clientX: touch.clientX,
|
||||||
|
clientY: touch.clientY
|
||||||
|
});
|
||||||
|
canvas.dispatchEvent(mouseEvent);
|
||||||
|
}, false);
|
||||||
|
|
||||||
|
// Get the position of a touch relative to the canvas
|
||||||
|
function getTouchPos(canvasDom, touchEvent) {
|
||||||
|
var rect = canvasDom.getBoundingClientRect();
|
||||||
|
return {
|
||||||
|
x: touchEvent.touches[0].clientX - rect.left,
|
||||||
|
y: touchEvent.touches[0].clientY - rect.top
|
||||||
|
};
|
||||||
|
}
|
||||||
|
var possibleBalls = Cookies.getJSON('balls');
|
||||||
|
if(possibleBalls == undefined){
|
||||||
|
spawnStuff();
|
||||||
|
} else {
|
||||||
|
buffs = possibleBalls.buffs;
|
||||||
|
portals = possibleBalls.portals;
|
||||||
|
rects = possibleBalls.rects;
|
||||||
|
|
||||||
|
// it doesnt store functions
|
||||||
|
buffs.forEach(function(buff){
|
||||||
|
buff.effect = function(ball) {
|
||||||
|
reboundBalls += buff.duration;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
portals.forEach(function(portal){
|
||||||
|
portal.source.effect = function(ball) {
|
||||||
|
collisionWithPortal(ball, portal.source, portal.target);
|
||||||
|
};
|
||||||
|
|
||||||
|
//blue
|
||||||
|
portal.target.effect = function(ball) {
|
||||||
|
collisionWithPortal(ball, portal.target, portal.source);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
config.balls.balls = possibleBalls.balls;
|
||||||
|
}
|
||||||
|
requestAnimationFrame(updateCanvas);
|
||||||
|
|
||||||
|
setInterval(function(){
|
||||||
|
if(doRestart > 0){
|
||||||
|
doRestart--;
|
||||||
|
}
|
||||||
|
}, config.balls.resetTapsDecreaseInterval * 1000)
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
24
balls/src/js/plugins.js
Normal file
24
balls/src/js/plugins.js
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Avoid `console` errors in browsers that lack a console.
|
||||||
|
(function() {
|
||||||
|
var method;
|
||||||
|
var noop = function () {};
|
||||||
|
var methods = [
|
||||||
|
'assert', 'clear', 'count', 'debug', 'dir', 'dirxml', 'error',
|
||||||
|
'exception', 'group', 'groupCollapsed', 'groupEnd', 'info', 'log',
|
||||||
|
'markTimeline', 'profile', 'profileEnd', 'table', 'time', 'timeEnd',
|
||||||
|
'timeline', 'timelineEnd', 'timeStamp', 'trace', 'warn'
|
||||||
|
];
|
||||||
|
var length = methods.length;
|
||||||
|
var console = (window.console = window.console || {});
|
||||||
|
|
||||||
|
while (length--) {
|
||||||
|
method = methods[length];
|
||||||
|
|
||||||
|
// Only stub undefined methods.
|
||||||
|
if (!console[method]) {
|
||||||
|
console[method] = noop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}());
|
||||||
|
|
||||||
|
// Place any jQuery/helper plugins in here.
|
||||||
9
balls/vite.config.js
Normal file
9
balls/vite.config.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { defineConfig } from 'vite'
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
base: './',
|
||||||
|
root: 'src',
|
||||||
|
build: {
|
||||||
|
outDir: '../../dist/balls'
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -123,4 +123,196 @@ export function randomNumberButAtLeast(range, min) {
|
|||||||
|
|
||||||
export function getIndexForCoordinate(config, x, y) {
|
export function getIndexForCoordinate(config, x, y) {
|
||||||
return (y * config.size.width + x) * 4;
|
return (y * config.size.width + x) * 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function createNormalizedVector(tip, shaft) {
|
||||||
|
let vect = createVector(tip, shaft);
|
||||||
|
|
||||||
|
let dist = pointDistance(tip, shaft);
|
||||||
|
vect.x /= dist;
|
||||||
|
vect.y /= dist;
|
||||||
|
return vect;
|
||||||
|
}
|
||||||
|
|
||||||
|
// only normalized vectors
|
||||||
|
export function angleBetweenTwoVectors(vectorA, vectorB){
|
||||||
|
return Math.acos(dotProduct(vectorA, vectorB));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function dotProduct(vector1, vector2) {
|
||||||
|
return vector1.x * vector2.x + vector1.y * vector2.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*!
|
||||||
|
* JavaScript Cookie v2.2.0
|
||||||
|
* https://github.com/js-cookie/js-cookie
|
||||||
|
*
|
||||||
|
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||||
|
* Released under the MIT license
|
||||||
|
*/
|
||||||
|
/*!
|
||||||
|
* JavaScript Cookie v2.2.0
|
||||||
|
* https://github.com/js-cookie/js-cookie
|
||||||
|
*
|
||||||
|
* Copyright 2006, 2015 Klaus Hartl & Fagner Brack
|
||||||
|
* Released under the MIT license
|
||||||
|
*/
|
||||||
|
;(function (factory) {
|
||||||
|
var registeredInModuleLoader = false;
|
||||||
|
if (typeof define === 'function' && define.amd) {
|
||||||
|
define(factory);
|
||||||
|
registeredInModuleLoader = true;
|
||||||
|
}
|
||||||
|
if (typeof exports === 'object') {
|
||||||
|
module.exports = factory();
|
||||||
|
registeredInModuleLoader = true;
|
||||||
|
}
|
||||||
|
if (!registeredInModuleLoader) {
|
||||||
|
var OldCookies = window.Cookies;
|
||||||
|
var api = window.Cookies = factory();
|
||||||
|
api.noConflict = function () {
|
||||||
|
window.Cookies = OldCookies;
|
||||||
|
return api;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}(function () {
|
||||||
|
function extend () {
|
||||||
|
var i = 0;
|
||||||
|
var result = {};
|
||||||
|
for (; i < arguments.length; i++) {
|
||||||
|
var attributes = arguments[ i ];
|
||||||
|
for (var key in attributes) {
|
||||||
|
result[key] = attributes[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
function init (converter) {
|
||||||
|
function api (key, value, attributes) {
|
||||||
|
var result;
|
||||||
|
if (typeof document === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write
|
||||||
|
|
||||||
|
if (arguments.length > 1) {
|
||||||
|
attributes = extend({
|
||||||
|
path: '/'
|
||||||
|
}, api.defaults, attributes);
|
||||||
|
|
||||||
|
if (typeof attributes.expires === 'number') {
|
||||||
|
var expires = new Date();
|
||||||
|
expires.setMilliseconds(expires.getMilliseconds() + attributes.expires * 864e+5);
|
||||||
|
attributes.expires = expires;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We're using "expires" because "max-age" is not supported by IE
|
||||||
|
attributes.expires = attributes.expires ? attributes.expires.toUTCString() : '';
|
||||||
|
|
||||||
|
try {
|
||||||
|
result = JSON.stringify(value);
|
||||||
|
if (/^[\{\[]/.test(result)) {
|
||||||
|
value = result;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
|
||||||
|
if (!converter.write) {
|
||||||
|
value = encodeURIComponent(String(value))
|
||||||
|
.replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent);
|
||||||
|
} else {
|
||||||
|
value = converter.write(value, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
key = encodeURIComponent(String(key));
|
||||||
|
key = key.replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent);
|
||||||
|
key = key.replace(/[\(\)]/g, escape);
|
||||||
|
|
||||||
|
var stringifiedAttributes = '';
|
||||||
|
|
||||||
|
for (var attributeName in attributes) {
|
||||||
|
if (!attributes[attributeName]) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stringifiedAttributes += '; ' + attributeName;
|
||||||
|
if (attributes[attributeName] === true) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stringifiedAttributes += '=' + attributes[attributeName];
|
||||||
|
}
|
||||||
|
return (document.cookie = key + '=' + value + stringifiedAttributes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
result = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// To prevent the for loop in the first place assign an empty array
|
||||||
|
// in case there are no cookies at all. Also prevents odd result when
|
||||||
|
// calling "get()"
|
||||||
|
var cookies = document.cookie ? document.cookie.split('; ') : [];
|
||||||
|
var rdecode = /(%[0-9A-Z]{2})+/g;
|
||||||
|
var i = 0;
|
||||||
|
|
||||||
|
for (; i < cookies.length; i++) {
|
||||||
|
var parts = cookies[i].split('=');
|
||||||
|
var cookie = parts.slice(1).join('=');
|
||||||
|
|
||||||
|
if (!this.json && cookie.charAt(0) === '"') {
|
||||||
|
cookie = cookie.slice(1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
var name = parts[0].replace(rdecode, decodeURIComponent);
|
||||||
|
cookie = converter.read ?
|
||||||
|
converter.read(cookie, name) : converter(cookie, name) ||
|
||||||
|
cookie.replace(rdecode, decodeURIComponent);
|
||||||
|
|
||||||
|
if (this.json) {
|
||||||
|
try {
|
||||||
|
cookie = JSON.parse(cookie);
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (key === name) {
|
||||||
|
result = cookie;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!key) {
|
||||||
|
result[name] = cookie;
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
api.set = api;
|
||||||
|
api.get = function (key) {
|
||||||
|
return api.call(api, key);
|
||||||
|
};
|
||||||
|
api.getJSON = function () {
|
||||||
|
return api.apply({
|
||||||
|
json: true
|
||||||
|
}, [].slice.call(arguments));
|
||||||
|
};
|
||||||
|
api.defaults = {};
|
||||||
|
|
||||||
|
api.remove = function (key, attributes) {
|
||||||
|
api(key, '', extend(attributes, {
|
||||||
|
expires: -1
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
api.withConverter = init;
|
||||||
|
|
||||||
|
return api;
|
||||||
|
}
|
||||||
|
|
||||||
|
return init(function () {});
|
||||||
|
}));
|
||||||
|
|||||||
BIN
img/balls.png
Normal file
BIN
img/balls.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.9 KiB |
@@ -12,5 +12,6 @@
|
|||||||
<a href="/orbits"><img src="img/orbits.png" alt="Solar system simulation" class="preview" title="Solar system simulation"></a> <br>
|
<a href="/orbits"><img src="img/orbits.png" alt="Solar system simulation" class="preview" title="Solar system simulation"></a> <br>
|
||||||
<a href="/recBubbles"><img src="img/recBubbles.png" alt="Recursive bubbles" class="preview" title="Recursive bubbles"></a> <br>
|
<a href="/recBubbles"><img src="img/recBubbles.png" alt="Recursive bubbles" class="preview" title="Recursive bubbles"></a> <br>
|
||||||
<a href="/fireWorks"><img src="img/fireWorks.png" alt="Fireworks" class="preview" title="Fireworks"></a>
|
<a href="/fireWorks"><img src="img/fireWorks.png" alt="Fireworks" class="preview" title="Fireworks"></a>
|
||||||
|
<a href="/balls"><img src="img/balls.png" alt="Balls" class="preview" title="Balls"></a>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user