VisualFreeBasic游戏趣味编程_11.2_分形与递归

2026-1-22 / 0 评论 / 108 阅读

雪花、果实、闪电、叶子、树枝、河道等自然界中很多对象的图形都具有以下两个特征:

(1)整体上看,物体图形是处处不规则的;

(2)在不同尺度上,图形的结构又有一定的相似性。

如图11-5所示。

满足这些特征的图形可以称为分形(Fractal),图11-6展示了用分形方法绘制一棵树的过程:

绘制过程可抽象为如下步骤。

(1)绘制一个树干。

(2)绘制其左边的子树干,绘制其右边的子树干。

(3)当到第n代树干时停止生成子树干。

输入并运行以下代码:

'枝干生成和绘制递归函数
'输入参数:枝干起始x,y坐标,枝干角度,第几代
Sub brunch(gg As yGDI, x_start As Single, y_start As Single, angle As Single, generation As Long)

   ' 利用三角函数求出当前枝干的终点x,y坐标
   Dim As Single x_end, y_end
   If angle > 360 Then angle -= 360
   If angle < 0   Then angle += 360

   x_end = x_start + 50 * Cos(angle * (3.1419265 / 180))
   y_end = y_start + 50 * Sin(angle * (3.1419265 / 180))

   gg.DrawLine(x_start, y_start, x_end, y_end) ' 画出当前枝干(画线)

   ' 求出子枝干的代数
   Dim childGeneration As Long = generation + 1
   ' 当子枝干并且代数小于或等于4,画出当前枝干,并递归调用产生子枝干
   If (childGeneration <= 4) Then
      ' 产生左右的子枝干
      brunch(gg, x_end, y_end, angle + 30, childGeneration)
      brunch(gg, x_end, y_end, angle - 30, childGeneration)
   End If
End Sub
Sub 游戏执行过程(hWndForm As hWnd)
   Dim gg As yGDI = hWndForm
   gg.Cls BGR(255, 255, 255) '白色背景
   gg.Pen 2,BGR(0,0,0) '设定线条颜色为黑色
   brunch(gg,DpiUnScaleF(Me.ScaleWidth/2),DpiUnScaleF(Me.ScaleHeight), 270,1)
   gg.Redraw 

End Sub

定义函数Sub brunch绘制起点坐标(x_start, y_start)、长度50、角度angle、代数generation的树枝。主函数中调用brunch(gg,DpiUnScaleF(Me.ScaleWidth/2),DpiUnScaleF(Me.ScaleHeight), 270,1)绘制主枝干。

brunch()函数内部,首先利用三角函数求出当前枝干的终点坐标(x_end,y_end),利用gg.DrawLine(x_start, y_start, x_end, y_end) 绘制当前枝干线条。

利用三角函数求出当前枝干的终点x,y坐标

   x_end = x_start + 50 * Cos(angle * (3.1419265 / 180))
   y_end = y_start + 50 * Sin(angle * (3.1419265 / 180))

然后对子枝干的代数加1,如果代数小于或等于4,则通过递归调用绘制左、右子枝干,两个子枝干的角度在父枝干基础上偏移 30度(angle * (3.1419265 / 180) 是 角度转换弧度,因为代码中的参数是弧度)

      brunch(gg, x_end, y_end, angle + 30, childGeneration)
      brunch(gg, x_end, y_end, angle - 30, childGeneration)

实现效果如图11-7所示。

进一步改进代码,使得子枝干的长度逐渐变短,枝干画线逐渐变细:

'全局变量定义
Dim Shared offsetAngle As Single = 30   ' 左右枝干和父枝干偏离的角度
Dim Shared shortenRate As Single = 0.65 ' 左右枝干长度与父枝干长度的比例
'枝干生成和绘制递归函数
'输入参数:枝干起始x,y坐标,枝干角度,第几代
Sub brunch(gg As yGDI, x_start As Single, y_start As Single, length As Single, angle As Single, thickness As Single, generation As Long)

   ' 利用三角函数求出当前枝干的终点x,y坐标
   Dim As Single x_end, y_end
   If angle > 360 Then angle -= 360
   If angle < 0   Then angle += 360

   x_end = x_start + length * Cos(angle * (3.1419265 / 180))
   y_end = y_start + length * Sin(angle * (3.1419265 / 180))

   gg.Pen thickness, BGR(0, 0, 0) '设定线条颜色为黑色
   gg.DrawLine(x_start, y_start, x_end, y_end) ' 画出当前枝干(画线)

   ' 求出子枝干的代数
   Dim childGeneration As Long = generation + 1
   '生成子枝干的长度,逐渐变短
   Dim childLength As Single = shortenRate *length
   ' 当子枝干长度大于2,并且代数小于或等于10,递归调用产生子枝干
   If childLength >= 2 And childGeneration <= 9 Then
      '生成子枝干的粗细,逐渐变细
      Dim childThickness As Single = thickness * 0.8
      If (childThickness < 1) Then childThickness = 1 ' 枝干绘图最细的线宽为2
      '产生左右的子枝干
      brunch(gg, x_end, y_end, childLength, angle + offsetAngle, childThickness, childGeneration)
      brunch(gg, x_end, y_end, childLength, angle - offsetAngle, childThickness, childGeneration)
   End If
End Sub
Sub 游戏执行过程(hWndForm As hWnd)
   Dim gg As yGDI = hWndForm
   gg.Cls BGR(255, 255, 255) '白色背景
   brunch(gg, DpiUnScaleF(Me.ScaleWidth / 2), DpiUnScaleF(Me.ScaleHeight), 0.45 *DpiUnScaleF(Me.ScaleHeight) *shortenRate, 270, 15 *shortenRate, 1)
   gg.Redraw

End Sub

程序运行后输出如图11-8所示。

练习题11-1:尝试将鼠标位置的x坐标用于调整子枝干和父枝干之间偏离角度,鼠标位置的y坐标用于调整树枝的高度。当用户移动鼠标时,可以绘制出不同高低形态的分形树,如图11-9所示。

评论一下?

OωO
取消