1. Trang chủ
  2. » Công Nghệ Thông Tin

Trò chơi xếp hình với VB6

9 372 2
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề Trò chơi xếp hình với VB6
Thể loại Bài viết
Định dạng
Số trang 9
Dung lượng 195,46 KB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Để thuận tiện cho việc "tạo hình" cho SC, ta sử dụng cấu trúc để lưu trữ dữ liệu các cạnh: Private Type CauTruc Top As Long Bottom As Long Left As Long Right As Long End Type Function sa

Trang 1

Trò chơi xếp hình với VB6 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: CreateRectRgn, CreateEllipseticRgn, CombineRgn

và SetWindowRgn Khai báo các hàm trên trong SC Khai báo thêm hàm DeleteObject dùng để hủy đối tượng đã tạo để giải phóng bộ 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ữ dữ liệu các 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 chính có tọa độ (22,22)-(77,77), hình ellipse có

bán kính lớn=22 và bán kính nhỏ=13 (H.1) Do hình ảnh chúng

ta muốn cắt có chiều rộng và chiều dài bất kì nên ta phải nhân

tỉ lệ này cho chiều dài, rộng thực của mỗi miếng hình nhỏ

(bằng với chiều dài và chiều rộng của SC, do SC sẽ là mỗi

miếng hình nhỏ)

Các giá trị Top, Left, Right, Bottom trong CauTruc có thể nhận các giá trị -1, 0, 1 Nếu Top nhận giá trị 1 có nghĩa là hình chữ nhật sẽ kết hợp với hình ellipse (H.2), nếu nhận giá trị 0 nghĩa là không có hình ellipse, còn giá trị -1 thì ellipse sẽ cắt hình chữ nhật (H.3) (tương tự cho Left, Right và Bottom) Bạn sẽ thấy cách qui định giá trị này rất hữu ích trong các bước sau

Trang 2

Sở dĩ khai báo Function CreateFormRegion là Private vì nếu bạn chuyển qua Public thì khi chạy chương trình, VB sẽ báo lỗi là kiểu người dùng định nghĩa (CauTruc) không được làm đối số (chỉ khi nào bạn tạo ActiveX Control riêng và biên dịch thành *.ocx mới không gặp lỗi này) Do

đó ta phải tạo 1 Sub có tính Public gọi Function này Sub này sẽ trở thành

một Method của 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 giờ thêm các 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 và mô phỏng việc nhấn

và rê chuột trái (khai báo thêm 2 API là ReleaseCapture và SendMessage ở phần khai báo các hàm API):

Private Sub UserControl_MouseDown(Button As Integer, Shift As Integer, X As Single, Y As Single)

Trang 3

ReleaseCapture

SendMessage UserControl.hwnd, &HA1, 2, 0&

End Sub

Ngoài ra, để có thêm nhiều sự kiện (Event) như MouseMove, MouseUp, Resize, bạn khai báo các sự kiện này ở đầu code:

Public <Tên sự kiện> (Các đối số)

Và khi UserControl xảy ra sự kiện nào thì bạn báo hiệu (RaiseEvent) sự kiện đó

Phần Form

Vấn đề kế tiếp là phải tạo các SC sao cho hợp lí vì các cạnh của SC (hay nói chính xác là các hình ellipse) mang các giá trị ngẫu nhiên (nếu không, các SC sẽ có cùng hình dạng).Trước hết tạo một hàm trả về giá trị ngẫu nhiên cho các 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 = 0

Else

NgauNhien = 1

End If

End Function

Hàm Rnd sẽ trả về một con số trong khoảng giá trị [0-1] và Randomize sẽ sinh một con số mới phục vụ cho việc lấy Rnd Nếu không dùng Randomize thì mỗi lần form Load, Rnd sẽ trả về các con số y hệt cũ

Trở lại vấn đề tạo các cạnh sao cho hợp lí Mời bạn xem hình 4 Ở đây tôi lần lượt đánh dấu các hình theo thứ tự Trái-Đỉnh-Phải-Đáy Theo đó, hai SC xếp trên cùng hàng sẽ có Phải trước+Trái sau=0 Hai SC trên cùng cột sẽ có Đáy trên+Đỉnh dưới=0 Cách thuận tiện nhất là lưu các dữ liệu

Trang 4

