불꽃놀이 효과를 얻기 위한 HTML5 Canvas 실용적인 코드 케이스

黄舟
풀어 주다: 2017-03-30 13:22:29
원래의
4200명이 탐색했습니다.

1. 효과

불꽃놀이 효과를 얻기 위한 HTML5 Canvas 실용적인 코드 케이스

2. 코드 분석

(1) requestAnimationFrame

requestAnimationFrame은 타이밍을 위해 사용됩니다 작업 반복을 위한 인터페이스 는 setTimeout과 유사하며 주요 목적은 웹 페이지를 프레임별로 다시 그리는 것입니다.

이 API를 설정하는 목적은 다양한 웹 페이지 애니메이션 효과(DOM 애니메이션, 캔버스 애니메이션, SVG 애니메이션, WebGL 애니메이션)가 통합된 새로 고침 메커니즘을 갖도록 하여 시스템 리소스를 절약하고 시스템 성능을 향상시키는 것입니다. 시각적 효과를 향상시킵니다. 코드에서 이 API를 사용하는 것은 애니메이션을 실행하고 싶다고 브라우저에 알리고 브라우저가 다음 애니메이션 프레임에서 웹 페이지를 다시 그리도록 예약하도록 하는 것입니다.

requestAnimationFrame의 장점은 디스플레이의 새로 고침 메커니즘을 최대한 활용하고 시스템 리소스를 절약한다는 것입니다. 디스플레이에는 고정된 새로 고침 빈도(60Hz 또는 75Hz)가 있습니다. 이는 초당 최대 60~75회만 다시 그릴 수 있음을 의미합니다. requestAnimationFrame의 기본 아이디어는 이 새로 고침 빈도와 동기화를 유지하고 이 새로 고침 빈도를 사용하는 것입니다. 페이지를 다시 그리려면 또한 이 API를 사용하면 페이지가 더 이상 브라우저의 현재 탭에 없으면 페이지 새로 고침이 자동으로 중지됩니다. 이렇게 하면 CPU, GPU 및 전력이 절약됩니다.

하지만 한 가지 주목할 점은 requestAnimationFrame이 메인 스레드에서 완료된다는 것입니다. 이는 메인 스레드가 매우 바쁜 경우 requestAnimationFrame의 애니메이션 효과가 크게 감소한다는 것을 의미합니다.

requestAnimationFrame은 콜백 함수를 매개변수로 사용합니다. 이 콜백 함수는 브라우저가 다시 그리기 전에 호출됩니다.

requestID = window.requestAnimationFrame(callback);
로그인 후 복사

현재 Firefox 23/IE 10/Chrome/Safari 상위 버전 브라우저에서 이 방법을 지원합니다. 다음 방법을 사용하여 브라우저가 이 API를 지원하는지 확인할 수 있습니다. 지원되지 않는 경우 배포 방법을 직접 시뮬레이션하세요.

window.requestAnimFrame = (function(){      
return  window.requestAnimationFrame       || 
              window.webkitRequestAnimationFrame || 
              window.mozRequestAnimationFrame    || 
              window.oRequestAnimationFrame      || 
              window.msRequestAnimationFrame     || 
              function( callback ){
                window.setTimeout(callback, 1000 / 60);
              };
})();
로그인 후 복사

위 코드는 requestAnimationFrame을 초당 60회(대략 16.7밀리초마다 한 번씩) 시뮬레이션합니다.

requestAnimationFrame을 사용할 때는 반복적으로 호출하면 됩니다.

function repeatOften() {  // Do whatever  requestAnimationFrame(repeatOften);
}

requestAnimationFrame(repeatOften);
로그인 후 복사

cancelAnimationFrame을 사용하여 다시 그리기를 취소합니다.

window.cancelAnimationFrame(requestID);
로그인 후 복사

해당 매개변수는 작업 ID를 나타내는 requestAnimationFrame이 반환한 정수 값입니다.

(2) 캔버스(canvas) 준비

브라우저가 캔버스를 지원하는지 확인하고, 너비와 높이를 브라우저 창 크기에 맞게 설정합니다.

