canvas 從初級到XX 2# 讓我們在之前的基礎之上,再邁進一步吧 [中級向] (上)

来源:https://www.cnblogs.com/z890524/archive/2017/12/29/8143030.html
-Advertisement-
Play Games

還是老樣子,先啰嗦一點前言。 最近各種事務纏身,所以也就隔了比較長的時間才開始碼這篇文。希望不會這麼快就過氣。 好了,接下來就開始碼代碼。(寫到中途,突然感覺到的。本篇設計大量初中物理知識,請懷念的往下看) 這次不像之前,是已經寫好的文件,拿出來解析一波,就糊弄出來了一篇隨筆。總之,我就一邊的編代碼 ...


還是老樣子,先啰嗦一點前言。

最近各種事務纏身,所以也就隔了比較長的時間才開始碼這篇文。希望不會這麼快就過氣。

好了,接下來就開始碼代碼。(寫到中途,突然感覺到的。本篇設計大量初中物理知識,請懷念的往下看)

這次不像之前,是已經寫好的文件,拿出來解析一波,就糊弄出來了一篇隨筆。總之,我就一邊的編代碼,一邊寫文章。時不時的截圖一個效果出來,不知道這樣,能不能糊弄過去。。。。

這次,目標是準備實現很多canvas,素材網站上比較常見的煙花效果。只看過幾次效果,也許實現的最終效果有些差異。但是,希望大家最後能以自己的能力改成自己更期待的結果,而不是只能跟著我做出一樣的東西,沒有任何的衍生。那意義就會缺少很多了。

既然是canvas,這一段還是不能省的。(註:往後的文章,可能會省略這段代碼。主要記住ctx , width , height 這3個變數各自代表是什麼就好了。之後我就直接使用了。所以希望大家多多包涵。)

