aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/web/api/canvas_api/tutorial/basic_animations
diff options
context:
space:
mode:
authorPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
committerPeter Bengtsson <mail@peterbe.com>2020-12-08 14:40:17 -0500
commit33058f2b292b3a581333bdfb21b8f671898c5060 (patch)
tree51c3e392513ec574331b2d3f85c394445ea803c6 /files/zh-cn/web/api/canvas_api/tutorial/basic_animations
parent8b66d724f7caf0157093fb09cfec8fbd0c6ad50a (diff)
downloadtranslated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.gz
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.tar.bz2
translated-content-33058f2b292b3a581333bdfb21b8f671898c5060.zip
initial commit
Diffstat (limited to 'files/zh-cn/web/api/canvas_api/tutorial/basic_animations')
-rw-r--r--files/zh-cn/web/api/canvas_api/tutorial/basic_animations/index.html718
1 files changed, 718 insertions, 0 deletions
diff --git a/files/zh-cn/web/api/canvas_api/tutorial/basic_animations/index.html b/files/zh-cn/web/api/canvas_api/tutorial/basic_animations/index.html
new file mode 100644
index 0000000000..531fef8cb1
--- /dev/null
+++ b/files/zh-cn/web/api/canvas_api/tutorial/basic_animations/index.html
@@ -0,0 +1,718 @@
+---
+title: 基本的动画
+slug: Web/API/Canvas_API/Tutorial/Basic_animations
+tags:
+ - Canvas
+ - HTML5
+ - 动画
+ - 图像
+ - 教程
+ - 进阶
+translation_of: Web/API/Canvas_API/Tutorial/Basic_animations
+---
+<div>{{CanvasSidebar}} {{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}</div>
+
+<div class="summary">
+<p>由于我们是用 JavaScript 去操控 {{HTMLElement("canvas")}} 对象,这样要实现一些交互动画也是相当容易的。在本章中,我们将看看如何做一些基本的动画。</p>
+</div>
+
+<p>可能最大的限制就是图像一旦绘制出来,它就是一直保持那样了。如果需要移动它,我们不得不对所有东西(包括之前的)进行重绘。重绘是相当费时的,而且性能很依赖于电脑的速度。</p>
+
+<h2 id="Basic_animation_steps" name="Basic_animation_steps">动画的基本步骤</h2>
+
+<p>你可以通过以下的步骤来画出一帧:</p>
+
+<ol>
+ <li><strong>清空 canvas</strong><br>
+ 除非接下来要画的内容会完全充满 canvas (例如背景图),否则你需要清空所有。最简单的做法就是用 <code>clearRect</code> 方法。</li>
+ <li><strong>保存 canvas 状态</strong><br>
+ 如果你要改变一些会改变 canvas 状态的设置(样式,变形之类的),又要在每画一帧之时都是原始状态的话,你需要先保存一下。</li>
+ <li><strong>绘制动画图形(animated shapes)</strong><br>
+ 这一步才是重绘动画帧。</li>
+ <li><strong>恢复 canvas 状态</strong><br>
+ 如果已经保存了 canvas 的状态,可以先恢复它,然后重绘下一帧。</li>
+</ol>
+
+<h2 id="Controlling_an_animation" name="Controlling_an_animation">操控动画 Controlling an animation</h2>
+
+<p>在 canvas 上绘制内容是用 canvas 提供的或者自定义的方法,而通常,我们仅仅在脚本执行结束后才能看见结果,比如说,在 for 循环里面做完成动画是不太可能的。</p>
+
+<p>因此, 为了实现动画,我们需要一些可以定时执行重绘的方法。有两种方法可以实现这样的动画操控。首先可以通过 <code>setInterval</code> 和 <code>setTimeout</code> 方法来控制在设定的时间点上执行重绘。</p>
+
+<h3 id="有安排的更新画布_Scheduled_updates"><strong>有安排的更新画布 </strong>Scheduled updates</h3>
+
+<p>首先,可以用{{domxref("window.setInterval()")}}, {{domxref("window.setTimeout()")}},和{{domxref("window.requestAnimationFrame()")}}来设定定期执行一个指定函数。</p>
+
+<dl>
+ <dt>{{domxref("WindowTimers.setInterval", "setInterval(function, delay)")}}</dt>
+ <dd>当设定好间隔时间后,function会定期执行。</dd>
+ <dt>{{domxref("WindowTimers.setTimeout", "setTimeout(function, delay)")}}</dt>
+ <dt>在设定好的时间之后执行函数</dt>
+ <dd></dd>
+ <dt>{{domxref("Window.requestAnimationFrame()", "requestAnimationFrame(callback)")}}</dt>
+ <dd>告诉浏览器你希望执行一个动画,并在重绘之前,请求浏览器执行一个特定的函数来更新动画。</dd>
+</dl>
+
+<p>如果你并不需要与用户互动,你可以使用setInterval()方法,它就可以定期执行指定代码。如果我们需要做一个游戏,我们可以使用键盘或者鼠标事件配合上setTimeout()方法来实现。通过设置事件监听,我们可以捕捉用户的交互,并执行相应的动作。</p>
+
+<div class="note">
+<p>下面的例子,采用 {{domxref("window.requestAnimationFrame()")}}实现动画效果。这个方法提供了更加平缓并更加有效率的方式来执行动画,当系统准备好了重绘条件的时候,才调用绘制动画帧。一般每秒钟回调函数执行60次,也有可能会被降低。想要了解更多关于动画循环的信息,尤其是游戏,可以在<a href="https://developer.mozilla.org/zh-CN/docs/Games">Game development zone</a> 参考这篇文章 <a href="https://developer.mozilla.org/zh-CN/docs/Games/Anatomy">Anatomy of a video game</a>。</p>
+</div>
+
+<h2 id="太阳系的动画">太阳系的动画</h2>
+
+<p>这个例子里面,我会做一个小型的太阳系模拟动画。</p>
+
+<pre class="brush: js">var sun = new Image();
+var moon = new Image();
+var earth = new Image();
+function init(){
+ sun.src = 'https://mdn.mozillademos.org/files/1456/Canvas_sun.png';
+ moon.src = 'https://mdn.mozillademos.org/files/1443/Canvas_moon.png';
+ earth.src = 'https://mdn.mozillademos.org/files/1429/Canvas_earth.png';
+ window.requestAnimationFrame(draw);
+}
+
+function draw() {
+ var ctx = document.getElementById('canvas').getContext('2d');
+
+ ctx.globalCompositeOperation = 'destination-over';
+ ctx.clearRect(0,0,300,300); // clear canvas
+
+ ctx.fillStyle = 'rgba(0,0,0,0.4)';
+ ctx.strokeStyle = 'rgba(0,153,255,0.4)';
+ ctx.save();
+ ctx.translate(150,150);
+
+ // Earth
+ var time = new Date();
+ ctx.rotate( ((2*Math.PI)/60)*time.getSeconds() + ((2*Math.PI)/60000)*time.getMilliseconds() );
+ ctx.translate(105,0);
+ ctx.fillRect(0,-12,50,24); // Shadow
+ ctx.drawImage(earth,-12,-12);
+
+ // Moon
+ ctx.save();
+ ctx.rotate( ((2*Math.PI)/6)*time.getSeconds() + ((2*Math.PI)/6000)*time.getMilliseconds() );
+ ctx.translate(0,28.5);
+ ctx.drawImage(moon,-3.5,-3.5);
+ ctx.restore();
+
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.arc(150,150,105,0,Math.PI*2,false); // Earth orbit
+ ctx.stroke();
+
+ ctx.drawImage(sun,0,0,300,300);
+
+ window.requestAnimationFrame(draw);
+}
+
+init();
+</pre>
+
+<div class="hidden">
+<pre class="brush: html">&lt;canvas id="canvas" width="300" height="300"&gt;&lt;/canvas&gt;</pre>
+</div>
+
+<p>{{EmbedLiveSample("太阳系的动画", "310", "310", "https://mdn.mozillademos.org/files/202/Canvas_animation1.png")}}</p>
+
+<h2 id="动画时钟">动画时钟</h2>
+
+<p>这个例子实现一个动态时钟, 可以显示当前时间。</p>
+
+<pre class="brush: js">function clock(){
+ var now = new Date();
+ var ctx = document.getElementById('canvas').getContext('2d');
+ ctx.save();
+ ctx.clearRect(0,0,150,150);
+ ctx.translate(75,75);
+ ctx.scale(0.4,0.4);
+ ctx.rotate(-Math.PI/2);
+ ctx.strokeStyle = "black";
+ ctx.fillStyle = "white";
+ ctx.lineWidth = 8;
+ ctx.lineCap = "round";
+
+ // Hour marks
+ ctx.save();
+ for (var i=0;i&lt;12;i++){
+ ctx.beginPath();
+ ctx.rotate(Math.PI/6);
+ ctx.moveTo(100,0);
+ ctx.lineTo(120,0);
+ ctx.stroke();
+ }
+ ctx.restore();
+
+ // Minute marks
+ ctx.save();
+ ctx.lineWidth = 5;
+ for (i=0;i&lt;60;i++){
+ if (i%5!=0) {
+ ctx.beginPath();
+ ctx.moveTo(117,0);
+ ctx.lineTo(120,0);
+ ctx.stroke();
+ }
+ ctx.rotate(Math.PI/30);
+ }
+ ctx.restore();
+
+ var sec = now.getSeconds();
+ var min = now.getMinutes();
+ var hr = now.getHours();
+ hr = hr&gt;=12 ? hr-12 : hr;
+
+ ctx.fillStyle = "black";
+
+ // write Hours
+ ctx.save();
+ ctx.rotate( hr*(Math.PI/6) + (Math.PI/360)*min + (Math.PI/21600)*sec )
+ ctx.lineWidth = 14;
+ ctx.beginPath();
+ ctx.moveTo(-20,0);
+ ctx.lineTo(80,0);
+ ctx.stroke();
+ ctx.restore();
+
+ // write Minutes
+ ctx.save();
+ ctx.rotate( (Math.PI/30)*min + (Math.PI/1800)*sec )
+ ctx.lineWidth = 10;
+ ctx.beginPath();
+ ctx.moveTo(-28,0);
+ ctx.lineTo(112,0);
+ ctx.stroke();
+ ctx.restore();
+
+ // Write seconds
+ ctx.save();
+ ctx.rotate(sec * Math.PI/30);
+ ctx.strokeStyle = "#D40000";
+ ctx.fillStyle = "#D40000";
+ ctx.lineWidth = 6;
+ ctx.beginPath();
+ ctx.moveTo(-30,0);
+ ctx.lineTo(83,0);
+ ctx.stroke();
+ ctx.beginPath();
+ ctx.arc(0,0,10,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.beginPath();
+ ctx.arc(95,0,10,0,Math.PI*2,true);
+ ctx.stroke();
+ ctx.fillStyle = "rgba(0,0,0,0)";
+ ctx.arc(0,0,3,0,Math.PI*2,true);
+ ctx.fill();
+ ctx.restore();
+
+ ctx.beginPath();
+ ctx.lineWidth = 14;
+ ctx.strokeStyle = '#325FA2';
+ ctx.arc(0,0,142,0,Math.PI*2,true);
+ ctx.stroke();
+
+ ctx.restore();
+
+ window.requestAnimationFrame(clock);
+}
+
+window.requestAnimationFrame(clock);
+</pre>
+
+<div class="hidden">
+<pre class="brush: html">&lt;canvas id="canvas" width="150" height="150"&gt;&lt;/canvas&gt;</pre>
+</div>
+
+<p>{{EmbedLiveSample("动画时钟", "180", "180", "https://mdn.mozillademos.org/files/203/Canvas_animation2.png")}}</p>
+
+<h2 id="循环全景照片">循环全景照片</h2>
+
+<p>在这个例子中,会有一个自左向右滑动的全景图。我们使用了在维基百科中找到的<a href="https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg">尤塞米提国家公园的图片</a>,当然你可以随意找一张任何尺寸大于canvas的图片。</p>
+
+<pre class="brush: js">var img = new Image();
+
+// User Variables - customize these to change the image being scrolled, its
+// direction, and the speed.
+
+img.src = 'https://mdn.mozillademos.org/files/4553/Capitan_Meadows,_Yosemite_National_Park.jpg';
+var CanvasXSize = 800;
+var CanvasYSize = 200;
+var speed = 30; // lower is faster
+var scale = 1.05;
+var y = -4.5; // vertical offset
+
+// Main program
+
+var dx = 0.75;
+var imgW;
+var imgH;
+var x = 0;
+var clearX;
+var clearY;
+var ctx;
+
+img.onload = function() {
+ imgW = img.width * scale;
+ imgH = img.height * scale;
+
+  if (imgW &gt; CanvasXSize) {
+  // image larger than canvas
+  x = CanvasXSize - imgW;
+  }
+ if (imgW &gt; CanvasXSize) {
+  // image width larger than canvas
+  clearX = imgW;
+  } else {
+  clearX = CanvasXSize;
+  }
+ if (imgH &gt; CanvasYSize) {
+  // image height larger than canvas
+  clearY = imgH;
+  } else {
+  clearY = CanvasYSize;
+  }
+
+ // get canvas context
+ ctx = document.getElementById('canvas').getContext('2d');
+
+  // set refresh rate
+ return setInterval(draw, speed);
+}
+
+function draw() {
+ ctx.clearRect(0, 0, clearX, clearY); // clear the canvas
+
+  // if image is &lt;= Canvas Size
+ if (imgW &lt;= CanvasXSize) {
+ // reset, start from beginning
+ if (x &gt; CanvasXSize) {
+  x = -imgW + x;
+  }
+ // draw additional image1
+ if (x &gt; 0) {
+  ctx.drawImage(img, -imgW + x, y, imgW, imgH);
+  }
+ // draw additional image2
+ if (x - imgW &gt; 0) {
+  ctx.drawImage(img, -imgW * 2 + x, y, imgW, imgH);
+  }
+ }
+
+ // image is &gt; Canvas Size
+ else {
+ // reset, start from beginning
+ if (x &gt; (CanvasXSize)) {
+  x = CanvasXSize - imgW;
+  }
+ // draw aditional image
+ if (x &gt; (CanvasXSize-imgW)) {
+  ctx.drawImage(img, x - imgW + 1, y, imgW, imgH);
+  }
+ }
+ // draw image
+ ctx.drawImage(img, x, y,imgW, imgH);
+ // amount to move
+ x += dx;
+}</pre>
+
+<div class="hidden">
+<pre class="brush: html">&lt;canvas id="canvas" width="800" height="200"&gt;&lt;/canvas&gt;</pre>
+</div>
+
+<p>下方就是是图片在其中滑动的 {{HTMLElement("canvas")}}。需要注意的是这里定义的width和height必须与JavaScript代码中的变量值<code>CanvasXZSize</code>和<code>CanvasYSize</code>保持一致。 </p>
+
+<pre>&lt;canvas id="canvas" width="800" height="200"&gt;&lt;/canvas&gt;</pre>
+
+<p>{{EmbedLiveSample("循环全景照片", "830", "230")}}</p>
+
+<h2 id="鼠标追踪动画">鼠标追踪动画</h2>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+    &lt;head&gt;
+        &lt;meta charset="UTF-8"&gt;
+        &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
+        &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
+        &lt;title&gt;Document&lt;/title&gt;
+        &lt;script&gt;
+            var cn;
+            //= document.getElementById('cw');
+            var c;
+            var u = 10;
+            const m = {
+                x: innerWidth / 2,
+                y: innerHeight / 2
+            };
+            window.onmousemove = function(e) {
+                m.x = e.clientX;
+                m.y = e.clientY;
+
+            }
+            function gc() {
+                var s = "0123456789ABCDEF";
+                var c = "#";
+                for (var i = 0; i &lt; 6; i++) {
+                    c += s[Math.ceil(Math.random() * 15)]
+                }
+                return c
+            }
+            var a = [];
+            window.onload = function myfunction() {
+                cn = document.getElementById('cw');
+                c = cn.getContext('2d');
+
+                for (var i = 0; i &lt; 10; i++) {
+                    var r = 30;
+                    var x = Math.random() * (innerWidth - 2 * r) + r;
+                    var y = Math.random() * (innerHeight - 2 * r) + r;
+                    var t = new ob(innerWidth / 2,innerHeight / 2,5,"red",Math.random() * 200 + 20,2);
+                    a.push(t);
+                }
+                //cn.style.backgroundColor = "#700bc8";
+
+                c.lineWidth = "2";
+                c.globalAlpha = 0.5;
+                resize();
+                anim()
+            }
+            window.onresize = function() {
+
+                resize();
+
+            }
+            function resize() {
+                cn.height = innerHeight;
+                cn.width = innerWidth;
+                for (var i = 0; i &lt; 101; i++) {
+                    var r = 30;
+                    var x = Math.random() * (innerWidth - 2 * r) + r;
+                    var y = Math.random() * (innerHeight - 2 * r) + r;
+                    a[i] = new ob(innerWidth / 2,innerHeight / 2,4,gc(),Math.random() * 200 + 20,0.02);
+
+                }
+                //  a[0] = new ob(innerWidth / 2, innerHeight / 2, 40, "red", 0.05, 0.05);
+                //a[0].dr();
+            }
+            function ob(x, y, r, cc, o, s) {
+                this.x = x;
+                this.y = y;
+                this.r = r;
+                this.cc = cc;
+                this.theta = Math.random() * Math.PI * 2;
+                this.s = s;
+                this.o = o;
+                this.t = Math.random() * 150;
+
+                this.o = o;
+                this.dr = function() {
+                    const ls = {
+                        x: this.x,
+                        y: this.y
+                    };
+                    this.theta += this.s;
+                    this.x = m.x + Math.cos(this.theta) * this.t;
+                    this.y = m.y + Math.sin(this.theta) * this.t;
+                    c.beginPath();
+                    c.lineWidth = this.r;
+                    c.strokeStyle = this.cc;
+                    c.moveTo(ls.x, ls.y);
+                    c.lineTo(this.x, this.y);
+                    c.stroke();
+                    c.closePath();
+
+                }
+            }
+            function anim() {
+                requestAnimationFrame(anim);
+                c.fillStyle = "rgba(0,0,0,0.05)";
+                c.fillRect(0, 0, cn.width, cn.height);
+                a.forEach(function(e, i) {
+                    e.dr();
+                });
+
+            }
+        &lt;/script&gt;
+        &lt;style&gt;
+            #cw {
+                position: fixed;
+                z-index: -1;
+            }
+
+            body {
+                margin: 0;
+                padding: 0;
+                background-color: rgba(0,0,0,0.05);
+            }
+        &lt;/style&gt;
+    &lt;/head&gt;
+    &lt;body&gt;
+        &lt;canvas id="cw"&gt;&lt;/canvas&gt;
+        qwerewr
+
+    &lt;/body&gt;
+&lt;/html&gt;
+</pre>
+
+<h5 id="OutPut">OutPut</h5>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <td>
+ <p><a href="https://kunalverma94.github.io/gallery/gags/beyblade.html"><img alt="beyblade" src="https://kunalverma94.github.io/gallery/beyblade.jpg" style="height: 298px; width: 399px;"></a></p>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Snake_Game">Snake Game</h2>
+
+<pre class="brush: html">&lt;!DOCTYPE html&gt;
+&lt;html lang="en"&gt;
+
+&lt;head&gt;
+    &lt;meta charset="UTF-8"&gt;
+    &lt;meta name="viewport" content="width=device-width,initial-scale=1"&gt;
+    &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
+    &lt;title&gt;Nokia 1100:snake..Member berries&lt;/title&gt;
+&lt;/head&gt;
+
+&lt;body&gt;
+    &lt;div class="keypress hide"&gt;
+        &lt;div class="up" onclick="emit(38)"&gt;&amp;#8593;&lt;/div&gt;
+        &lt;div class="right" onclick="emit(39)"&gt;&amp;#8594;&lt;/div&gt;
+        &lt;div class="left" onclick="emit(37)"&gt;&amp;#8592;&lt;/div&gt;
+        &lt;div class="down" onclick="emit(40)"&gt;&amp;#8595;&lt;/div&gt;
+    &lt;/div&gt;
+    &lt;div class="banner" id="selector"&gt;
+        &lt;div&gt;
+            Time :&lt;span id="time"&gt;0&lt;/span&gt;
+        &lt;/div&gt;
+        &lt;div&gt;LousyGames ©&lt;/div&gt;
+        &lt;div&gt;
+            Score :&lt;span id="score"&gt;0&lt;/span&gt;
+        &lt;/div&gt;
+        &lt;div class="touch off" onclick="touch(this)"&gt;touch&lt;/div&gt;
+    &lt;/div&gt;
+    &lt;canvas id="main"&gt;&lt;/canvas&gt;
+&lt;/body&gt;
+&lt;style&gt;
+    body {
+        margin: 0;
+        overflow: hidden;
+        background: #000
+    }
+
+    .banner {
+        text-align: center;
+        color: #fff;
+        background: #3f51b5;
+        line-height: 29px;
+        position: fixed;
+        left: 0;
+        top: 0;
+        right: 0;
+        font-family: monospace;
+        height: 30px;
+        opacity: .4;
+        display: flex;
+        transition: .5s
+    }
+
+    .banner:hover {
+        opacity: 1
+    }
+
+    div#selector&gt;div {
+        flex-basis: 30%
+    }
+
+    @keyframes diss {
+        from {
+            opacity: 1
+        }
+
+        to {
+            opacity: 0
+        }
+    }
+
+    .keypress&gt;div {
+        border: dashed 3px #fff;
+        height: 48%;
+        width: 48%;
+        display: flex;
+        align-content: center;
+        justify-content: center;
+        align-self: center;
+        align-items: center;
+        font-size: -webkit-xxx-large;
+        font-weight: 900;
+        color: #fff;
+        transition: .5s;
+        opacity: .1;
+        border-radius: 7px
+    }
+
+    .keypress {
+        position: fixed;
+        width: 100vw;
+        height: 100vh;
+        top: 0;
+        left: 0;
+        display: flex;
+        flex-wrap: wrap;
+        justify-content: space-around;
+        opacity: 1;
+        user-select: none
+    }
+
+    .keypress&gt;div:hover {
+        opacity: 1
+    }
+
+    .touch {
+        background: #8bc34a
+    }
+
+    .off {
+        background: #f44336
+    }
+
+    .hide {
+        opacity: 0
+    }
+&lt;/style&gt;
+&lt;/html&gt;</pre>
+
+<p>Javascript</p>
+
+<pre class="brush: js">function tmz() {
+        var e = new Date(t),
+            i = new Date,
+            n = Math.abs(i.getMinutes() - e.getMinutes()),
+            o = Math.abs(i.getSeconds() - e.getSeconds());
+        return n + " : " + o
+    }
+
+    function coll(t, e) {
+        return t.x &lt; e.x + e.w &amp;&amp; t.x + t.w &gt; e.x &amp;&amp; t.y &lt; e.y + e.h &amp;&amp; t.h + t.y &gt; e.y
+    }
+
+    function snake() {
+        this.w = 15, this.h = 15, this.dx = 1, this.dy = 1, this.xf = 1, this.yf = 1, this.sn = [];
+        for (var t = {
+            x: w / 2,
+            y: h / 2
+        }, e = 0; e &lt; 5; e++) this.sn.push(Object.assign({}, t)), t.x += this.w;
+        this.draw = function () {
+            var t = d &amp;&amp; d.search("Arrow") &gt; -1,
+                e = -1;
+            if (t) {
+                var i = {
+                    ...this.sn[0]
+                };
+                if ("ArrowUp" == d &amp;&amp; (i.y -= this.h), "ArrowDown" == d &amp;&amp; (i.y += this.h), "ArrowLeft" == d &amp;&amp; (i.x -= this.w), "ArrowRight" == d &amp;&amp; (i.x += this.w), i.x &gt;= w ? i.x = 0 : i.x &lt; 0 &amp;&amp; (i.x = w - this.w), i.y &gt; h ? i.y = 0 : i.y &lt; 0 &amp;&amp; (i.y = h), e = fa.findIndex(t =&gt; coll({
+                    ...this.sn[0],
+                    h: this.h,
+                    w: this.w
+                }, t)), this.sn.unshift(i), -1 != e) return console.log(e), fa[e].renew(), void (document.getElementById("score").innerText = Number(document.getElementById("score").innerText) + 1);
+                this.sn.pop(), console.log(6)
+            }
+            this.sn.forEach((t, e, i) =&gt; {
+                if (0 == e || i.length - 1 == e) {
+                    var n = c.createLinearGradient(t.x, t.y, t.x + this.w, t.y + this.h);
+                    i.length - 1 == e ? (n.addColorStop(0, "black"), n.addColorStop(1, "#8BC34A")) : (n.addColorStop(0, "#8BC34A"), n.addColorStop(1, "white")), c.fillStyle = n
+                } else c.fillStyle = "#8BC34A";
+                c.fillRect(t.x, t.y, this.w, this.h), c.strokeStyle = "#E91E63", c.font = "30px serif", c.strokeStyle = "#9E9E9E", i.length - 1 != e &amp;&amp; 0 != e &amp;&amp; c.strokeRect(t.x, t.y, this.w, this.h), 0 == e &amp;&amp; (c.beginPath(), c.fillStyle = "#F44336", c.arc(t.x + 10, t.y + 2, 5, 360, 0), c.fill()), c.arc(t.x + 10, t.y + 2, 5, 360, 0), c.fill(), c.beginPath()
+            })
+        }
+    }
+
+    function gc() {
+        for (var t = "0123456789ABCDEF", e = "#", i = 0; i &lt; 6; i++) e += t[Math.ceil(15 * Math.random())];
+        return e
+    }
+
+    function food() {
+        this.x = 0, this.y = 0, this.b = 10, this.w = this.b, this.h = this.b, this.color = gc(), this.renew = function () {
+            this.x = Math.floor(Math.random() * (w - 200) + 10), this.y = Math.floor(Math.random() * (h - 200) + 30), this.color = gc()
+        }, this.renew(), this.put = (() =&gt; {
+            c.fillStyle = this.color, c.arc(this.x, this.y, this.b - 5, 0, 2 * Math.PI), c.fill(), c.beginPath(), c.arc(this.x, this.y, this.b - 5, 0, Math.PI), c.strokeStyle = "green", c.lineWidth = 10, c.stroke(), c.beginPath(), c.lineWidth = 1
+        })
+    }
+
+    function init() {
+        cc.height = h, cc.width = w, c.fillRect(0, 0, w, innerHeight);
+        for (var t = 0; t &lt; 10; t++) fa.push(new food);
+        s = new snake(w / 2, h / 2, 400, 4, 4), anima()
+    }
+
+    function anima() {
+        c.fillStyle = "rgba(0,0,0,0.11)", c.fillRect(0, 0, cc.width, cc.height), fa.forEach(t =&gt; t.put()), s.draw(), document.getElementById("time").innerText = tmz(), setTimeout(() =&gt; {
+            requestAnimationFrame(anima)
+        }, fw)
+    }
+
+    function emit(t) {
+        key.keydown(t)
+    }
+
+    function touch(t) {
+        t.classList.toggle("off"), document.getElementsByClassName("keypress")[0].classList.toggle("hide")
+    }
+    var t = new Date + "",
+        d = void 0,
+        cc = document.getElementsByTagName("canvas")[0],
+        c = cc.getContext("2d");
+    key = {}, key.keydown = function (t) {
+        var e = document.createEvent("KeyboardEvent");
+        Object.defineProperty(e, "keyCode", {
+            get: function () {
+                return this.keyCodeVal
+            }
+        }), Object.defineProperty(e, "key", {
+            get: function () {
+                return 37 == this.keyCodeVal ? "ArrowLeft" : 38 == this.keyCodeVal ? "ArrowUp" : 39 == this.keyCodeVal ? "ArrowRight" : "ArrowDown"
+            }
+        }), Object.defineProperty(e, "which", {
+            get: function () {
+                return this.keyCodeVal
+            }
+        }), e.initKeyboardEvent ? e.initKeyboardEvent("keydown", !0, !0, document.defaultView, !1, !1, !1, !1, t, t) : e.initKeyEvent("keydown", !0, !0, document.defaultView, !1, !1, !1, !1, t, 0), e.keyCodeVal = t, e.keyCode !== t &amp;&amp; alert("keyCode mismatch " + e.keyCode + "(" + e.which + ")"), document.dispatchEvent(e)
+    };
+    var o, s, h = innerHeight,
+        w = innerWidth,
+        fw = 60,
+        fa = [];
+    window.onkeydown = function (t) {
+        var e = t.key;
+        (e.search("Arrow") &gt; -1 || "1" == e) &amp;&amp; (d = t.key), "i" != e &amp;&amp; "I" != e || (console.log("inc"), fw -= 10), "d" != e &amp;&amp; "D" != e || (console.log("dec"), fw += 10)
+    }, init();
+</pre>
+
+<h5 id="Output">Output</h5>
+
+<table class="standard-table">
+ <tbody>
+ <tr>
+ <td>
+ <h2 id="sect1"><a href="https://kunalverma94.github.io/pokemon/snake.html"><img alt="Snake game" src="https://kunalverma94.github.io/view/images/snake.jpg" style="height: 400px; width: 600px;"></a></h2>
+ </td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="Other_examples" name="Other_examples">其它例子</h2>
+
+<dl>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/A_basic_ray-caster" title="/zh-CN/docs/Web/Guide/HTML/A_basic_ray-caster">A basic ray-caster</a></dt>
+ <dd>一个关于如何使用键盘关联控制动画的优秀的案例。</dd>
+ <dt><a href="https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Tutorial/Advanced_animations">Advanced animations</a></dt>
+ <dd>我们将在下一章看到一些先进的动画技术和物理现象。</dd>
+</dl>
+
+<p>{{PreviousNext("Web/API/Canvas_API/Tutorial/Compositing", "Web/API/Canvas_API/Tutorial/Advanced_animations")}}</p>