var canvas = document.getElementById("myCanvas");
if (!canvas.getContext) {    return;
}
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;var ctx = canvas.getContext("2d");
로그인 후 복사

(3) 불꽃놀이 개체(FireWork)

폭죽 효과는 간단히 점을 둘러싸는 것으로 생각하면 되며, 폭발하면 옆으로 퍼지는 작은 공이 많이 생성됩니다. 따라서 불꽃놀이 개체가 필요합니다. 이 개체는 주로 불꽃놀이의 위치와 주변 공에 대한 정보를 기록합니다. 그래서 우리의 불꽃놀이 객체는 다음과 같이 정의됩니다.

function FireWork() {    
this.x = -1;    
this.y = -1;    
this.balls = [];
}
로그인 후 복사

그럼 이 객체에는 어떤 메소드가 있어야 할까요?

먼저 폭발하는 작은 공을 만듭니다.

createBalls: function () {        
for (var i = 0; i < 300; i++) {            
var angle = Math.random() * Math.PI * 2,
radius = getRandom(50, 200);            
this.balls.push(new Ball(fwx, fwy, fwx + Math.cos(angle) * radius, fwy + Math.sin(angle) * radius));
        }
    }
로그인 후 복사

참고: 여기서 fwx는 불꽃놀이 위치의 X축 좌표이고, fwy는 불꽃놀이 위치의 Y축 좌표입니다. 아래와 같습니다.

여기서 공의 이동 길이는 50~200 사이의 임의의 값입니다. 공의 궤적의 시작점은 불꽃놀이의 위치이고 끝점은 원 위의 임의의 지점입니다.

그런 다음 주로 위치를 결정하고 작은 공을 생성하기 위해 불꽃놀이를 초기화해야 합니다.

init: function () {        
this.x = getRandom(200, width - 200);        
this.y = getRandom(200, height - 200);
        fwx = this.x;
        fwy = this.y;        
        this.createBalls();
        drawCount = 0;
        currBallIndex = 0;
    }
로그인 후 복사

참고: 여기서 drawCount는 추첨 횟수이고 currBallIndex는 현재 추첨된 공 인덱스 입니다.

FireWork 전체는 다음과 같이 정의됩니다.

function FireWork() {    
this.x = -1;    
this.y = -1;    
this.balls = [];
}

FireWork.prototype = {
    init: function () {        
    this.x = getRandom(200, width - 200);        
    this.y = getRandom(200, height - 200);
        fwx = this.x;
        fwy = this.y;        
        this.createBalls();
        drawCount = 0;
        currBallIndex = 0;
    },
    run: function () {        
    this.init();
    },
    createBalls: function () {        
    for (var i = 0; i < 300; i++) {            
    var angle = Math.random() * Math.PI * 2,
                
  radius = getRandom(50, 200);            
this.balls.push(new Ball(fwx, fwy, fwx + Math.cos(angle) * radius, fwy + Math.sin(angle) * radius));
        }
    }
}
로그인 후 복사

(4) 폭발로 생성된 공 객체(Ball)

공은 시작점과 끝점의 위치를 ​​알아야 하므로 다음과 같이 정의됩니다. 다음과 같습니다.