này vào mảng 2 chiều cấu trúc (mỗi phần tử mảng là 1 cấu trúc theo kiểu CauTruc), sau đó tạo các SC theo các phần tử này 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 cùng là chia hình ra thành nhiều mảnh nhỏ (thực chất mỗi mảnh nhỏ là một SC) và 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 là hDC của thiết bị nhận khối hình, X là hoành độ trên trái điểm bắt đầu nhận khối hình, Y là tung độ trên trái điểm bắt đầu nhận khối hình, nWidth là chiều rộng khối hình,

nHeight là chiều cao khối hình (tất cả các đối số này là của

SC)

- hSrcDC là hDC của hình gốc, xSrc là hoành độ trên trái của

khối hình truyền đi, ySrc là tung độ trên trái của khối hình

truyền đi (của hình đích, cụ thể là một PictureBox)

- dwRop là cờ xác định hoạt động quét, ở đây là chỉ cần kiểu

quét y nguyên như cũ (SRCCOPY)

Sub sau sẽ sinh ra các mảnh hình bất kì:

Private Sub SinhHinh(ByVal wCount As Integer, ByVal hCount As Integer)

wCount là số mảnh muốn cắt theo chiều ngang, hCount là số mảnh muốn cắt theo chiều dọc picPicture là một PictureBox chứa hình đích Nếu bạn nghĩ muốn chia tấm hình ra thành

wCount*hCount mảnh, mỗi mảnh(hay SC control) có chiều dài = chiều dài tấm hình/wCount và chiều rộng = chiều rộng tấm hình/hCount, thì kết quả bạn đạt được sẽ không như ý muốn Phần

Trang 5

chúng ta nhìn thấy được sau khi SC đã tạo hình chỉ là hình chữ nhật trong cùng (= 5/9 chiều dài của SC) và các hình ellipse (nếu có) Do đó mỗi SC sẽ có chiều dài (hoặc rộng) thực =

(9/5*chiều dài tấm hình)/wCount (hoặc /hCount) Vì ta không biết người sử dụng sẽ cắt ra bao nhiêu mảnh nên đầu tiên phải đưa lên form một SC và đặt index=0 Sau đó sẽ nạp các SC còn lại tương ứng với số mảnh Hàm ChieuDai(sLen) sẽ trả về 0 nếu sLen<=0 (cụ thể ở đây là =-1,0), trường hợp khác trả về 1

Private Function ChieuDai(ByVal sLen) As Integer

If sLen <= 0 Then

ChieuDai = 0

Else

ChieuDai = 1

End If

End Function

Sở dĩ có hàm ChieuDai này là vì khi copy mảnh hình từ picPicture ta không biết đưa khối hình vào SC ở tọa độ X nào cho hợp lí (vì hình ellipse trái khi có khi không do tạo ngẫu nhiên), do đó tọa độ X ở đây sẽ là tọa độ X của hình chữ nhật trong cùng (2/9*uW) trừ chiều dài hình ellipse trái (nếu có, cũng =2/9*uW), tương tự cho tọa độ Y của SC, tọa độ X,Y của picPicture Còn chiều dài và cao phụ thuộc vào ellipse phải, trái, đỉnh, đáy, nên ngoài kích thước của hình chữ nhật trong cùng (5/9*uW) phải cộng thêm chiều dài các ellipse (nếu có)

Bây giờ trò chơi cơ bản đã hoàn tất Việc còn lại là thiết kế giao diện tùy vào thẩm mỹ của mỗi người Điều căn bản của trò chơi này là bạn phải có một khu vực chính dành cho các SC để tạo lại hình, một PictureBox của hình nguồn làm nhiệm vụ hướng dẫn người chơi (hình này nhỏ hơn hình gốc) và một vùng chứa các hình đã cắt

THỦ TỤC SINH RA CÁC MẢNH HÌNH BẤT KÌ:

Trang 6

Private Sub SinhHinh(ByVal wCount

As Integer, ByVal hCount As Integer)

On Error Resume Next

Dim i As Integer

Dim j As Integer

Dim uW As Long

Dim uH As Long

uW = (9 / 5) * (picPicture.Width /

wCount)

uH = (9 / 5) * (picPicture.Height /

hCount)

sc(0).Width = uW

sc(0).Height = uH

Static nCount

nCount = -1

For i = 1 To wCount * hCount - 1

Load sc(i)

sc(i).Visible=False

Next

For i = 0 To hCount - 1

For j = 0 To wCount - 1

a(i, j).Top = -a(i - 1, j).Bottom

a(i, j).Left = -a(i, j - 1).Right

