Chương trình sẽ cắt một hình cho trước ra thành nhiều mảnh có hình dạng ngẫu nhiên, và người chơi sẽ phải ráp từng mảnh lại. Trò chơi thật đơn giản nhưng lập trình để tạo trò chơi này không đơn giản chút nào. Bài viết giới thiệu một chương trình như vậy được thực hiện với VB6. Tạo Activex control Tạo một Standard Project mới. Vào menu Project/Add Usercontrol để thêm một Usercontrol mới (đặt tên tùy thích, ở đây tôi đặt là ShapeControl, AutoRedraw=True). Để tạo ShapeControl (SC) có hình dạng đặc biệt cần dùng 4 hàm API:...
Trị chơi xếp hình với VB6 Chương trình cắt hình cho trước thành nhiều mảnh có hình dạng ngẫu nhiên, người chơi phải ráp mảnh lại Trị chơi thật đơn giản lập trình để tạo trị chơi khơng đơn giản chút Bài viết giới thiệu chương trình thực với VB6 Tạo Activex control Tạo Standard Project Vào menu Project/Add Usercontrol để thêm Usercontrol (đặt tên tùy thích, tơi đặt ShapeControl, AutoRedraw=True) Để tạo ShapeControl (SC) có hình dạng đặc biệt cần dùng hàm API: CreateRectRgn, CreateEllipseticRgn, CombineRgn SetWindowRgn Khai báo hàm SC Khai báo thêm hàm DeleteObject dùng để hủy đối tượng tạo để giải phóng nhớ Để thuận tiện cho việc "tạo hình" cho SC, ta sử dụng cấu trúc để lưu trữ liệu cạnh: Private Type CauTruc Top As Long Bottom As Long Left As Long Right As Long End Type Function sau tạo hình cho SC: Private Function CreateFormRegion(ScaleX As Single, ScaleY As Single, OffsetX As Integer, OffsetY As Integer, DrawStyle As CauTruc) As Long Hình chữ nhật có tọa độ (22,22)-(77,77), hình ellipse có bán kính lớn=22 bán kính nhỏ=13 (H.1) Do hình ảnh muốn cắt có chiều rộng chiều dài nên ta phải nhân tỉ lệ cho chiều dài, rộng thực miếng hình nhỏ (bằng với chiều dài chiều rộng SC, SC miếng hình nhỏ) Các giá trị Top, Left, Right, Bottom CauTruc nhận giá trị -1, 0, Nếu Top nhận giá trị có nghĩa hình chữ nhật kết hợp với hình ellipse (H.2), nhận giá trị nghĩa khơng có hình ellipse, cịn giá trị -1 ellipse cắt hình chữ nhật (H.3) (tương tự cho Left, Right Bottom) Bạn thấy cách qui định giá trị hữu ích bước sau Sở dĩ khai báo Function CreateFormRegion Private bạn chuyển qua Public chạy chương trình, VB báo lỗi kiểu người dùng định nghĩa (CauTruc) không làm đối số (chỉ bạn tạo ActiveX Control riêng biên dịch thành *.ocx không gặp lỗi này) Do ta phải tạo Sub có tính Public gọi Function Sub trở thành Method SC Public Sub DrawShape(vLeft As Long, vTop As Long, vRight As Long, vBottom As Long) Dim DrawStyle As CauTruc Dim nRet As Long DrawStyle.Left = vLeft DrawStyle.Top = vTop DrawStyle.Right = vRight DrawStyle.Bottom = vBottom nRet = SetWindowRgn(UserControl.hwnd, CreateFormRegion(1, 1, 0, 0, DrawStyle), True) End Sub Bây thêm Property phục vụ cho việc đồ họa: Public Property get hWnd() as Long hWnd=Usercontrol.hWnd End Property Public Property get hDC() as Long hDC=Usercontrol.hDC End Property Để di chuyển SC (khơng có TitleBar) dễ dàng, bạn phải "capture" chuột mô việc nhấn rê chuột trái (khai báo thêm API ReleaseCapture SendMessage phần khai báo hàm API): Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single) ReleaseCapture SendMessage UserControl.hwnd, &HA1, 2, 0& End Sub Ngoài ra, để có thêm nhiều kiện (Event) MouseMove, MouseUp, Resize, bạn khai báo kiện đầu code: Public (Các đối số) Và UserControl xảy kiện bạn báo hiệu (RaiseEvent) kiện Phần Form Vấn đề phải tạo SC cho hợp lí cạnh SC (hay nói xác hình ellipse) mang giá trị ngẫu nhiên (nếu khơng, SC có hình dạng).Trước hết tạo hàm trả giá trị ngẫu nhiên cho cạnh: Private Function NgauNhien() As Long Randomize If Rnd < 0.3333 Then NgauNhien = -1 ElseIf Rnd > 0.3333 And Rnd < 0.6666 Then NgauNhien = Else NgauNhien = End If End Function Hàm Rnd trả số khoảng giá trị [0-1] Randomize sinh số phục vụ cho việc lấy Rnd Nếu khơng dùng Randomize lần form Load, Rnd trả số y hệt cũ Trở lại vấn đề tạo cạnh cho hợp lí Mời bạn xem hình Ở tơi đánh dấu hình theo thứ tự Trái-Đỉnh-Phải-Đáy Theo đó, hai SC xếp hàng có Phải trước+Trái sau=0 Hai SC cột có Đáy trên+Đỉnh dưới=0 Cách thuận tiện lưu liệu vào mảng chiều cấu trúc (mỗi phần tử mảng cấu trúc theo kiểu CauTruc), sau tạo SC theo phần tử Chúng ta khai báo lại kiểu CauTruc Private Type CauTruc Top as Long Bottom as Long Left as Long Right as Long End Type Dim a(100,100) As CauTruc 'mảng có tối đa 101*101 phần tử Sau chia hình thành nhiều mảnh nhỏ (thực chất mảnh nhỏ SC) dùng hàm BitBlt để copy vùng ảnh bên ảnh đích (ảnh cần cắt) qua SC Private Declare Function BitBlt Lib "gdi32" (ByVal hDestDC As Long, ByVal X As Long, ByVal Y As Long, ByVal nWidth As Long, ByVal nHeight As Long, ByVal hSrcDC As Long, ByVal xSrc As Long, ByVal ySrc As Long, ByVal dwRop As Long) As Long Private Const SRCCOPY = &HCC0020 - hDestDC hDC thiết bị nhận khối hình, X hồnh độ trái điểm bắt đầu nhận khối hình, Y tung độ trái điểm bắt đầu nhận khối hình, nWidth chiều rộng khối hình, nHeight chiều cao khối hình (tất đối số SC) - hSrcDC hDC hình gốc, xSrc hồnh độ trái khối hình truyền đi, ySrc tung độ trái khối hình truyền (của hình đích, cụ thể PictureBox) - dwRop cờ xác định hoạt động quét, cần kiểu quét y nguyên cũ (SRCCOPY) Sub sau sinh mảnh hình bất kì: Private Sub SinhHinh(ByVal wCount As Integer, ByVal hCount As Integer) wCount số mảnh muốn cắt theo chiều ngang, hCount số mảnh muốn cắt theo chiều dọc picPicture PictureBox chứa hình đích Nếu bạn nghĩ muốn chia hình thành wCount*hCount mảnh, mảnh(hay SC control) có chiều dài = chiều dài hình/wCount chiều rộng = chiều rộng hình/hCount, kết bạn đạt không ý muốn Phần nhìn thấy sau SC tạo hình hình chữ nhật (= 5/9 chiều dài SC) hình ellipse (nếu có) Do SC có chiều dài (hoặc rộng) thực = (9/5*chiều dài hình)/wCount (hoặc /hCount) Vì ta khơng biết người sử dụng cắt mảnh nên phải đưa lên form SC đặt index=0 Sau nạp SC cịn lại tương ứng với số mảnh Hàm ChieuDai(sLen) trả sLen