function Ball(bx, by, ex, ey) {    this.bx = bx;//起点X轴坐标
    this.by = by;//起点Y轴坐标
    this.ex = ex;//终点X轴坐标
    this.ey = ey;//终点Y轴坐标}
로그인 후 복사

공은 현재 추첨 횟수와 총 추첨 횟수를 바탕으로 현재 좌표와 다음 그리기 좌표를 계산할 수 있어야 합니다. 이 두 좌표를 연결하는 직선이 그려지는 내용입니다. 이번에는 다음과 같이 정의됩니다.

Ball.prototype = {
    getSpan: function () {        
    var xSpan = (this.ex - this.bx) / allDrawCount,
            ySpan = (this.ey - this.by) / allDrawCount;        
            return {
            x: xSpan,
            y: ySpan
        };
    },
    currPosition: function () {        
    var span = this.getSpan(),
            currX = -1,
            currY = -1;        
            if (drawCount < allDrawCount) {
            currX = this.bx + span.x * (drawCount - 1);
            currY = this.by + span.y * (drawCount - 1);            
            return {
                x: currX,
                y: currY
            };
        }        return null;
    },
    nextPosition: function () {        
    var span = this.getSpan(),
            currX = -1,
            currY = -1;        
            if (drawCount < allDrawCount) {
            currX = this.bx + span.x * drawCount;
            currY = this.by + span.y * drawCount;            
            return {
                x: currX,
                y: currY
            };
        }        return null;
    }
}
로그인 후 복사

(5) 전역 변수와 도구 메서드

var fwx = -1,                 //烟花位置X轴坐标
    fwy = -1,                 //烟花位置Y轴坐标
    currFW = null,            //烟花实例
    currBallIndex = -1,       //当前正在绘制的小球索引
    drawCount = 0,            //绘制次数
    allDrawCount = 40,        //总共需要的绘制次数
    width = canvas.width,     //画布宽度
    height = canvas.height;   //画布高度
로그인 후 복사

그 다음에는 여러 가지 도구 메서드가 있습니다.

function componentToHex(c) {    
var hex = c.toString(16);    
return hex.length == 1 ? "0" + hex : hex;
}function rgbToHex(r, g, b) {    
return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b);
}function getRandom(minNum, maxNum) {    
var iChoices = maxNum - minNum + 1;      
return Math.floor(Math.random() * iChoices + minNum);
}
로그인 후 복사

(6) 그리기 방법

드디어 requestAnimationFrame이 호출할 그리기 방법이 하나 남았습니다. 이 그리기 방법은 현재 그리는 갯수를 기준으로 폭발하는 공의 경로(시작점과 끝점을 포함하는 선분)를 구한 후, 마지막으로 그린 ​​경로를 지우는 것입니다.

하나의 불꽃 효과가 그려지면 다음 불꽃 그리기를 진행합니다.

function drawLine(span) {    
if (currFW && currBallIndex !== -1) {        
if (drawCount <= allDrawCount) {
            ctx.save();
            drawCount++;            
            for (var i = 0, j = currFW.balls.length; i < j; i++) {                
            var currBall = currFW.balls[i],
                    beginPoint = currBall.currPosition(),
                    endPoint = currBall.nextPosition();                
                    if (beginPoint && endPoint) {
                    console.log(currBallIndex, drawCount, currBall, beginPoint, endPoint);
                    ctx.beginPath();
                    ctx.moveTo(currBall.bx, currBall.by);
                    ctx.lineTo(beginPoint.x, beginPoint.y);
                    ctx.strokeStyle = "#000";
                    ctx.stroke();
                    ctx.beginPath();
                    ctx.moveTo(beginPoint.x, beginPoint.y);
                    ctx.lineTo(endPoint.x, endPoint.y);                    
                    var r = getRandom(0, 255);                    
                    var g = getRandom(0, 255);                    
                    var b = getRandom(0, 255);
                    ctx.strokeStyle = rgbToHex(r, g, b);
                    ctx.stroke();
                } else {
                    ctx.beginPath();
                    ctx.moveTo(currBall.bx, currBall.by);
                    ctx.lineTo(currBall.ex, currBall.ey);
                    ctx.strokeStyle = "#000";
                    ctx.stroke();
                }
            }
            currBallIndex++;
            currBallIndex %= currFW.balls.length;
            ctx.restore();
        } else {
            ctx.clearRect(0, 0, width, height);
            currFW = new FireWork();
            currFW.run();
        }
    }
    requestAnimationFrame(drawLine);
}
로그인 후 복사

여기 색상은 임의의 값입니다.

(7) 그리기 시작

마지막 단계는 그리기 시작입니다.

currFW = new FireWork();
currFW.run();
requestAnimationFrame(drawLine);
로그인 후 복사

(8) 모든 코드.

전체 코드는 다음과 같으며, 총 160줄입니다.

아아아아

토론에 오신 것을 환영합니다.

위 내용은 불꽃놀이 효과를 얻기 위한 HTML5 Canvas 실용적인 코드 케이스의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿
회사 소개 부인 성명 Sitemap
PHP 중국어 웹사이트:공공복지 온라인 PHP 교육,PHP 학습자의 빠른 성장을 도와주세요!