var drawing = document.getElementById('drawing')
var ctx = drawing.getContext('2d')
var width = drawing.width
var height = drawing.height
View Code
  1.  對煙花的分析:
    大家心裡都對,煙花有一定的印象。煙花有一個升空的過程,然後在空中爆炸散開成很多束。然後漸漸消散。
    總之,就是有2種狀態了。用一個 Boolean 值來判斷就好了。
    除此之外,還有煙花的位置,x, y軸上的速度,以及煙花的各種顏色。當然,還有其他各種屬性,一時之間也想不到那麼完美,不如我們走一步看一步,如何呢?

    function Fireworks (x, y, xSpeed, ySpeed, color) {

        this.x = x
        this.y = y
        this.xSpeed = xSpeed
        this.ySpeed = ySpeed
        this.color = color
        this.boom = false
    }

    其實,寫到這裡挺猶豫的。因為,不知道各位看官的知識面有多廣,是否應該用  class ,最終,考量了一下,使用es6的,肯定知道構造函數,但是,反過來就不一定了。所以,也就簡單做一個優雅降級吧。

  2. 上天吧!
    嘛。。。此情此景上天的當然是煙花咯。
    繼承的寫法多種多樣,希望大家不要過多的考究。萬分感謝。
        Fireworks.prototype.draw = function(){
          ctx.clearRect(0, 0, width, height)
          ctx.beginPath()
          ctx.arc(this.x, this.y, 10 , 0 , 2 *Math.PI)
          ctx.fill()
        }
    
        Fireworks.prototype.toSky = function(){
          this.x += this.xSpeed
          this.y += this.ySpeed
          this.draw()
        }

    為了更加的真實,我們還需要模擬重力加速度。 var g = 9.8 當然,這裡只是假設。並不是我們必須設定的和實際的重力加速度一樣。只是方便理解,而我百分百的確定,我之後一定會改變這個值的。

    Fireworks.prototype.toSky = function(){
          this.x += this.xSpeed
          this.y += this.ySpeed
          this.ySpeed -= g
          this.draw()
        }

    此時。比較細心的朋友,以及正跟著一步步敲代碼的朋友,應該都會發現。這段代碼裡面有一些問題。我當然是故意的啦。不然,我就直接去上面改成沒問題的代碼,然後減掉這一段了!
    問題的bug,就是我們速度的正負值,以及canvas的y軸方向和我們正常習慣的y軸方向。有一些比較厲害的朋友,自己寫方法將canvas的軸,修改成,我們通常使用的。
    但是,本篇還是使用的原生的,y軸正方向向下的情況。於是。。我們的煙花要升天。就要使用一個負值的速度。重力加速度,也需要相應的改動。我就不在這裡做改動,混字數了,大家可以小修正一下y軸相關值正負,然後創建一個 Fireworks 實例加一個定時器來調用  toSky。就可以看到一小效果了,但是,這樣就夠了嗎?其實,我接下來有更多需要豐滿的地方。

  3. 現在該做什麼呢?
    開頭說的那麼故弄玄虛,到現在不是就值做出了一個走拋物線的小球嗎?而且還是寫死的半徑為10的黑球。就連之前說好的 color 都沒有加上去。教練,這和說好的不一樣啊!!
    所以,本來這一段效果優化的代碼,準備放在總體邏輯完成之後再寫下來的。但是現在的體驗極差。就先豐滿這一部分的視覺效果吧。
    首先,做一個簡單操作 var r = Math.random.bind(Math)  很多人看到random。 就感覺有大事要發生。沒錯,就是這樣。讓我們對最初的構造函數,先做出小改動吧。
    function Fireworks () {
          var x = width * (r() * .8 + .1)
          this.x = x
          this.y = height
          this.xSpeed = x > width / 2 ? -(20 * r() - 10)  : (20 * r() - 10) 
          this.ySpeed = 20 * r() + 10
          this.color = 'rgb('+ f(r() * 256) +',' + f(r() * 256) + ','+ f(r() * 256) +' )'
          this.radius = 5
          this.dotNum = 20
          this.dots = []
        }

    大致的改動,大家都是可以自己看出來的。將起始點,定在canvas的最底部,起始點最少距離左右邊緣都會有十分之一的寬度,根據起始點的位置,來決定,x軸的方向。將速度,顏色。都改成了隨機數。將圓的半徑也定義了進來。
    這些數字類型的值,大多都是可以自己按需修改,或者定義常量來使用。就不要過於糾結了。當然,這些數值都還不完善。只能最後我們添加了定時器,實際運行的時候,才能確定比較合理的數值。

    既然說到了定時器,不如就多說幾句吧。一般我們動畫上使用的定時器,每幀的間隔都會使用15ms。至於為什麼就不說了。隨便查一下就能找到,而且說太多了也偏離了本篇的主題了。想多說的就是做動畫效果的時候的另外一個API, requestAnimationFrame 這裡也不會介紹太多關於這個API,因為會偏題呀。只是之後會使用,所以,還不太瞭解的同學,可以先去瞭解一下這個API。
    到此,似乎,我們實際的效果並沒有什麼改變。
    那麼接下來,就讓我來使用新增的2個屬性吧。

    Fireworks.prototype.createDotArr = function(){
          var length = this.dots.length
          if (length < this.dotNum) 
            this.dots.push(
              {
                x: this.x, 
                y: this.y
              })
          } else {
            for (var i = 0; i < length - 1; i++) {
              this.dots[i] = this.dots[i + 1]
            }
            this.dots[length - 1] = {
              x: this.x, 
              y: this.y
            }
          }
        }

    上面這個方法,將我們之前的那個拋物線的圓,經過的點記錄下來。因為只是一段較短的拋物線,所以我們暫時只記錄20個點。也就是 dotNum 這個屬性控制的點數。
    接下來就是將每個點都進行繪製,所以改寫了我們之前的方法。於是就成了這樣。

        Fireworks.prototype.draw = function(){
          var self = this
          ctx.clearRect(0, 0, width, height)
          self.dots.forEach(function(v){
            ctx.beginPath()
            ctx.arc(v.x, v.y, self.radius , 0 , 2 * Math.PI)
            ctx.fill()
          })
        }
    
       Fireworks.prototype.toSky = function(){
          this.x += this.xSpeed
          this.y -= this.ySpeed
          this.ySpeed -= g
          this.createDotArr()
          this.draw()
        }

    接下來,讓我們來進行一下測試。看看現在效果如何了。

    var test = new Fireworks()
        function animate () {
          requestAnimationFrame(function () {
            test.toSky()
            animate()
          })
        }
        animate()
    

    並不是最終的調用形式。 只是做一個測試的效果。所以,之後這段是不包含在邏輯代碼里的。另外,大家可以在做這個測試的時候,去改變構造函數內的常量參數,將它變成你喜歡的樣子。我就不多廢話了。
    其實,現在看起來好像也還不是很美觀,顏色也並沒有加上去。那就讓我來加上顏色吧。當然並不是你們所想的 fillStyle = this.color 。因為這樣看起來也並不好看啊。

    Fireworks.prototype.draw = function(){
          var self = this
          ctx.clearRect(0, 0, width, height)
          self.dots.forEach(function(v, i){
            var gradients = ctx.createRadialGradient(v.x, v.y, 1, v.x, v.y, i / self.dots.length * self.radius + 1)
            gradients.addColorStop(0, "rgba(" + self.R + "," + self.G + "," + self.B + "," + i / self.dotNum + ")")
            gradients.addColorStop(1, "rgba(" + self.R + "," + self.G + "," + self.B + ", 0 )")
            ctx.fillStyle = gradients
            ctx.beginPath()
            ctx.arc(v.x, v.y, self.radius , 0 , 2 * Math.PI)
            ctx.fill()
          })
        }

    忘記補充的一點,R,G,B屬性。是我在構造函數中,將color屬性,拆分成了,這3個屬性。大家可以自己實現,我就不貼代碼了。
    這裡採用的漸變色,內部為最深的顏色,但是在點的索引逐漸變大,也就是這個點存在的時間變長的時候,逐漸變的透明,向外部延伸直至完全透明。要保證漸變向外延伸,所以在 createRadialGradient 的第六個參數的最後 + 1,以此確保這個值是大於1的。

