Skip to content

Instantly share code, notes, and snippets.

@lostintangent
Last active December 15, 2023 19:58
Show Gist options
  • Select an option

  • Save lostintangent/24fe9c1ff087947f5c19b847dde0b89d to your computer and use it in GitHub Desktop.

Select an option

Save lostintangent/24fe9c1ff087947f5c19b847dde0b89d to your computer and use it in GitHub Desktop.

Revisions

  1. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,6 @@
    //- .fps
    //- .rain-count
    .reset Reset
    .debug Debug
    //- .debug Debug
    .title mouse moves cloud ° click to rain ° FLOOD the VALLEY
    .ground-grid
  2. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -7,6 +7,6 @@
    //- .fps
    //- .rain-count
    .reset Reset
    //- .debug Debug
    .debug Debug
    .title mouse moves cloud ° click to rain ° FLOOD the VALLEY
    .ground-grid
  3. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    each _ in Array(8)
    span
    //- .fps
    .rain-count
    //- .rain-count
    .reset Reset
    //- .debug Debug
    .title mouse moves cloud ° click to rain ° FLOOD the VALLEY
  4. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@
    each _ in Array(8)
    span
    //- .fps
    //- .rain-count
    .rain-count
    .reset Reset
    //- .debug Debug
    .title mouse moves cloud ° click to rain ° FLOOD the VALLEY
  5. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    .cloud
    each _ in Array(8)
    span
    .fps
    //- .fps
    //- .rain-count
    .reset Reset
    //- .debug Debug
  6. lostintangent revised this gist Dec 15, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion index.pug
    Original file line number Diff line number Diff line change
    @@ -4,7 +4,7 @@
    .cloud
    each _ in Array(8)
    span
    //- .fps
    .fps
    //- .rain-count
    .reset Reset
    //- .debug Debug
  7. lostintangent created this gist Jan 13, 2021.
    7 changes: 7 additions & 0 deletions flood-the-valley.markdown
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,7 @@
    🌊 Flood the Valley
    ------------------


    A [Pen](https://codepen.io/JoshuaVB/pen/BaLOOLB) by [Joshua van Boxtel](https://codepen.io/JoshuaVB) on [CodePen](https://codepen.io).

    [License](https://codepen.io/JoshuaVB/pen/BaLOOLB/license).
    12 changes: 12 additions & 0 deletions index.pug
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,12 @@
    .background
    each _ in Array(5)
    span
    .cloud
    each _ in Array(8)
    span
    //- .fps
    //- .rain-count
    .reset Reset
    //- .debug Debug
    .title mouse moves cloud ° click to rain ° FLOOD the VALLEY
    .ground-grid
    407 changes: 407 additions & 0 deletions script.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,407 @@
    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;
    }
    1 change: 1 addition & 0 deletions scripts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1 @@
    <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    345 changes: 345 additions & 0 deletions style.scss
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,345 @@
    @import url("https://fonts.googleapis.com/css?family=Major+Mono+Display&display=swap");

    $ground: #481d13;
    $density: 3.33vw;
    $water: lighten(blue, 10%);

    html,
    body {
    height: 100%;
    width: 100%;
    overflow: hidden;
    background: #cfe3f1;
    }

    .title {
    user-select: none;
    position: absolute;
    font-family: "Major Mono Display", monospace;
    color: $water;
    top: 16px;
    left: 16px;
    right: 60px;
    font-size: 22px;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    word-spacing: -5px;
    letter-spacing: -1.5px;
    padding-bottom: 15px;
    &::before {
    content: "";
    position: absolute;
    bottom: 0;
    opacity: 0.25;
    left: 0px;
    height: 3px;
    width: 87px;
    background: $water;
    }
    }

    .background {
    position: absolute;
    top: 0;
    bottom: 0;
    left: 0;
    right: 0;
    opacity: 0.5;

    span {
    width: 35vw;
    height: 35vw;
    background: linear-gradient(
    135deg,
    rgb(181 189 200 / 94%) 0%,
    #769cbd 36%,
    #126b2e 100%
    );
    position: absolute;
    bottom: 0;
    left: 0;
    transform: rotate(45deg) translateY(50%);
    border-radius: 40px;

    &:nth-of-type(2) {
    left: 25%;
    }

    &:nth-of-type(3) {
    left: 50%;
    }

    &:nth-of-type(4) {
    left: 75%;
    }

    &:nth-of-type(5) {
    left: 100%;
    }
    }
    }

    .fps {
    position: absolute;
    top: 110px;
    right: 10px;
    font: 400 16px/1 sans-serif;
    }

    .rain-count {
    position: absolute;
    top: 135px;
    right: 10px;
    font: 400 16px/1 sans-serif;
    }

    .reset,
    .debug {
    position: absolute;
    top: 10px;
    right: 10px;
    font: 400 16px/1 sans-serif;
    padding: 10px;
    border: 1px solid black;
    cursor: pointer;

    &:hover {
    background: black;
    color: white;
    }
    }

    .debug {
    top: 60px;
    }

    .raindrop {
    position: absolute;
    top: 0px;
    width: 2px;
    height: 5px;
    background: $water;
    transform: translateY(150px);
    z-index: 0;
    }

    .ground-grid {
    display: flex;
    flex-wrap: wrap;
    position: absolute;
    bottom: 0;
    left: 0;
    width: 100%;

    &__block {
    width: $density;
    padding-top: $density;
    // border: 1px dashed black;
    box-sizing: border-box;
    position: relative;

    &--water {
    span {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    background: $water;

    &:not([style="height:0%"])::before,
    &:not([style="height:0%"])::after {
    content: "";
    position: absolute;
    z-index: 0;
    background: $water;
    top: 0;
    right: 90%;
    height: 3vw;
    width: 1vw;
    border-radius: 15px;
    }
    &:not([style="height:0%"])::after {
    right: auto;
    left: 90%;
    }
    }

    &.heavyWater {
    &::after {
    content: "";
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    height: 2vw;
    background: $water;
    }
    }
    }

    &--dirt,
    &--leftRound,
    &--rightRound {
    background: $ground;

    &::after {
    content: "";
    position: absolute;
    z-index: 1;
    width: 100%;
    height: 100%;
    background: $ground;
    top: 0;
    left: 0;
    border-radius: 15px 0 0 0;
    }
    }

    &--leftRound {
    border-radius: 15px 0 0 0;

    &.spillage {
    &::before {
    content: "";
    position: absolute;
    right: 0;
    bottom: 0;
    background: $water;
    top: -2px;
    left: -2px;
    border-radius: 15px 0 0 0;
    }
    }
    }

    &--rightRound {
    border-radius: 0 15px 0 0;

    &::after {
    border-radius: 0 15px 0 0;
    }

    &.spillage {
    &::before {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    background: $water;
    right: -2px;
    top: -2px;
    border-radius: 0 15px 0 0;
    }
    }
    }

    &--rightSlope {
    &::after {
    content: "";
    position: absolute;
    top: 0px;
    left: 0px;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 5vw 0 0 5vw;
    border-color: transparent transparent transparent $ground;
    }
    }

    &--leftSlope {
    &::after {
    content: "";
    position: absolute;
    top: 0px;
    left: 0px;
    width: 0;
    height: 0;
    border-style: solid;
    border-width: 0 0 5vw 5vw;
    border-color: transparent transparent $ground transparent;
    }
    }
    }
    }

    .cloud {
    position: absolute;
    top: 100px;
    left: 50%;
    transform: translateX(-50%);
    width: 110px;
    cursor: pointer;
    z-index: 1;

    &::after {
    content: "";
    position: absolute;
    background: white;
    width: 70px;
    height: 30px;
    top: 27px;
    left: 22px;
    }

    span {
    position: absolute;
    width: 40px;
    height: 40px;
    top: 0;
    left: 0;
    border-radius: 100%;
    background: white;
    box-shadow: 0px 0px 4px rgba(black, 0.1);

    &:nth-of-type(1) {
    top: 25px;
    }

    &:nth-of-type(2) {
    width: 30px;
    height: 30px;
    top: 13px;
    left: 20px;
    }

    &:nth-of-type(3) {
    left: 40px;
    }

    &:nth-of-type(4) {
    width: 30px;
    height: 30px;
    top: 12px;
    left: 67px;
    }

    &:nth-of-type(5) {
    width: 30px;
    height: 30px;
    top: 30px;
    left: 80px;
    }

    &:nth-of-type(6) {
    width: 23px;
    height: 23px;
    left: 24px;
    top: 45px;
    }

    &:nth-of-type(7) {
    width: 35px;
    height: 35px;
    left: 38px;
    top: 38px;
    }

    &:nth-of-type(8) {
    left: 60px;
    top: 40px;
    width: 30px;
    height: 30px;
    }
    }
    }