If j = wCount - 1 Then

a(i, j).Right = 0

Else

a(i, j).Right = NgauNhien

End If

If i = hCount - 1 Then

a(i, j).Bottom = 0 Else

a(i, j).Bottom = NgauNhien End If

Next Next For i = 0 To hCount - 1 For j = 0 To wCount - 1 nCount = nCount + 1 BitBlt sc(nCount).hDc, _ (2 / 9) * uW - (2 / 9) * uW * ChieuDai(a(i, j).Left), (2 / 9) * uH - (2 / 9) - (2 / 9) * uH * ChieuDai(a(i, j).Top), _

(5 / 9) * uW + (2 / 9) * uW * ChieuDai(a(i, j).Right) + (2 / 9) * uW

* ChieuDai(a(i, j).Left), _ (5 / 9) * uH + (2 / 9) * uH * ChieuDai(a(i, j).Bottom) + (2 / 9) * uH

* ChieuDai(a(i, j).Top), _ picPicture.hDc, _

(5 / 9) * uW * j - (2 / 9) * uW * ChieuDai(a(i, j).Left), _

(5 / 9) * uH * i - (2 / 9) * uH * ChieuDai(a(i, j).Top), SRCCOPY sc(nCount).DrawShape a(i, j).Left, a(i, j).Top, a(i, j).Right, a(i, j).Bottom sc(nCount).Visible = True Next j

Next i End Sub

Mẹo vặt

1 Cũng như bao trò chơi khác, trò chơi của chúng ta cũng phải có "cheat" Trong ShapeControl, bạn tạo một Label và đặt vào chính giữa của SC với thuộc tính Visible=False Mỗi khi sub SinhHinh trong Form được gọi thì bạn thêm vào sc(i).Label1.caption=nCount để đánh dấu Mỗi khi gọi cheat (do bạn quy định) thì chỉ việc set thuộc tính Visible của Label thành True

2 Đối với những hình ảnh lớn (800x600), nếu không đủ diện tích màn hình thì bạn dùng hàm API CopyImage với thông số chiều rộng và chiều cao mới để tạo hình nhỏ hơn ban đầu cho picPicture và cũng dùng hàm này cho hình hướng dẫn

3 Khi nạp các SC trong Sub SinhHinh thì các SC này nằm chồng lên nhau, do đó bạn phải sắp xếp lại các SC này một cách ngẫu nhiên Để tiết kiệm không gian thì các SC này nên nằm trong một PictureBox (PB), PB này phải đủ rộng để chứa tất cả các SC bạn tạo ra và PB này phải nằm

Trang 7

trong một Container (1 PB khác, 1 Usercontrol khác, ) kết hợp với ScrollBar Để hình dung việc này thì bạn cứ xem thanh TaskPane (Ctrl+F1) của bộ Office và làm theo ScrollBar sẽ xác định tọa độ Top của PB chứa các SC

Về việc sắp xếp các SC ngẫu nhiên để không gây nhàm chán, bạn tạo 2 mảng một chiều Giả sử chúng ta có 20 SC thì bạn sinh mảng a(0 to 19) và giá trị các phần tử = trị số (a(0)=0, a(1)=1, ), sau đó đổi chỗ ngẫu nhiên các phần tử thì ta có mảng ngẫu nhiên

Mảng b(0 to 19) sẽ mang lần lượt các giá trị của mảng a() (các giá trị này chính là thứ tự của các

SC, b(0)=b(a(0))=6) rồi định lại tọa độ Top và Left Muốn đưa các SC từ PB ra ngoài vùng sắp xếp chính thì dùng hàm SetParent <hWnd cũ>,<hWnd mới>

Bạn có thể tải về mã nguồn chương trình mẫu trên website của TGVT-PCW VN Online

FUNTION ĐẢM NHIỆM VIỆC TẠO HÌNH CHO SC:

Trang 8

Private Function

CreateFormRegion(ScaleX As Single,

ScaleY As Single, OffsetX As Integer,

OffsetY As Integer, DrawStyle As

CauTruc) As Long

Dim HolderRegion As Long,

ObjectRegion As Long, nRet As

Long, Counter As Integer

Dim uW As Long

Dim uH As Long

ResultRegion = CreateRectRgn(0, 0,

0, 0)

HolderRegion = CreateRectRgn(0, 0,

0, 0)

uW = UserControl.Width / 15

uH = UserControl.Height / 15

'Hình chữ nhật chính