小結: 

至此,就是一個可以上天,但是還不能爆炸的啞炮煙花了。代碼敲到這裡,主要實現煙花的各種邏輯已經全部都有講到了,之後的內容沒有什麼新的知識點,大家可以自己嘗試完成接下來的內容。由於時間不足,就寫到這裡,不久之後,我會回來填坑的。

 大家就不要打我了。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 邊緣與中心檢測: CGRectGetMinX 返回矩形左邊緣的坐標。 CGRectGetMinY 返回矩形底部邊緣的坐標。 CGRectGetMidX 返回矩形中心的x坐標。 CGRectGetMidY 返回矩形中心的y坐標。 CGRectGetMaxX 返回矩形右邊緣的坐標。 CGRectGetM ...
  • 添加屬性 odiv.setAttribute("title","hello div!"); odiv.setAttribute("class","boxClass"); odiv.setAttribute("hello","divTag");//自定義屬性設(hello="divTag") 獲取屬性... ...
  • 類選擇器相容性 getbyclass()類選擇器,在IE8及以下均不可用。 // 類選擇器的相容性 function getbyclass(parentName,Name){ var parentName=document.getElementById(parentName); // 通過標簽名通配... ...
  • 無聊弄了這個東西,還是發表出來吧 導入包 實體類 資料庫連接 資料庫操作 service層數據操作 網頁對service層可視化實現 model package com.ij34.model; public class article { private int id; private String ...
  • 作者網站原文:http://hawkzz.com/blog/blog/1514542087911 簡介 我們開發不可能只寫一個頁面,每次都要寫很多頁面,這時為了開發效率,我們使用前端自動化工具webpack,那麼webpack是如何打包頁面的呢?又是如何打包多頁面的呢? 單頁面打包 我們知道要打包單 ...
  • 前言 經過2個多月的艱苦奮鬥,app的第一個版本已經快完工了,期間遇到了太多的坑,作為一個喜歡分享的人,我當然不會吝嗇分享這爬坑歷程。不要問我有多坑,我會告訴你很多,很多..... 過去一直從事.net web開發工作,直到幾個月前,公司需要開發一個h5+,於是我這樣的全能型選手自然而然就被派去搞w ...
  • 這個需求場景很常見,但好像到目前還沒有一個正統的做法,以至於一搜這個問題,出來的招數五花八門,典型的包括: 給body上overflow:hidden,fixed什麼的。問題在於:手機端可能沒用,或者會讓頁面回到頂部~影響體驗 簡單粗暴的屏蔽touchmove。問題在於:彈出層內部需要滾動就不行 張 ...
  • 1:concat 2:join 3:pop 4:push 5:reverse 6:shift 7:slice 8:unshift 9:splice ...
一周排行
    -Advertisement-
    Play Games
  • 前言 本文介紹一款使用 C# 與 WPF 開發的音頻播放器,其界面簡潔大方,操作體驗流暢。該播放器支持多種音頻格式(如 MP4、WMA、OGG、FLAC 等),並具備標記、實時歌詞顯示等功能。 另外,還支持換膚及多語言(中英文)切換。核心音頻處理採用 FFmpeg 組件,獲得了廣泛認可,目前 Git ...
  • OAuth2.0授權驗證-gitee授權碼模式 本文主要介紹如何筆者自己是如何使用gitee提供的OAuth2.0協議完成授權驗證並登錄到自己的系統,完整模式如圖 1、創建應用 打開gitee個人中心->第三方應用->創建應用 創建應用後在我的應用界面,查看已創建應用的Client ID和Clien ...
  • 解決了這個問題:《winForm下,fastReport.net 從.net framework 升級到.net5遇到的錯誤“Operation is not supported on this platform.”》 本文內容轉載自:https://www.fcnsoft.com/Home/Sho ...
  • 國內文章 WPF 從裸 Win 32 的 WM_Pointer 消息獲取觸摸點繪製筆跡 https://www.cnblogs.com/lindexi/p/18390983 本文將告訴大家如何在 WPF 裡面,接收裸 Win 32 的 WM_Pointer 消息,從消息裡面獲取觸摸點信息,使用觸摸點 ...
  • 前言 給大家推薦一個專為新零售快消行業打造了一套高效的進銷存管理系統。 系統不僅具備強大的庫存管理功能,還集成了高性能的輕量級 POS 解決方案,確保頁面載入速度極快,提供良好的用戶體驗。 項目介紹 Dorisoy.POS 是一款基於 .NET 7 和 Angular 4 開發的新零售快消進銷存管理 ...
  • ABP CLI常用的代碼分享 一、確保環境配置正確 安裝.NET CLI: ABP CLI是基於.NET Core或.NET 5/6/7等更高版本構建的,因此首先需要在你的開發環境中安裝.NET CLI。這可以通過訪問Microsoft官網下載並安裝相應版本的.NET SDK來實現。 安裝ABP ...
  • 問題 問題是這樣的:第三方的webapi,需要先調用登陸介面獲取Cookie,訪問其它介面時攜帶Cookie信息。 但使用HttpClient類調用登陸介面,返回的Headers中沒有找到Cookie信息。 分析 首先,使用Postman測試該登陸介面,正常返回Cookie信息,說明是HttpCli ...
  • 國內文章 關於.NET在中國為什麼工資低的分析 https://www.cnblogs.com/thinkingmore/p/18406244 .NET在中國開發者的薪資偏低,主要因市場需求、技術棧選擇和企業文化等因素所致。歷史上,.NET曾因微軟的閉源策略發展受限,儘管後來推出了跨平臺的.NET ...
  • 在WPF開發應用中,動畫不僅可以引起用戶的註意與興趣,而且還使軟體更加便於使用。前面幾篇文章講解了畫筆(Brush),形狀(Shape),幾何圖形(Geometry),變換(Transform)等相關內容,今天繼續講解動畫相關內容和知識點,僅供學習分享使用,如有不足之處,還請指正。 ...
  • 什麼是委托? 委托可以說是把一個方法代入另一個方法執行,相當於指向函數的指針;事件就相當於保存委托的數組; 1.實例化委托的方式: 方式1:通過new創建實例: public delegate void ShowDelegate(); 或者 public delegate string ShowDe ...