經過初步測試圖片捲動看似可以了,但是要實際拿來用的話還要補上很多東西,先處理這些吧:
1.要能控制轉動的結果,也就是要讓它正確的轉出事先定義的結果圖片。
2.要能從前一次轉動最後停駐的那張圖片開始運轉,不能每回都從第一張開始。
3.每次的轉動時間長度要不同,這樣將來要做水果盤遊戲時才不會九格幾乎同時停止。
4.要加上運動函數讓轉動顯得自然(起動時由慢至快→然後維持在最高速→停止前由快漸慢到停止)。
經過初步測試圖片捲動看似可以了,但是要實際拿來用的話還要補上很多東西,先處理這些吧:
- 要能控制轉動的結果,也就是要讓它正確的轉出事先定義的結果圖片。
- 要能從前一次轉動最後停駐的那張圖片開始運轉,不能每回都從第一張開始。
- 每次的轉動時間長度要不同,這樣將來要做水果盤遊戲時才不會九格幾乎同時停止。
- 要加上運動函數讓轉動顯得自然(起動時由慢至快→然後維持在最高速→停止前由快漸慢到停止)。
做法分享:
1、如何控制最後停止的位置,令轉動停止在事先約定的圖片上面。
- 考慮「當下圖號」「目的圖號」「上捲或下捲」「圖片總數」「畫格總數」等條件設計演算法。
-
定義一個「希望值」:
- 希望值就是在轉動停止時所希望停駐的圖號。
- 希望值的範圍在0至圖片總數和 –1 之間,若為 –1就表示交由亂數決定。
- 計算共要捲動多少張圖片,再換算成多少小格(就是下面程式碼中的「補償列數」),然後再交給轉動程序去執行畫面捲動。
-
這部分看似複雜,但基本原理很簡單:
- 用「(希望的結果圖號 - 當下圖號)* 單張圖片的高度 」算出要捲動幾小格。
- 當「當下圖號」大於「目的圖號」時這個值會是負值,所以再由亂數產生一至數個大週期的格數加上去,以保證傳回的格數不會是負數。
- 程序中圖號的邏輯編排分用兩種座標系統,向上捲動時圖號由上至下編排,向下捲動時圖號由下至上編排。
- User 認知的圖號是固定不變的,一律是從上至下(0到9)的絶對編號。
-
計算應轉動總格數的程式碼如下(L和H表示由亂數決定加上去的大週期數量):
Function 算出應捲動多少格數(ByRef 希望值, L, H) As Integer '------------------------------------------------------------------------------------------ ' 根據捲動方向校正當下圖號: ' 以 User 角度而言圖號為固定編號, 恆為由上而下排列,但在程式中的邏輯編號則受捲動方向支配。 ' 向上捲動時:圖號由上至下編號(0-n) ' 向下捲動時:圖號由下至上編號(n-0) '------------------------------------------------------------------------------------------ If 捲動方向 = 捲動方向列舉常數.向下捲動 Then 當下圖號 = 圖片數 - 當下圖號 '------------------------------------------------------------------------------------------ ' 根據希望值計算共要捲動畫格的圖點總列數 ' 1. 傳入參數 n 為預期的結果圖片號碼 ' n >= 0:使用者指定期望數字 ' n <=-1:程式以亂數產生期望數字,做為最後呈現的圖編號。 ' 2. 以全部圖片的高度總和為一單位,亂數產 3-5 倍的長度做為預設捲動的小格數量。 ' 3. 若使用者指定期望值,則需計算從結果圖片到目標圖片共需再移動幾小格做為補償格數。 '------------------------------------------------------------------------------------------ Randomize() If (希望值 < 0) Or (希望值 > 圖片數 - 1) Then 希望值 = Int(Rnd(1) * 圖片數) Dim 補償列數 As Integer = 0 Dim 應捲動總列數 As Integer = _畫格總數 * 亂數產生器.Next(L, H) Select Case 捲動方向 Case 捲動方向列舉常數.向上捲動 : 補償列數 = (希望值 - 當下圖號) * 畫格高 Case 捲動方向列舉常數.向下捲動 : 補償列數 = (圖片數 - 希望值 - 當下圖號) * 畫格高 End Select 應捲動總列數 += 補償列數 Return 應捲動總列數 End Function
-
執行捲動的程式碼如下(等速的捲動):
'---可指定結果及捲動方向的捲動--- Sub 捲動圖片2(目的圖框 As PictureBox, Optional 希望值 As Integer = -1) Dim 應捲動總列數 = 算出應捲動多少格數(希望值, 1, 1) Dim 速度 As Single = 20 Dim 位移 As Integer = 畫格高 \ 16 Dim 圖塊大小 As New Rectangle(New Point(0, 0), 目的圖框.Size) Dim 當下畫格指標 = 畫格高 * 當下圖號 Dim ee As Graphics = pic_展示框.CreateGraphics Dim 擷圖起點位置 As Integer = 0 For i As Integer = 當下畫格指標 To 當下畫格指標 + 應捲動總列數 Step 位移 Select Case 捲動方向 '---根據捲動方向換算擷圖的起點座標--- Case 捲動方向列舉常數.向上捲動 : 擷圖起點位置 = i Mod _畫格總數 Case 捲動方向列舉常數.向下捲動 : 擷圖起點位置 = _畫格總數 - (i Mod _畫格總數) End Select ee.CompositingQuality = Drawing2D.CompositingQuality.HighSpeed ee.DrawImage(接成的長條圖.Image, 圖塊大小, 0, 擷圖起點位置, 畫格寬, 畫格高, GraphicsUnit.Pixel) ee.ReleaseHdc(ee.GetHdc) Thread.Sleep(速度) Application.DoEvents() Next 目的圖框.Image = pic(希望值) 當下圖號 = 希望值 End Sub
2、要加上運動函數讓轉動顯得自然(起動時由慢至快→然後維持在最高速→停止前由快漸慢到停止)。
- 使用二次曲線函數讓效果自然,直接想到的就是重力加速度的 H= 1/2 * G * T^2
- 其中的 G 值經測試選擇一個定值,而時間 T 就用已轉動的格數位置代入,指數也不固定用二次方,總之是以實測為準。
- 影響轉動速度的因素有兩個,一是每次捲動的格數,一是每次捲動後暫停的的毫秒數。
-
這部分的程式碼如下:
'---加上運動函數的捲動--- Sub 捲動圖片3(目的圖框 As PictureBox, Optional 希望值 As Integer = -1) Dim 已捲動列數 As Integer = 0 Dim 應捲動總列數 = 算出應捲動多少格數(希望值, 3, 6) '---根據「當下圖片、期望圖片、捲動方向」算出應捲動格數--- Dim 位移 = 0 '---記錄每次捲動的位移量--- Dim 擷圖起點位置 As Integer = 0 '---記錄每次捲動後擷取圖像的 Top 位置--- Dim 當下暫停毫秒數 As Single = 0 Dim id As Integer = 0 加速階段終點列數 = 畫格高 * 2 '---定義由慢至快的範圍(最前2張圖片)--- 減速階段起點列數 = 應捲動總列數 - 畫格高 * 9 '---定義由快至慢的範圍(最後9張圖片)--- Try Dim 目的框 As New Rectangle(New Point(0, 0), 目的圖框.Size) Using ee As Graphics = 目的圖框.CreateGraphics Do id = 畫格高 * 當下圖號 + 已捲動列數 Select Case 捲動方向 '---根據捲動方向換算擷圖的起點座標--- Case 捲動方向列舉常數.向上捲動 : 擷圖起點位置 = id Mod _畫格總數 Case 捲動方向列舉常數.向下捲動 : 擷圖起點位置 = _畫格總數 - (id Mod _畫格總數) End Select ee.CompositingQuality = Drawing2D.CompositingQuality.HighSpeed ee.DrawImage(接成的長條圖.Image, 目的框, 0, 擷圖起點位置, 畫格寬, 畫格高, GraphicsUnit.Pixel) ee.ReleaseHdc(ee.GetHdc) 已捲動列數 += 位移 '--------------------------------------------------------------------- ' 速度控制處理(1.起動後加速 2.維持最高速 3.停止前減速)的計算 ' 1. 採用基本運動函數(s = a + b * t^2)建立速度曲線。 ' 2. 再依當下已捲動列數值傳入到運動函數,以取出暫停毫秒數。 '--------------------------------------------------------------------- Select Case 已捲動列數 Case Is >= 減速階段起點列數 '---停止前減速階段--- 位移 = 2 + (畫格高 / 4) * ((應捲動總列數 - 已捲動列數) / (應捲動總列數 - 減速階段起點列數)) ^ 3 當下暫停毫秒數 = 基本暫停毫秒數 / 2 Case Is < 加速階段終點列數 '---啟動後加速階段--- 位移 = 1 + (畫格高 / 4) * (已捲動列數 / 加速階段終點列數) ^ 1.2 當下暫停毫秒數 = 基本暫停毫秒數 Case Else '---極速階段--- 位移 = (畫格高 / 2) 當下暫停毫秒數 = 基本暫停毫秒數 End Select id += 位移 Thread.Sleep(當下暫停毫秒數) Application.DoEvents() Loop While 已捲動列數 < 應捲動總列數 End Using Catch ex As Exception Finally 目的圖框.Image = pic(希望值) '---更新控制項的圖片為最後停駐的圖片--- 當下圖號 = 希望值 '---更新當下圖號--- GC.Collect() '---清理垃圾--- End Try End Sub
下面是擷圖及影片:
下載[圖片捲動2_demo.rar]
下載[圖片捲動(二)專案原始碼.rar]