'22/99,22/99,77/99,77/99

ObjectRegion = CreateRectRgn((2 /

9) * uW * ScaleX * 15 /

Screen.TwipsPerPixelX + OffsetX, (2

/ 9) * uH * ScaleY * 15 /

Screen.TwipsPerPixelY + OffsetY, (7

/ 9) * uW * ScaleX * 15 /

Screen.TwipsPerPixelX + OffsetX, (7

/ 9) * uH * ScaleY * 15 /

Screen.TwipsPerPixelY + OffsetY)

nRet = CombineRgn(ResultRegion,

ObjectRegion, ObjectRegion,

RGN_COPY)

DeleteObject ObjectRegion

'Hình ellipse trái

If DrawStyle.Left <> 0 Then

ObjectRegion =

CreateEllipseticRgn(0 * ScaleX * 15 /

Screen.TwipsPerPixelX + OffsetX,

(37 / 99) * uH * ScaleY * 15 /

Screen.TwipsPerPixelY + OffsetY, (4

/ 9) * uW * ScaleX * 15 /

Screen.TwipsPerPixelX + OffsetX, (7

/ 11) * uH * ScaleY * 15 /

Screen.TwipsPerPixelY + OffsetY)

nRet = CombineRgn(HolderRegion,

ResultRegion, ResultRegion,

OffsetX, 0 * ScaleY * 15 / Screen.TwipsPerPixelY + OffsetY, uW

* (7 / 11) * ScaleX * 15 / Screen.TwipsPerPixelX + OffsetX, uH

* (4 / 9) * ScaleY * 15 / Screen.TwipsPerPixelY + OffsetY) nRet = CombineRgn(HolderRegion, ResultRegion, ResultRegion,

RGN_COPY) nRet = CombineRgn(ResultRegion, HolderRegion, ObjectRegion, 3 - DrawStyle.Top)

DeleteObject ObjectRegion End If

'Hình ellipse cạnh phải

If DrawStyle.Right <> 0 Then ObjectRegion =

CreateEllipseticRgn(uW * (5 / 9) * ScaleX * 15 / Screen.TwipsPerPixelX + OffsetX, uH * (37 / 99) * ScaleY *

15 / Screen.TwipsPerPixelY + OffsetY, uW * ScaleX * 15 / Screen.TwipsPerPixelX + OffsetX, uH

* (7 / 11) * ScaleY * 15 / Screen.TwipsPerPixelY + OffsetY) nRet = CombineRgn(HolderRegion, ResultRegion, ResultRegion,

RGN_COPY) nRet = CombineRgn(ResultRegion, HolderRegion, ObjectRegion, 3 - DrawStyle.Right)

DeleteObject ObjectRegion End If

'Hình ellipse cạnh đáy

If DrawStyle.Bottom <> 0 Then ObjectRegion =

CreateEllipseticRgn(uW * (37 / 99) * ScaleX * 15 / Screen.TwipsPerPixelX + OffsetX, uH * (5 / 9) * ScaleY * 15 / Screen.TwipsPerPixelY + OffsetY, uW

* (7 / 11) * ScaleX * 15 / Screen.TwipsPerPixelX + OffsetX, uH

* ScaleY * 15 / Screen.TwipsPerPixelY + OffsetY)

Trang 9

RGN_COPY)

nRet = CombineRgn(ResultRegion,

HolderRegion, ObjectRegion, 3 -

DrawStyle.Left)

DeleteObject ObjectRegion

End If

'Hình ellipse trên đỉnh

If DrawStyle.Top <> 0 Then

ObjectRegion =

CreateEllipseticRgn((37 / 99) * uW *

ScaleX * 15 / Screen.TwipsPerPixelX

+

nRet = CombineRgn(HolderRegion, ResultRegion, ResultRegion,

RGN_COPY) nRet = CombineRgn(ResultRegion, HolderRegion, ObjectRegion, 3 -DrawStyle.Bottom)

DeleteObject ObjectRegion End If

DeleteObject HolderRegion CreateFormRegion = ResultRegion End Function

 

Ngày đăng: 06/11/2013, 09:15

HÌNH ẢNH LIÊN QUAN

Hình chữ nhật chính có tọa độ (22,22)-(77,77), hình ellipse có - Trò chơi xếp hình với VB6
Hình ch ữ nhật chính có tọa độ (22,22)-(77,77), hình ellipse có (Trang 1)

TỪ KHÓA LIÊN QUAN

w