|
let rows = [ |
|
[ |
|
0, |
|
0, |
|
0, |
|
5, |
|
6, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
5 |
|
], |
|
[ |
|
6, |
|
0, |
|
5, |
|
4, |
|
4, |
|
6, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
5, |
|
4 |
|
], |
|
[ |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
6, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
5, |
|
4, |
|
4, |
|
4 |
|
], |
|
[ |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
6, |
|
0, |
|
5, |
|
6, |
|
0, |
|
0, |
|
5, |
|
4, |
|
6, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
0, |
|
4, |
|
4, |
|
4, |
|
4 |
|
], |
|
[ |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
4, |
|
6, |
|
0, |
|
5, |
|
4, |
|
6, |
|
0, |
|
0, |
|
0, |
|
5, |
|
4, |
|
4, |
|
4, |
|
4 |
|
] |
|
]; |
|
const rowsBackup = JSON.parse(JSON.stringify(rows)); |
|
const cloudW = 110; |
|
const density = 0.0333; |
|
const maxDroplets = 60; |
|
let raining = false; |
|
const times = []; |
|
const rainSpeed = 7; |
|
const rainIncrease = 0.025; |
|
const spreadIncrement = 0.01; // how fast the water spreads |
|
const spreadCutoff = 0.01; // determines when the water should consider itself "equalized" |
|
let reset = false; |
|
let fps; |
|
|
|
$(".reset").on("click", function (e) { |
|
reset = true; |
|
}); |
|
|
|
$(".debug").on("click", function () { |
|
console.log(rows); |
|
}); |
|
|
|
$(document).on("mousemove", function (e) { |
|
$(".cloud").css("left", e.pageX); |
|
}); |
|
|
|
$(document).on("mousedown", function () { |
|
raining = true; |
|
}); |
|
|
|
$(document).on("mouseup", function () { |
|
raining = false; |
|
}); |
|
|
|
function mainLoop() { |
|
if (reset) { |
|
console.log("resetting flood..."); |
|
rows = JSON.parse(JSON.stringify(rowsBackup)); |
|
$(".raindrop").remove(); |
|
reset = false; |
|
} else { |
|
if (raining && $(".raindrop").length < maxDroplets) { |
|
addDrop(); |
|
} |
|
moveDrops(); |
|
calcDrops(); |
|
spreadWater(); |
|
} |
|
calcFPS(); |
|
drawRows(); |
|
requestAnimationFrame(mainLoop); |
|
} |
|
requestAnimationFrame(mainLoop); |
|
|
|
function moveDrops() { |
|
const screenH = $(window).outerHeight(); |
|
const screenW = $(window).outerWidth(); |
|
$(".raindrop").each(function () { |
|
const currY = $(this).offset().top; |
|
const newY = currY + rainSpeed; |
|
const dropCol = parseInt($(this).data("col")); |
|
const colHeight = getColHeight(dropCol); |
|
if (newY > screenH - colHeight * (screenW * density)) { |
|
let emptyRow = -1; |
|
$.each(rows.slice().reverse(), function (index, row) { |
|
if (row[dropCol] < 1) { |
|
emptyRow = rows.length - 1 - index; |
|
return false; |
|
} |
|
}); |
|
if (emptyRow > -1) { |
|
rows[emptyRow][dropCol] = Math.min( |
|
1, |
|
rows[emptyRow][dropCol] + rainIncrease |
|
); |
|
} |
|
$(this).remove(); |
|
} else { |
|
$(this).css("transform", "translateY(" + newY + "px)"); |
|
} |
|
}); |
|
} |
|
|
|
function addDrop() { |
|
const xRand = Math.random() * cloudW; |
|
const cloudLeft = $(".cloud").offset().left; |
|
const rainPos = cloudLeft + xRand; |
|
const winW = $(window).outerWidth(); |
|
const colSector = Math.floor((rainPos / winW / 3.33) * 100); |
|
// console.log("adding raindrop to column " + colSector); |
|
$("body").append('<div class="raindrop raindrop--new"></div>'); |
|
$(".raindrop--new") |
|
.removeClass("raindrop--new") |
|
.css("left", rainPos) |
|
.data("col", colSector); |
|
} |
|
|
|
function calcFPS() { |
|
const now = performance.now(); |
|
while (times.length > 0 && times[0] <= now - 1000) { |
|
times.shift(); |
|
} |
|
times.push(now); |
|
fps = times.length; |
|
$(".fps").text("FPS: " + fps); |
|
} |
|
|
|
function calcDrops() { |
|
$(".rain-count").text("Droplets: " + $(".raindrop").length); |
|
} |
|
|
|
function drawRows() { |
|
const grid = $(".ground-grid"); |
|
grid.empty(); |
|
$.each(rows, function (index, row) { |
|
$.each(row, function (index2, col) { |
|
let removeSpillage = false; |
|
let newBlock = $( |
|
'<div class="ground-grid__block" data-row=' + |
|
index + |
|
" data-col=" + |
|
index2 + |
|
"></div>" |
|
); |
|
if (col > 6) { |
|
newBlock.addClass("spillage"); |
|
removeSpillage = true; |
|
} |
|
if (col == 6 || col == 8) { |
|
newBlock.addClass("ground-grid__block--rightRound"); |
|
} |
|
if (col == 5 || col == 7) { |
|
newBlock.addClass("ground-grid__block--leftRound"); |
|
} |
|
if (col == 4) { |
|
newBlock.addClass("ground-grid__block--dirt"); |
|
} |
|
if (col == 2) { |
|
newBlock.addClass("ground-grid__block--rightSlope"); |
|
} |
|
if (col == 3) { |
|
newBlock.addClass("ground-grid__block--leftSlope"); |
|
} |
|
if (col <= 1 && col > 0) { |
|
const level = col * 100; |
|
const heavyWater = level >= 5; |
|
const drawLevel = heavyWater ? level : 0; |
|
newBlock |
|
.addClass("ground-grid__block--water") |
|
.append( |
|
"<span data-level=" + |
|
level + |
|
' style="height:' + |
|
(drawLevel + "%") + |
|
'"></span>' |
|
); |
|
if (heavyWater) { |
|
newBlock.addClass("heavyWater"); |
|
} |
|
} |
|
grid.append(newBlock); |
|
rows[index][index2] = removeSpillage |
|
? rows[index][index2] - 2 |
|
: rows[index][index2]; |
|
}); |
|
}); |
|
} |
|
|
|
function spreadWater() { |
|
// remove spillage animations |
|
$(".spillage").removeClass("spillage"); |
|
// go through each water tile and spread water |
|
$(".ground-grid__block--water").each(function () { |
|
const row = $(this).data("row"); |
|
const col = $(this).data("col"); |
|
const level = $(this).find("span").data("level") / 100; |
|
let addBelow = false; |
|
// always check block below first |
|
const belowBlockVal = row != rows.length - 1 ? rows[row + 1][col] : null; |
|
if (belowBlockVal !== null && belowBlockVal < 1) { |
|
rows[row + 1][col] += spreadIncrement; |
|
if (rows[row + 1][col] > 1) { |
|
rows[row + 1][col] = 1; |
|
} |
|
rows[row][col] -= spreadIncrement; |
|
addBelow = true; |
|
} |
|
// check block to the left |
|
const leftBlockVal = col != 0 ? rows[row][col - 1] : null; |
|
if ( |
|
leftBlockVal !== null && |
|
leftBlockVal < 1 && |
|
leftBlockVal < level && |
|
Math.abs(leftBlockVal - level) > spreadCutoff && |
|
!addBelow |
|
) { |
|
rows[row][col] -= spreadIncrement; |
|
rows[row][col - 1] += spreadIncrement; |
|
if (rows[row][col - 1] > 1) { |
|
rows[row][col - 1] = 1; |
|
} |
|
// if not falling down, add spillage below |
|
if (belowBlockVal !== null && belowBlockVal != 4 && belowBlockVal != 1) { |
|
rows[row + 1][col] = belowBlockVal == 5 ? 7 : 8; |
|
} |
|
} |
|
// check block to the right |
|
const rightBlockVal = col != 29 ? rows[row][col + 1] : null; |
|
if ( |
|
rightBlockVal !== null && |
|
rightBlockVal < 1 && |
|
rightBlockVal < level && |
|
Math.abs(rightBlockVal - level) > spreadCutoff && |
|
!addBelow |
|
) { |
|
rows[row][col] -= spreadIncrement; |
|
rows[row][col + 1] += spreadIncrement; |
|
if (rows[row][col + 1] > 1) { |
|
rows[row][col + 1] = 1; |
|
} |
|
// if not falling down, add spillage below |
|
if (belowBlockVal !== null && belowBlockVal != 4 && belowBlockVal != 1) { |
|
rows[row + 1][col] = belowBlockVal == 5 ? 7 : 8; |
|
} |
|
} |
|
// if tile is essentially empty, drain it |
|
if (level < spreadIncrement) { |
|
rows[row][col] = 0; |
|
} |
|
}); |
|
} |
|
|
|
function getColHeight(col) { |
|
let height = 0; |
|
$.each(rows.slice().reverse(), function (index, row) { |
|
const rowCol = row[col]; |
|
if (rowCol == 0) { |
|
return false; |
|
} else if (rowCol <= 1) { |
|
height += rowCol; |
|
} else { |
|
height += 1; |
|
} |
|
}); |
|
return height; |
|
} |