ZeroByter

standalone snake game

Mar 8th, 2021
686
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
HTML 7.74 KB | None | 0 0
  1. <style>
  2.     body {
  3.         margin: 0px;
  4.         overflow: hidden;
  5.         font-family: "Arial";
  6.     }
  7.  
  8.     #ui {
  9.         position: fixed;
  10.         top: 10px;
  11.         left: 10px;
  12.         z-index: 1;
  13.         color: white;
  14.     }
  15.  
  16.     #pause-screen {
  17.         position: fixed;
  18.         top: 0px;
  19.         left: 0px;
  20.         width: 100%;
  21.         height: 100%;
  22.         background: rgba(0, 0, 0, 0.65);
  23.         z-index: 2;
  24.         text-align: center;
  25.         padding-top: 60px;
  26.     }
  27.  
  28.     #pause-continue-countdown {
  29.         font-size: 30px;
  30.     }
  31.  
  32.     #pause-continue-highlighted-area {
  33.         position: fixed;
  34.         z-index: 3;
  35.         width: 30px;
  36.         height: 30px;
  37.         background: rgba(255, 255, 255, 0.65);
  38.         border-radius: 30px;
  39.     }
  40. </style>
  41. <script>
  42.     //vector module
  43.     function vector2(x, y) {
  44.         this.x = x || 0
  45.         this.y = y || 0
  46.     }
  47.     vector2.prototype.add = function (otherVector) {
  48.         return new vector2(this.x + otherVector.x, this.y + otherVector.y)
  49.     }
  50.     vector2.prototype.minus = function (otherVector) {
  51.         return new vector2(this.x - otherVector.x, this.y - otherVector.y)
  52.     }
  53.     vector2.prototype.multiply = function (factor) {
  54.         return new vector2(this.x * factor, this.y * factor)
  55.     }
  56.     vector2.prototype.magnitude = function () {
  57.         return Math.sqrt((this.x * this.x) + (this.y * this.y))
  58.     }
  59.     vector2.prototype.normalized = function () {
  60.         const length = this.magnitude()
  61.         return new vector2(this.x / length, this.y / length)
  62.     }
  63.     vector2.prototype.distance = function (otherVector) {
  64.         return Math.sqrt(Math.pow(this.x - otherVector.x, 2) + Math.pow(this.y - otherVector.y, 2))
  65.     }
  66.     vector2.prototype.copy = function () {
  67.         return new vector2(this.x, this.y)
  68.     }
  69.  
  70.     const lerp = (a, b, t) => {
  71.         return a + (b - a) * t
  72.     }
  73.  
  74.     window.onload = function () {
  75.         let canvas = document.getElementById("canvas")
  76.  
  77.         canvas.width = window.innerWidth
  78.         canvas.height = window.innerHeight
  79.  
  80.         let ctx = canvas.getContext("2d")
  81.  
  82.         let gameRunning = true
  83.         let pauseActive = false
  84.         let pauseContinueStartTime = -1
  85.  
  86.         let head = {
  87.             location: new vector2(canvas.width / 2, canvas.height / 2),
  88.             parent: null
  89.         }
  90.         let parts = []
  91.         let foods = []
  92.         let mouseLocation = new vector2()
  93.         let score = 0
  94.  
  95.         const UpdateUI = () => {
  96.             //this function is pretty ineffecient but whatever...
  97.             document.getElementById("score").innerHTML = "Score: " + score
  98.  
  99.             if (pauseActive) {
  100.                 document.getElementById("pause-screen").style.display = ""
  101.             } else {
  102.                 document.getElementById("pause-screen").style.display = "none"
  103.             }
  104.         }
  105.         UpdateUI()
  106.  
  107.         const newFood = () => {
  108.             foods.push({
  109.                 location: new vector2(50 + Math.random() * (canvas.width - 100), 50 + Math.random() * (canvas.height - 100)),
  110.                 expiration: 0
  111.             })
  112.         }
  113.         newFood()
  114.  
  115.         const newPart = () => {
  116.             let parent = head
  117.             let location = head.location.copy()
  118.             if (parts.length != 0) {
  119.                 parent = parts[parts.length - 1]
  120.                 location = parent.location.copy()
  121.             }
  122.  
  123.             let placedInMiddleIndex = -1
  124.             if (parts.length > 3) {
  125.                 let index = Math.floor(Math.random() * (parts.length - 2) + 2)
  126.                 placedInMiddleIndex = index
  127.                 parent = parts[index - 1]
  128.                 location = parent.location.copy()
  129.             }
  130.  
  131.             //randomize starting location
  132.             location = new vector2(location.x + Math.random() * 2 - 1, location.y + Math.random() * 2 - 1)
  133.  
  134.             const newPart = {
  135.                 parent,
  136.                 location
  137.             }
  138.             if (placedInMiddleIndex != -1) {
  139.                 parts.splice(placedInMiddleIndex, 0, newPart)
  140.  
  141.                 parts[placedInMiddleIndex + 1].parent = parts[placedInMiddleIndex]
  142.             } else {
  143.                 parts.push(newPart)
  144.             }
  145.         }
  146.  
  147.         newPart()
  148.         newPart()
  149.         newPart()
  150.  
  151.         canvas.addEventListener("mousemove", e => {
  152.             mouseLocation = new vector2(e.pageX, e.pageY)
  153.         })
  154.  
  155.         document.addEventListener("keydown", e => {
  156.             if (e.code === "Space" || e.code === "KeyP" || e.code === "Escape") {
  157.                 gameRunning = false
  158.                 pauseActive = true
  159.                 UpdateUI()
  160.             }
  161.         })
  162.  
  163.         setInterval(() => {
  164.             if (!gameRunning) return
  165.  
  166.             head.location.x = mouseLocation.x
  167.             head.location.y = mouseLocation.y
  168.  
  169.             parts.forEach((part, index) => {
  170.                 let distanceToHead = part.location.distance(head.location)
  171.                 if (index > 0 && distanceToHead > 5 && distanceToHead < 17) {
  172.                    gameRunning = false
  173.                    alert("fuck you lost")
  174.                }
  175.  
  176.                let parent = head
  177.                let distance = 25
  178.  
  179.                if (index != 0) {
  180.                    parent = part.parent
  181.                    distance = 20
  182.                }
  183.  
  184.                const direction = part.location.minus(parent.location).normalized()
  185.                parts[index].location = parent.location.add(direction.multiply(distance))
  186.            })
  187.  
  188.            foods.forEach((food, foodIndex) => {
  189.                if (head.location.distance(food.location) < 18) {
  190.                    let newPartsCount = Math.max(1, Math.round(parts.length / 10))
  191.                    for (let i = 0; i < newPartsCount; i++) {
  192.                        newPart()
  193.                    }
  194.  
  195.                    newFood()
  196.  
  197.                    foods.splice(foodIndex, 1)
  198.  
  199.                    score += 1
  200.                    UpdateUI()
  201.                }
  202.            })
  203.        }, 5)
  204.  
  205.        //debug
  206.        // ctx.font = '10px serif';
  207.        // ctx.strokeStyle = "red"
  208.        setInterval(() => {
  209.             if (!gameRunning) return
  210.  
  211.             ctx.fillStyle = "black"
  212.             ctx.fillRect(0, 0, canvas.width, canvas.height)
  213.  
  214.             ctx.fillStyle = "red"
  215.             ctx.beginPath()
  216.             ctx.arc(head.location.x, head.location.y, 10, 0, 2 * Math.PI)
  217.             ctx.fill()
  218.  
  219.             ctx.fillStyle = "white"
  220.             parts.forEach((part, index) => {
  221.                 ctx.beginPath()
  222.                 ctx.arc(part.location.x, part.location.y, lerp(10, 7.5, index / parts.length), 0, 2 * Math.PI)
  223.                 ctx.fill()
  224.             })
  225.  
  226.             //debug...
  227.             // ctx.fillStyle = "blue"
  228.             // parts.forEach((part, index) => {
  229.             //     ctx.beginPath()
  230.             //     ctx.moveTo(part.location.x, part.location.y)
  231.             //     ctx.lineTo(part.parent.location.x, part.parent.location.y)
  232.             //     ctx.stroke()
  233.  
  234.             //     ctx.fillText(index, part.location.x, part.location.y);
  235.             // })
  236.  
  237.             foods.forEach(food => {
  238.                 ctx.fillStyle = `rgba(0,255,0,${1 - food.expiration})`
  239.                 ctx.beginPath()
  240.                 ctx.arc(food.location.x, food.location.y, 8, 0, 2 * Math.PI)
  241.                 ctx.fill()
  242.             })
  243.         }, 10)
  244.     }
  245. </script>
  246.  
  247. <canvas id="canvas"></canvas>
  248. <div id="ui">
  249.     <div id="score"></div>
  250.     <div id="pause-screen">
  251.         <div>Paused!</div>
  252.         <div>Put your cursor on the highlighted area to continue!</div>
  253.         <div id="pause-continue-countdown">0</div>
  254.         <div id="pause-continue-highlighted-area"></div>
  255.     </div>
  256. </div>
Add Comment
Please, Sign In to add comment