Демо JavaScript:
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>Infinite Cheese</title> </head> <body> <canvas height="500" width="500" id="сanvas"></canvas> <script src="https://cdnjs.cloudflare.com/ajax/libs/fabric.js/4.1.0/fabric.min.js"> </script> <script> var canvas = new fabric.Canvas('сanvas') var ctx = document.getElementById('сanvas').getContext('2d') var counterBites = 0 const SPEEDUP = 20 const BASESPEED = 1200 const MAXSPEED = 6 * BASESPEE</p></p>D / SPEEDUP canvas.on('mouse:down', function (e) { isInside({ x: e.pointer.x, y: e.pointer.y}) }) var counter = new fabric.Text(counterBites.toString(), { left: 470, top: 15, fontSize: 15, fontFamily: 'Georgia', fill: 'Yellow', selectable: false }); canvas.backgroundColor = '#722f37' var text = new fabric.Text('Bites: ', { left: 420, top: 15, fontSize: 15, fontFamily: 'Georgia', fill: 'Yellow', selectable: false }); var cheeseTopCoords = [ { x: 0, y: 0 }, { x: 80, y: 0 }, { x: 40, y: 60 }, ] var cheeseTopData = new fabric.Polygon(cheeseTopCoords, { fill: '#ffc444', originX: "center", originY: "center", }) var cheeseRightCoords = [ { x: 40, y: 60 }, { x: 40, y: 100 }, { x: 80, y: 40 }, { x: 80, y: 0 }, ] var cheeseRightData = new fabric.Polygon(cheeseRightCoords, { fill: '#e6a61d', originX: "center", originY: "center", }) var cheeseLeftCoords = [ { x: 0, y: 0 }, { x: 40, y: 60 }, { x: 40, y: 100 }, { x: 0, y: 40 }, ] var cheeseLeftData = new fabric.Polygon(cheeseLeftCoords, { fill: '#c58f1c', originX: "center", originY: "center", }) var cheese = new fabric.Group([cheeseTopData, cheeseRightData, cheeseLeftData], { left: 360, top: 350, selectable: false }) function animateRandom(){ var randomX = Math.round(Math.random()*420); var randomY = Math.round(Math.random()*400); cheese.animate({left: randomX, top: randomY}, { duration: MAXSPEED, onChange: canvas.renderAll.bind(canvas), easing: fabric.util.ease.easeOutExpo }) } function classify(pointS, pointE, pointC) { var pr = (pointE.x - pointS.x) * (pointC.y - pointS.y) - (pointE.y - pointS.y) * (pointC.x - pointS.x) if (pr > 0) return 1 // Точка слева от ребра else if (pr < 0) return -1 // Точка справа от ребра else return 0 // Точка на ребре } function edgeType(pointS, pointE, pointC) { var cl = classify(pointS, pointE, pointC) if (cl > 0) // Точка слева return ((pointS.y < pointC.y) && (pointC.y <= pointE.y)) ? 1 : 2 // Если точка внутри отрезка по y то горизональная прямая пересекает грань else if (cl < 0) // Точка справа return ((pointE.y < pointC.y) && (pointC.y <= pointS.y)) ? 1 : 2 // Если точка внутри отрезка по y то горизональная прямая пересекает грань else return 0 // Точка на ребре } function pointInPolygon(pol, point) { var parity = 0, et for (var i = 0; i < pol.length - 1; i++) { et = edgeType(pol[i], pol[i + 1], point) if (et == 0) return 2 else if (et == 1) parity = 1 - parity // Четность } et = edgeType(pol[i], pol[0], point) if (et == 0) return 2 else if (et == 1) parity = 1 - parity return parity } function getTempCoords(tmp) { offX = parseFloat(cheese.left) // Текущая координата x многоугольника offY = parseFloat(cheese.top) // Текущая координата y многоугольника return { x: offX + tmp.x, y: offY + tmp.y } } function isInTop(point) { var tmp = [...cheeseTopCoords] for (i = 0; i < tmp.length; i++) tmp[i] = getTempCoords(tmp[i]) return pointInPolygon(tmp, point) } function isInRight(point) { var tmp = [...cheeseRightCoords] for (i = 0; i < tmp.length; i++) tmp[i] = getTempCoords(tmp[i]) return pointInPolygon(tmp, point) } function isInLeft(point) { var tmp = [...cheeseLeftCoords] for (i = 0; i < tmp.length; i++) tmp[i] = getTempCoords(tmp[i]) return pointInPolygon(tmp, point) } function isInside(point) { if (isInTop(point) || isInRight(point) || isInLeft(point)) counterBites++ else counterBites = 0 counter.text = counterBites.toString() canvas.add(counter) animateRandom() clearInterval(intervalBase) intervalBase = setInterval(animateRandom, (BASESPEED - counterBites * SPEEDUP > MAXSPEED) ? BASESPEED - counterBites * SPEEDUP : MAXSPEED) } canvas.add(text) canvas.add(cheese) canvas.renderAll() var intervalBase = setInterval(animateRandom, BASESPEED); </script> </body> </html>
Прикрепленный файл | Размер |
---|---|
InfiniteCheese.zip | 1.77 кб |