Từ kinh nghiệm từ trò chơi lật hình và trò chơi xếp hình, bạn có thể hình dung cách giải quyết như sau: tạo trước một nhân vật có dạng một ô chứa dòng chữ động, tạo ra một loạt thể hiện [r]
(1)Mục lục
Bài 1: Làm quen với cửa sổ Flash
Bài 2: Nhân vật thể
Bài 3: Khung chốt hoạt cảnh
Bài 4: Hành vi nhân vật
Bài 5: Hành vi thể 10
Bài 6: Câu lệnh điều kiện 12
Bài 7: Hàm xử lý tình 15
Bài 8: Thuộc tính thể 18
Bài 9: Nhân vật phức hợp 21
Bài 10: Hàm có sẵn 23
Bài 11: Hàm tự tạo 25
Bài 12: Trò chơi "rượt bắt" 27
Bài 13: Hàm kiểm tra va chạm 29
Bài 14: Hàm tính trị ngẫu nhiên 32
Bài 15: Liên lạc thể 35
Bài 16: Vẽ biển 37
Bài 17: Vẽ cá 39
Bài 18: Diễn hoạt phận 41
Bài 19: Hình nhạc 44
Bài 20: Câu lệnh tạo thể 46
Bài 21: Sao chép thể 48
Bài 22: Nhân vật trống rỗng 50
Bài 23: Gán hành vi vào thể 52
Bài 24: Tạo nút bấm 54
Bài 25: Nút bấm khởi động 56
Bài 26: Thao tác dãy 59
Bài 27: Hành vi dãy 61
Bài 28: Vui đùa với dãy 63
Bài 29: Dãy nhiều chiều 65
Bài 30: Chỉ mục dãy 67
Bài 31: Trị chơi "lật hình" 72
Bài 32: Xáo hình ngẫu nhiên 75
Bài 33: Úp hình lật hình 80
Bài 34: Những lỗi "nhỏ nhặt" 84
Bài 35: Tìm hình giống 88
Bài 36: Đồng hồ bấm giây 91
Bài 37: Trò chơi ráp hình 98
Bài 38: Sắp xếp mẩu hình 102
Bài 39: Hàm dịch chuyển hình 106
Bài 40: Dịch chuyển hình tự động 109
Bài 41: Điều khiển dòng chữ 115
Bài 42: Hiển thị câu chào mừng 119
Bài 43: Trị chơi tìm số nhỏ 124
Bài 44: Trình bày số dãy 130
Bài 45: Giải thuật tìm số nhỏ 133
(2)Nếu thích thú với trị chơi máy tính, có lúc bạn mơ ước "hành nghề" lập trình trị chơi, chưa Bạn bắt đầu với Flash, cơng cụ tạo trò chơi trang Web Flash giúp dựng nên hoạt cảnh, vật thể, nhân vật hoạt động theo quy tắc có thơng minh định mà người ta gọi “trí tuệ nhân tạo” (artificial intelligence) Khơng trị chơi, Flash cho phép tạo chương trình chạy trang Web Flash công cụ người chuyên nghiệp "dễ chịu" người "lơ mơ" Chỉ cần chăm bước nhỏ, bạn xa
Trước hết, bạn cần cài đặt phần mềm Flash Để làm quen với Flash, bạn dùng từ phiên Flash trở sau Flash gọi Flash MX 2004, chạy tốt máy tính năm 2004 Máy tính cũ giúp bạn thu nhiều kỹ Những nội dung nâng cao địi hỏi phải có phiên Flash công cụ bổ sung (chẳng hạn Flex Builder) trình bày sau bạn nắm vững phần
Sau khâu cài đặt phần mềm, bạn khởi động Flash Khi thấy cửa sổ nhỏ, bạn chọn mục Flash Document phần Create New, bắt đầu làm quen với thứ bên cửa sổ Flash. Cửa sổ Flash gồm nhiều bảng chọn (panel), giúp bạn thực việc khác Chẳng hạn, hình bảng chọn Color Mixer, cho phép chọn màu cho hình vẽ Bạn bấm vào chỗ khung màu để chọn ghi trị số vào ô R (Red), G (Green) B (Blue) Đó ba trị số xác định màu Ô Alpha giúp quy định độ suốt màu
Bạn di chuyển bảng chọn đâu được, để thuận tiện cho công việc Muốn vậy, bạn cần trỏ vào góc trên, bên trái bảng chọn , giữ phím trái chuột, kéo Muốn bảng chọn “đậu” vào chỗ cũ, bạn làm giống vậy: “nắm kéo” góc trên, bên trái bảng chọn, đưa vị trí cố định bên phải cửa sổ Flash
Vì có nhiều bảng chọn nên chưa dùng đến bảng chọn đó, bạn nên cho “co lại”
cách bấm phát vào tiêu đề Khi cần dùng
bảng chọn, muốn cho “bung ra”, bạn lại bấm phát vào tiêu đề
(3)Bạn thấy cửa sổ Flash có khung trống trơn, màu trắng (hình 3) Đó sân khấu (stage), nơi mà bạn xây dựng hoạt cảnh, thể ý tưởng sáng tạo Ta tạo nên các hình vẽ sân khấu, co dãn di chuyển chúng tùy ý Người ta gọi chúng đối tượng (object).
(4)Bạn bấm vào công cụ chọn hộp công cụ (hoặc gõ phím chữ V), trỏ vào phía trên, bên trái hình trịn vừa vẽ, kéo chuột qua phải, xuống dưới, nhằm "căng" khung chọn bao quanh hình trịn Xong, bạn trỏ vào hình trịn, thử kéo đến vị trí khác sân khấu
Vùng màu xám bao quanh sân khấu xem “hậu trường” sân khấu Nếu bạn đặt hình trịn vào vùng xám, khơng xuất "trình diễn" Khi cần cho đối tượng xuất hiện, bạn kéo từ hậu trường vào sân khấu
Để lưu hoạt cảnh tạo (dù lúc banh chưa "nhúc nhích" hết), bạn bấm vào File trình đơn chọn Save trình đơn xổ xuống (nói vắn tắt chọn File > Save) Bạn thấy xuất hộp thoại (dialog box), giúp bạn chọn thư mục đặt tên cho tập tin chứa hoạt cảnh, thường gọi tập tin nguồn Flash (Flash Document) Tập tin nguồn Flash có tên phân loại fla.
Bài 2: Nhân vật thể hiện
Mỗi khởi động Flash, bạn thấy cửa sổ nhỏ liệt kê số tập tin fla mà bạn mở xem tạo lần trước Bạn chọn tập tin có hình banh bạn vẽ
Bạn trỏ vào banh, giữ phím trái chuột, thử kéo banh qua vị trí khác Có lẽ bạn ngạc nhiên vị trí cũ cịn đường trịn, khơng có màu tơ Đó nét viền hình trịn tạo cơng cụ Oval Tool Bạn quy định màu riêng cho nét viền hình trịn Ta cần banh khơng có nét viền, bạn xóa nét viền cách bấm vào nét viền để chọn gõ phím Delete
Để "tơ màu" cho banh, bạn bấm vào banh để chọn, bấm vào ô Fill Color bảng Color Mixer (tỏ ý bạn muốn quy định màu tô màu nét) chọn màu bạn thích
Quả banh có bạn hình vẽ đơn Muốn cho banh trở thành đối tượng có hành vi riêng, điều khiển cách lập trình, trước hết bạn cần chuyển đổi banh thành nhân vật (movie clip) Với banh tình trạng "được chọn", bạn cần gõ phím F8 Khi thấy hộp thoại Convert to Symbol (hình 1), bạn gõ Ball (quả banh) để đặt tên cho nhân vật tạo Bạn nên chọn điểm mốc nhân vật cạnh khung bao hình banh cách bấm vào ô giữa, chín vng nhỏ mục Registration Sau này, nói tọa độ nhân vật, bạn hiểu tọa độ điểm mốc.
(5)Thư viện nơi lưu trữ nhiều thứ khác, chẳng hạn âm cần dùng cho chương trình Flash bạn
Sau thao tác chuyển đổi hình vẽ banh thành nhân vật, banh sân khấu dường khơng có thay đổi Thực có thay đổi lớn: banh sân khấu thể (instance) nhân vật Ball thư viện Muốn có nhiều banh, bạn tạo nhiều thể khác nhân vật Ball Hoạt cảnh bạn có nhiều banh dung lượng tập tin fla tăng không đáng kể so với trường hợp có banh Ngồi ra, bạn chỉnh sửa chi cho nhân vật Ball thư viện, thể nhân vật thay đổi Cấu trúc nhân vật-thể đem đến lợi ích tuyệt vời!
Trước mắt, điều nên làm đặt tên riêng cho thể nhân vật Ball Với banh sân khấu tình trạng "được chọn", bạn bấm vào tiêu đề Properties cạnh cửa sổ Flash (hoặc ấn Ctrl+F3) để mở bảng Properties (hình 2), nơi trình bày thuộc tính thể chọn Trong bảng Properties, bạn bấm vào có dịng chữ <Instance Name> (tên thể hiện) gõ tên ball1 (ngụ ý: thể nhân vật Ball).
Nếu sân khấu có thể nhân vật, bạn gọi thể "nhân vật" Nhiều người dùng thuật ngữ "nhân vật" thay cho "thể hiện" Không hết, miễn bạn hiểu khái niệm
Bấm vào tiêu đề Properties để dẹp bảng Properties, bấm vào sân khấu để chọn thể ball1, bạn bắt đầu việc lập trình cách bấm vào tiêu đề Actions (hoặc gõ phím F9) để mở bảng Actions (hình 3), nơi dùng để ghi câu lệnh ActionScript ActionScript tên ngơn ngữ lập trình dùng để tạo kịch cho nhân vật Flash Bấm vào khung soạn thảo trống trơn bảng Actions, bạn gõ câu lệnh:
(6)Câu lệnh vừa nêu làm cho thuộc tính _xscale nhân vật ball1 có trị số 200 (gán trị số 200 cho biến _xscale nhân vật ball1) Điều nghĩa nhân vật ball1 kéo dãn 200% theo phương x (phương ngang)
Để "chạy chương trình" (chương trình có câu lệnh), bạn ấn Ctrl+Enter Cửa sổ Flash thay đổi, nhiều thứ giấu Giữa cửa sổ khung trắng có hình banh bầu dục, cho thấy rõ ràng câu lệnh bạn viết thực "nghiêm túc": banh kéo dãn theo phương ngang Kích thước theo phương ngang banh bầu dục gấp đơi đường kính banh tròn ban đầu
Để dẹp khung trắng hiển thị kết chương trình, bạn bấm nút góc trên, bên phải khung trắng
Bài 3: Khung chốt của hoạt cảnh
Bạn viết câu lệnh Flash ball1._xscale = 200; chạy thử chương trình có câu lệnh Trong câu lệnh đó, tên nhân vật ball1 tên biến _xscale có dấu chấm để phân cách
Biến _xscale biến có sẵn nhân vật Flash Vế trái câu lệnh đọc "biến _xscale nhân vật ball1" Toàn câu lệnh đọc "gán trị số 200 cho biến _xscale nhân vật ball1" Khi khơng sợ nhầm lẫn, ta gọi "thể ball1 nhân vật Ball" "nhân vật ball1" Bạn ý, cần có dấu chấm phẩy (;) để kết thúc câu lệnh Xem lại thư mục chứa tập tin fla, bạn thấy có thêm tập tin thuộc loại swf Nếu tập tin chứa banh bạn có tên Ball.fla, tập tin tạo có tên Ball.swf (chỉ khác phần phân loại) Trước đây, bạn ấn Ctrl+Enter, Flash ghi xuống tập tin chương trình swf chạy chương trình Chính tập tin swf chương trình chạy được, dùng trang Web Việc chuyển đổi tập tin fla thành tập tin swf chạy gọi biên dịch (compile) Đối với bạn, swf chương trình Đối với người xem trang Web, swf hoạt cảnh (animation) trị chơi (game) Phía sân khấu, bảng Timeline, bạn thấy có dài với số 1, 5, 10, Đó số thứ tự khung hình (frame), gọi tắt khung Diễn biến chương trình Flash theo dịng thời gian giống đoạn phim, nên có khái niệm "khung hình" Mỗi ô ghi số thứ tự biểu diễn khung hình Dải gọi thời tuyến (timeline) Trong bảng Timeline, bạn thấy số có màu đỏ hồng (hình 1) Người ta gọi đầu đọc (playhead) Đầu đọc khung cho biết bạn xem khung (những có sân khấu nội dung khung 1) Trong ô tương ứng với khung có chữ a be bé, ngụ ý nói có câu lệnh ActionScript ghi khung
(7)bằng cách bấm vào khung soạn thảo bảng Actions (nếu khơng thấy nó, bạn gõ phím F9) gõ câu lệnh: ball1._xscale = 100; Câu lệnh gán trị 100 cho biến _xscale nhân vật ball1, quy định độ co dãn theo phương ngang ball1 100%, tức khơng co dãn Vào lúc chạy chương trình, hiển thị đến khung 5, Flash thi hành câu lệnh mà bạn vừa viết Quan sát thời tuyến, bạn thấy đầu đọc nhảy đến khung (hình 2), nghĩa bạn thấy sân khấu thuộc khung Tại khung có dấu trịn màu đen cho biết khung chốt Khung có chữ a giống khung để nói có câu lệnh ActionScript viết cho khung Nhận dấu tròn đen khung 1, có lẽ bạn thắc mắc ngay: "Vậy khung khung chốt?" Vâng, vậy, khung luôn khung chốt theo mặc định Khung thường trước khung chốt đánh dấu dấu chữ nhật màu trắng Dấu cho thấy rõ kết thúc loạt khung giống
Ấn Ctrl+Enter để biên dịch chạy chương trình, bạn thấy banh "phập phồng" liên tục câu lệnh ActionScript khung khung thi hành lặp lặp lại Đóng cửa sổ Ball.swf (cửa sổ trình diễn hoạt cảnh) vừa mở, gõ phím F12 (hoặc chọn File > Publish Preview > Default -HTML), bạn thấy cửa sổ trình duyệt xuất hiện, trình bày tập tin Ball.html Quả banh bạn "diễn trò" thoải mái cửa sổ trình duyệt Đó nhờ tập tin Ball.html có chứa liên kết trỏ đến tập tin Ball.swf Điều giúp bạn hình dung hoạt cảnh trơng đặt trang Web Xem xong, bạn đóng cửa sổ trình duyệt, trở cửa sổ Flash, ấn Ctrl+S để lưu lại thành tập tin Ball.fla
Bài 4: Hành vi của nhân vật
(8)(9)trong khung
Việc giải vấn đề nho nhỏ vừa đặt giúp bạn hiểu cấu trúc lớp Flash Hoạt cảnh gồm nhiều lớp chồng lên Mỗi lớp có khung chốt riêng biệt Quả banh lớp Layer thời chưa "nhúc nhích" hết Bạn áp dụng kinh nghiệm từ banh thứ nhất cho banh thứ hai: đặt tên cho banh thứ hai ball2, tạo khung chốt vị trí tùy ý thời tuyến Layer ghi câu lệnh ActionScript ball2._xscale = khung chốt Tuy nhiên, chuyện cũ, có lẽ khơng cần lặp lại Bạn đặt câu hỏi: "Nếu có hàng chục banh sân khấu hoạt động gống nhau, lẽ phải lập trình cho banh?" Trong trường hợp vậy, bạn nên lập trình cho nhân vật thư viện thay lập trình cho thể nhân vật sân khấu Nhờ vậy, banh đưa từ thư viện vào sân khấu tự biết "phập phồng", khơng cần "chỉ dẫn"
(10)Bạn chọn mục Scene (trên bảng Timeline) để trở với sân khấu Đưa vào sân khấu thêm hai banh từ thư viện ấn Ctrl+Enter, bạn thấy ba banh phập phồng
Bài 5: Hành vi thể hiện
Bạn tạo hoạt cảnh gồm ba banh "phập phồng" Đó ba thể nhân vật Ball thư viện, nhân vật có hành vi "phập phồng" Tuy nhiên, có lúc bạn muốn thể có hành vi khác biệt với "đồng loại" Flash cho phép bạn lập trình cho riêng thể chọn
Trong ba banh sân khấu, bạn bấm chọn banh gõ phím F9 để mở bảng Actions (hình 1) Bấm vào khung soạn thảo cửa sổ Actions, bạn gõ nội dung sau: onClipEvent(mouseDown) {
_y = _y + 20; }
Những bạn ghi bảng Actions theo cách có hiệu lực thể chọn Ở khơng cịn câu lệnh ActionScript trước, mà đoạn mã ActionScript "bí ẩn" gọi hàm (function) Phần onClipEvent tên hàm Phần ghi cặp dấu ngoặc đối mục (parameter, argument) hàm Đối mục hàm (ở cụ thể mouseDown) cung cấp thông tin cho hoạt động hàm Hoạt động hàm diễn đạt thân hàm, phần nằm cặp dấu gộp { } Phần thân hàm thường ghi thụt vào để dễ phân biệt với tên hàm (điều không bắt buộc)
Hàm onClipEvent dùng để diễn đạt việc cần làm xảy tình (event) thể xét Người ta gọi hàm xử lý tình (event handler) Khi lập trình cho thể (quy định hành vi nó), bạn phép viết hàm xử lý tình huống, khơng thể viết câu lệnh tùy ý bên ngồi phạm vi hàm xử lý tình
(11)(12)Bài 6: Câu lệnh điều kiện
Bạn thấy thông báo lỗi xuất bảng Output Khi bạn dừng chương trình (đóng cửa sổ swf), thơng báo lỗi cịn lưu lại bảng Output phía phải cửa sổ Flash để bạn "nghiền ngẫm" Lỗi gọi lỗi lúc biên dịch (compile-time error) Chương trình khơng chạy có lỗi lúc biên dịch Nếu chương trình chạy lại tỏ "kỳ cục", không dự kiến, người ta nói chương trình có lỗi lúc chạy (run-time error)
Trong chương trình mình, bạn chủ động đưa thơng báo bảng Output Nhờ vậy, chạy chương trình, bạn dễ dàng theo dõi diễn biến thực tế, dễ dàng phát nguyên nhân gây lỗi lúc chạy Để thử đưa thông báo bảng Output, bạn bấm chọn banh có lỗi biên dịch, gõ phím F9 để mở lại bảng Actions (nếu cần) Trong bảng Actions, bạn xóa câu lệnh sai, gõ đoạn mã sau:
onClipEvent(mouseDown) { _y -= 20;
trace("Tôi lên đây."); }
(13)Để banh không mất, bạn dừng chương trình, sửa nội dung hàm onClipEvent sau: onClipEvent(mouseDown) {
if(_y > 0) {
_y -= 20;
trace("Tôi lên đây.");
}
}
Những bạn vừa viết bên hàm onClipEvent câu lệnh điều kiện Câu lệnh ngụ ý: tung độ _y banh lớn xê dịch banh đưa thông báo "Tôi lên đây" bảng Output Điều kiện "tung độ _y lớn 0" phải viết cặp dấu ngoặc ( ), đặt sau từ if Những việc cần làm điều kiện thỏa phải viết bên cặp dấu gộp { }, đặt sau cặp dấu ngoặc ( ) Để Flash hiểu bạn viết, cần tuân thủ nghiêm ngặt quy tắc vừa nêu Chạy lại chương trình bấm chuột nhiều lần, bạn thấy banh rốt dừng lại, "không thèm" nhúc nhích Đó điều kiện "tung độ _y lớn 0" không thỏa, tức _y nhỏ Bạn ý, tung độ banh tung độ điểm mốc Chính bạn quy định điểm mốc nằm cạnh khung bao banh Nếu muốn banh "nói năng" điều kiện "tung độ _y lớn 0" không thỏa, không im lìm, bạn viết thêm vào hàm onClipEvent:
onClipEvent(mouseDown) { if(_y > 0) {
_y -= 20;
trace("Tôi lên đây."); }
else {
trace("Tôi không nữa."); }
}
(14)sau từ else Nhờ viết vậy, lúc chạy chương trình, banh thơng báo "Tơi khơng nữa" tung độ khơng lớn Lời từ chối cho bạn thấy banh trơ trơ hiểu bạn bấm chuột thúc giục Với hai banh cịn lại "chưa có cá tính", ta thử lập trình cho chúng có hành vi khác biệt Trước làm vậy, bạn nên cho hai banh cịn lại có màu khác cho dễ phân biệt: xanh, cam chẳng hạn Bạn chọn màu tô khác cho thể khác nhân vật chọn màu nhuộm (tint color) khác cho chúng Cụ thể, bạn chọn banh "chưa có cá tính", ấn Ctrl+F3 để mở cửa sổ Properties tương ứng, chọn Tint ô Color, bấm vào ô màu kế bên chọn màu bảng màu Muốn màu nhuộm lấn át màu tô, bạn ghi 100% ô Tint Amount: Bằng cách đó, bạn có ba thể nhân vật Ball có màu khác (hình 2) Bạn chọn banh màu xanh, gõ đoạn mã sau bảng Actions:
onClipEvent(mouseDown) { if(_yscale == 100) {
_yscale = 200; }
else {
_yscale = 100; }
}
(15)Bài 7: Hàm xử lý tình huống
Trong hàm xử lý tình bấm chuột onClipEvent(mouseDown) banh màu xanh, bạn viết câu lệnh điều kiện if(_yscale == 100) Câu lệnh đặt điều kiện "nếu biến _yscale banh màu xanh có trị 100" Biến _yscale xác định tỉ lệ co dãn theo phương thẳng đứng Bạn ý, dấu "bằng" (==) khác với dấu "gán" (=) mà bạn dùng
Biểu thức điều kiện _yscale == 100 sai vào lúc chạy Người ta cịn nói "kiểu cách" chút: biểu thức _yscale == 100 có trị true false Nhờ có hàm onClipEvent(mouseDown) banh màu xanh, bạn bấm chuột vào lúc chạy, banh chuyển đổi qua lại hai trạng thái: kéo dãn theo phương thẳng đứng không Quả banh màu đỏ màu xanh thể "cá tính" chúng, ta nên cho banh màu cam diễn trị Bạn bấm vào banh màu cam, gõ phím F9 để mở bảng Actions (hình 1) gõ đoạn mã sau:
onClipEvent(mouseDown) { if(_visible) {
_visible = false; }
else {
_visible = true; }
}
(16)Để diễn đạt điều kiện "nếu biến _visible có trị true", bạn viết if(_visible == true) Tuy nhiên, cách viết nêu gọn có ý nghĩa tương đương Bạn cịn viết gọn nữa:
onClipEvent(mouseDown) { _visible = !_visible;
}
Trong đó, ta dùng tác tử "không", biểu diễn dấu chấm than (!) Khi đặt dấu chấm than trước biến _visible, bạn nhận trị true biến _visible có trị false ngược lại Kết tác động tác tử "không" gán trở lại biến _visible Nói khác đi, câu lệnh _visible = !_visible; có tác dụng chuyển đổi trị biến _visible true false Bấm chuột nhiều lần vào lúc chạy chương trình, có lẽ bạn hơi mỏi tay nghĩ: "Phải chi banh tự động diễn trị mà khơng cần chờ bấm chuột" Để đạt "ước mơ" giản dị đó, bạn cần sửa đối mục mouseDown thành enterFrame:
onClipEvent(enterFrame) { _visible = !_visible;
}
(17)vào ô Frame rate hộp thoại vừa (hình 2), gõ gõ Enter (giảm tốc độ từ 12 khung giây xuống khung giây)
Trong banh xanh cam nổ, banh đỏ khiến bạn phiền lịng dừng lại đụng "trần" đứng yên Chắc bạn nghĩ: "Giá banh đỏ liên tục chạy lên chạy xuống vui hơn" Để thực điều này, bạn chọn banh đỏ, sửa đổi bảng Actions như sau:
onClipEvent(load) { step = 20;
}
onClipEvent(enterFrame) {
if(_y < || _y > 500) { step = -step;
trace("Tôi đổi chiều đây."); }
_y += step;
}
Như bạn thấy, câu lệnh thay đổi tung độ _y banh đỏ, thay ghi số cụ thể để xê dịch banh bước cố định trước _y += 20; ta dùng biến, gọi step (bạn tùy ý đặt tên cho biến): _y += step; Khi banh đụng "trần" "sàn", cần đổi dấu cho trị biến step, banh đổi chiều chuyển động Cụ thể, câu lệnh if(_y < || _y > 500) diễn đạt trường hợp đụng "trần" "sàn": _y có trị nhỏ _y có trị lớn 500 (dấu || nghĩa "hoặc") Câu lệnh step = -step; dùng để đổi dấu cho trị số biến step
(18)Bài 8: Thuộc tính thể hiện
Khi chơi đùa với banh (các thể nhân vật Ball), bạn biết đến biến có sẵn bên banh, cho biết trạng thái banh: _x, _y, _xscale, _yscale, _visible Các biến gọi thuộc tính (property) thể Khơng giống biến bạn tự tạo (như biến step cho banh màu đỏ), bạn thay đổi thuộc tính thể nào, trạng thái thể tự động thay đổi Chẳng hạn, gán trị false cho biến _visible banh, banh biến
Để tìm hiểu thêm thuộc tính khác thể hiện, bạn nên tạo nhân vật Lần ta vẽ hình vng để "thay đổi khơng khí" Trước hết, bạn bấm kép vào tên lớp Layer bảng Timeline, gõ Balls, gõ Enter Làm để đổi tên lớp thành Balls, ngụ ý lớp xét lớp dành cho banh Bạn tạo lớp dành cho hình vng Bạn bấm nút "tạo lớp mới" (góc dưới, bên trái bảng Timeline), bấm kép vào tên lớp Layer gõ Squares Để tập trung ý vào hình vng tạo ra, bạn cho banh biến cách bấm vào dấu chấm hàng biểu thị lớp Balls bảng Timeline, cột có hình mắt Các banh giấu để đỡ vướng víu cho bạn làm việc, chúng "góp mặt" bình thường bạn chạy chương trình Bạn vẽ hình vng cách chọn cơng cụ Rectangle hộp cơng cụ, trỏ vào sân khấu, giữ phím Shift giữ phím trái chuột, kéo chuột qua phải, xuống Nhờ bạn giữ phím Shift, hình khung vẽ hình vng Bạn nên tơ màu cho hình vng khác với banh, màu xanh chẳng hạn (hình 1)
(19)Hình vng xanh tình trạng "được chọn" Bạn gõ phím F9 để mở bảng Actions, viết hai hàm xử lý tình cho hình vuông chọn sau:
onClipEvent(load) { step = 10;
}
onClipEvent(enterFrame) { _rotation += step;
}
Trong đó, hàm xử lý tình khởi động tạo biến step chứa trị số 10, hàm xử lý tình chuyển khung cộng biến step vào thuộc tính _rotation hình vng Nhờ vậy, lần chuyển khung, góc quay hình vng lại tăng thêm 10 Bạn ý, biến step ta dùng biến step dùng cho banh màu đỏ Hai biến step tên có phạm vi (scope) khác nhau, khơng có "dây mơ rễ má" hết Ấn Ctrl+Enter để chạy chương trình, bạn thấy hình vng quay góc quay "tà tà" tăng lên lần chuyển khung "Nếu để hình vng quay hồi hồi, lẽ góc quay tăng đến vô cùng?" Bạn yên tâm, thực góc quay hình vng nhận trị số từ -180 đến 180 (tính độ) Flash tự động điều chỉnh trị gán cho biến _rotation để có trị thích hợp khoảng Để kiểm tra, bạn ghi câu lệnh theo dõi trace("Góc quay: " + _rotation); sau câu lệnh _rotation += step; hàm OnClipEvent(enterFrame) Bằng cách dùng hàm trace vậy, chạy chương trình, bạn thấy dịng thơng báo này: Góc quay: 120 Đó nhờ chuỗi "Góc quay: " ghép với trị số biến _rotation dấu cộng Nếu không muốn có q nhiều thơng báo bảng Output chạy chương trình, bạn thêm dấu // trước câu lệnh gọi hàm trace: //trace("Góc quay: " + _rotation); Flash hiểu ghi sau dấu // dịng phần thích, khơng cần xét đến biên dịch Do vậy, đặt dấu // trước câu lệnh giúp bạn tạm thời vơ hiệu hóa câu lệnh Khi muốn khơi phục hiệu lực câu lệnh, bạn cần xóa dấu // trước câu lệnh Bạn nhuộm màu tím cho hình vng có, gõ phím F11 để mở bảng Library kéo hình vng xanh từ thư viện vào sân khấu, tạo thêm thể nhân vật Square (hình 3) Trong bảng Actions, bạn viết hàm xử lý tình sau cho hình vng xanh lá:
onClipEvent(mouseMove) { trace("_xmouse: " + _xmouse); trace("_ymouse: " + _ymouse); trace("_alpha: " + _alpha); _alpha -= 1;
}
(20)(21)Bài 9: Nhân vật phức hợp
Trong hàm xử lý tình onClipEvent(mouseMove) hình vng xanh lá, bạn dùng thuộc tính _xmouse, _ymouse _alpha Hai thuộc tính _xmouse _ymouse hình vng xanh cho biết tọa độ trỏ chuột so với điểm mốc hình vng (trong trường hợp xét, điểm mốc nằm tâm hình vng) Thuộc tính _alpha cho biết độ đục hình vng Khi độ đục nhỏ 0, hình vng trở nên suốt
Vào lúc chạy chương trình, hàm onClipEvent(mouseMove) gọi trỏ chuột "nhúc nhích" Với câu lệnh viết bên hàm đó, bạn đẩy chuột, thơng báo vị trí trỏ chuột độ đục liên tục bảng Output, đồng thời độ đục giảm dần Chỉ cần đẩy chuột đôi chút, bạn làm cho hình vng nhợt nhạt biến (hình vng trở nên "vơ hình") Có lẽ bạn muốn làm "thực tế" trị "nhảm nhí" nêu Ta thực việc "có lý": hình vng tự nhảy đến vị trí trỏ chuột bấm chuột Bạn ghi dấu /* trước hàm onClipEvent(mouseMove) ghi dấu */ sau hàm gõ hàm onClipEvent(mouseUp):
/*
onClipEvent(mouseMove) { trace("_xmouse: " + _xmouse); trace("_ymouse: " + _ymouse); trace("_alpha: " + _alpha); _alpha -= 1;
} */
onClipEvent(mouseUp) { _x = _root._xmouse; _y = _root._ymouse; }
(22)(23)Bài 10: Hàm có sẵn
Có lẽ bạn nóng lịng muốn lập trình trị chơi thú vị với Flash Tuy vậy, bạn cần kiên trì tìm hiểu khái niệm lập trình Khi có tảng vững vàng, bạn tự sáng tạo Thực có nhiều điều thú vị kiến thức
Ngoài hàm trace() mà bạn dùng vài lần để theo dõi diễn biến chương trình, cịn nhiều hàm có sẵn (built-in function) khác Flash, làm đủ thứ việc Gọi "hàm có sẵn" để phân biệt với hàm bạn tự tạo ra, tự đặt tên (user-defined function) Bạn cần biết cách dùng hàm có sẵn trước thử tạo hàm có chức ý Bạn khởi động Flash chọn Flash Document để tạo tập tin Bạn gõ phím F9 để mở bảng Actions Nói cho rõ, dòng tiêu đề bảng Actions - Frame, ngụ ý câu lệnh bạn viết bảng có hiệu lực khung hiện hành, thi hành Flash hiển thị khung vào lúc chạy Khác với trường hợp lập trình cho nhân vật thể hiện, bạn không viết hàm xử lý tình Bạn gõ hai câu lệnh sau: result = Math.pow(2, 3);
trace("2 lũy thừa 3: " + result);
Câu lệnh thứ tính "2 lũy thừa 3" gán kết cho biến mang tên result (để tạo biến, bạn thoải mái viết tên biến tùy ý gán trị cho nó) Câu lệnh thứ hai trình bày trị biến result bảng Output, giúp bạn biết kết tính có hay không Lúc viết câu lệnh thứ nhất, sau bạn gõ Math dấu chấm, Flash nhanh nhẩu đưa danh sách hàm (hình 1) Bạn gõ thêm chữ p, Flash đốn hàm lũy thừa pow Thay gõ tiếp ow, bạn gõ Enter để chấp thuận cho Flash ghi hàm pow thay Tiếp theo, Flash nhiệt tình đưa dịng hướng dẫn nhắc bạn đối mục thứ hàm pow số đối mục thứ hai số mũ Viết xong hai câu lệnh, bạn ấn Ctrl+Enter để chạy chương trình Khi hiển thị khung số (ngồi khung số 1, bạn chưa có khung khác), Flash thi hành hai câu lệnh ghi khung Kết xuất bảng Output cho thấy Flash "tính tốn thần": lũy thừa 3:
(24)thừa với số số mũ 1, 2, , cách viết lại đoạn mã ActionScript cho khung sau:
for(i = 1; i < 10; i++) { result = Math.pow(2, i);
trace("2 lũy thừa " + i + ": " + result); }
Chạy chương trình, bạn thu kết bảng Output (hình 2) Bạn thấy rõ câu lệnh result = Math.pow(2, i); thi hành lặp lặp lại lần Người ta gọi vịng lặp (loop) Trong lần thi hành đầu tiên, biến i gán trị Mỗi lần lặp lại, trị biến i tăng thêm so với trước
(25)Bài 11: Hàm tự tạo
Sau dùng thử hàm Math.pow (hàm pow lớp Math), có lẽ bạn muốn biết hàm có sẵn khác Để tra cứu hàm có sẵn, bạn trỏ vào cạnh trái khung soạn thảo bảng Actions (trong cửa sổ Flash, bảng Actions chưa mở, bạn gõ phím F9), cho trỏ chuột chuyển thành dạng "mũi tên hai đầu", kéo chuột qua phải Bạn thấy lộ cửa sổ "bí mật", chứa đựng "tàng thư" quan trọng việc lập trình Flash (hình 1)
Thư mục Global Functions giúp bạn tìm hiểu hàm toàn cục, tức hàm cần dùng thường xuyên, không nằm lớp Thư mục Global Properties liệt kê biến toàn cục, tức biến mà bạn dùng lúc viết chương trình Biến tồn cục dùng chung cho nhân vật thể Thư mục Built-in Classes giúp bạn tìm hiểu lớp có sẵn Bấm vào thư mục đó, bạn thấy thư mục con, thư mục Core liệt kê lớp cốt lõi Thử bấm vào thư mục Core, bấm vào thư mục Math, bấm vào thư mục Methods, bạn thấy rõ hàm thuộc lớp Math Trỏ vào hàm, bạn thấy dịng giải thích ngắn gọn công dụng hàm
(26)phải tạo hàm phù hợp với nhu cầu Người ta gọi hàm tự tạo (user-defined function) nhằm phân biệt với hàm có sẵn Để thử tạo hàm, bạn xóa nội dung có trong bảng Actions (nếu còn) gõ đoạn mã sau:
function init() { num = 0; }
function count() { num++;
trace("Số đếm là: " + num); }
Viết nghĩa bạn định nghĩa hai hàm init() count() Định nghĩa hàm function, nhằm làm cho Flash hiểu "Đây hàm nhé!" Sau từ function tên hàm bạn tùy ý chọn cặp dấu ngoặc () Tiếp theo, phần ghi cặp dấu gộp {} thân hàm (function body), diễn đạt việc mà hàm thực
Hàm init() gán cho biến num trị ban đầu Hàm count() làm cho trị biến num tăng thêm thể trị biến num bảng Output Bạn hình dung hàm count() dùng để đếm thứ Bạn gọi hàm count() để "đếm tới" Khi cần "đếm lại từ đầu", bạn gọi hàm init() trước, sau gọi hàm count() Để thử dùng hai hàm toanh mình, bạn ghi thêm sau bên hai định nghĩa hàm:
init();
for(i = 0; i < 5; i++) { count();
}
Viết nghĩa gọi hàm init(), gọi hàm count() năm lần Thay viết năm lần câu lênh count(); ta dùng vòng lặp for theo cách thức mà bạn biết Ấn Ctrl+Enter để chạy chương trình, bạn thấy dịng thơng báo số đếm năm lần dự định Định nghĩa hàm cịn viết theo cách khác sau:
init = function() { num = 0; }
(27)trace("Số đếm là: " + num); }
Thay viết vịng lặp for, bạn dùng vịng lặp while: while(num < 5) {
count(); }
Sửa lại chương trình theo cách viết chạy thử, bạn thấy kết bảng Output hoàn toàn giống trước Quan sát cách viết vòng lặp while, bạn hiểu ngay: vịng lặp trì điều kiện num < thoả Sau biến num nhận trị số 5, điều kiện num < không thỏa nữa, vòng lặp kết thúc Khi lập trình, bạn thấy viết viết lại nhóm câu lệnh đó, cần nghĩ đến việc viết hàm chứa đựng nhóm câu lệnh để dùng cho tiện, khơng nên để chương trình dài lê thê với nhiều đoạn tương tự Sau định nghĩa hàm, cần câu lệnh gọi hàm đó, bạn giải nhanh gọn nhiều việc
Bài 12: Trò chơi "rượt bắt"
Với điều biết Flash, bạn bắt tay vào việc thực trò chơi "rượt bắt" đơn giản: vật rượt theo bạn, nói cho rượt theo trỏ chuột bạn điều khiển Có thể hình dung trỏ chuột di chuyển nước cá "hung dữ" đuổi theo Trước hết, bạn mở cửa sổ Flash, bắt đầu với tập tin trống trơn Bạn cần vẽ hình trịn tượng trưng cho cá (tưởng tượng cá nóc) Khi chương trình chạy tốt, ta vẽ cá cách tỉ mỉ Để vẽ hình trịn, bạn biết cần dùng cơng cụ Oval Tool giữ phím Shift vẽ sân khấu Xong, bạn bấm vào công cụ chọn Selection Tool , căng khung chọn bao quanh hình trịn vừa vẽ, chuẩn bị chọn màu tô (fill color) màu nét (stroke color) Ở hộp cơng cụ phía trái cửa sổ Flash, bạn ý phần Colors có hai ô màu Bạn bấm vào ô màu trên, chọn màu nét bảng màu vừa Tương tự, bạn bấm vào ô màu dưới, chọn màu tô Bạn nên chọn màu nét đen màu tô sáng (màu cam chẳng hạn) cho dễ thấy "con cá" Để hình trịn trở thành nhân vật, bạn gõ phím F8 Khi thấy hộp thoại Convert to Symbol, bạn gõ Fish để đặt tên cho nhân vật gõ Enter Từ đây, hình trịn diện sân khấu thể nhân vật Fish Để lập trình cho cá, bạn gõ phím F9 để mở cửa sổ Actions - Movie Clip (hình 1) Vì thể nhân vật Fish tình trạng "được chọn", bạn ghi vào cửa sổ Actions - Movie Clip quy định hành vi thể Bạn biết muốn diễn đạt hành vi thể hiện, ta phải viết hàm xử lý tình Bạn viết hai hàm xử lý tình sau để làm cho cá biết đuổi theo trỏ chuột:
onClipEvent(load) { step = 5;
}
onClipEvent(enterFrame) { if(_x + step < _root._xmouse) _x += step;
else if(_x - step > _root._xmouse) _x -= step;
(28)Trong hàm onClipEvent(load), ta tạo biến step gán trị cụ thể cho Biến step xác định bước dịch chuyển cá Trị biến step lớn, cá dịch chuyển nhanh Hàm onClipEvent(enterFrame) gọi Flash hiển thị khung Hiện thời, bạn có khung Flash hiển thị khung lặp lặp lại vào lúc chạy, hàm onClipEvent(enterFrame) gọi liên tục Trong hàm onClipEvent(enterFrame), để biết cá có nên tới hay khơng (có nên gia tăng hồnh độ _x cá hay khơng), ta lấy hoành độ _x cá cộng với step so sánh kết với hoành độ trỏ chuột (tức _root._xmouse) Nếu kết phép cộng cịn nhỏ hồnh độ trỏ chuột (điều kiện _x + step < _root._xmouse thỏa), ta cho hoành độ _x cá tăng thêm bước: x += step; Nếu kết lớn hoành độ trỏ chuột, rõ ràng không nên tới cần tiếp tục xét xem có nên lui hay khơng Để biết có nên cho cá lui hay khơng, ta lấy hồnh độ _x trừ step so sánh kết phép trừ với hoành độ trỏ chuột Nếu kết cịn lớn hồnh độ trỏ chuột, nên cho cá lui cách giảm hoành độ _x bước: x -= step; Ngoài trường hợp xét, hoành độ _x giữ nguyên, tức cá đứng yên Có lẽ bạn ngờ ngợ cách viết hàm onClipEvent(enterFrame) Dường phải dùng cặp dấu gộp {} sau cú pháp câu lệnh điều kiện:
onClipEvent(enterFrame) { if(_x + step < _root._xmouse) { _x += step;
}
else if(_x - step > _root._xmouse) { _x -= step;
} }
(29)chưa "huấn luyện" cho cá làm điều Để cá biết nên bơi lên xuống nào, hàm onClipEvent(enterFrame), bạn cần xét đến tung độ _y cá tung độ trỏ chuột _root._ymouse theo cách thức tương tự làm hồnh độ Trở lại với chương trình, bạn viết thêm vào hàm onClipEvent(enterFrame) sau:
onClipEvent(enterFrame) { if(_x + step < _root._xmouse) _x += step;
else if(_x - step > _root._xmouse) _x -= step;
if(_y + step < _root._ymouse) _y += step;
else if(_y - step > _root._ymouse) _y -= step;
}
Thử chạy chương trình, bạn thấy rõ cá trở nên "khơn lanh" hẳn
Bài 13: Hàm kiểm tra va chạm
Trong trò chơi "rượt bắt" đơn giản thực hiện, bạn huấn luyện cá cách thức rượt đuổi mục tiêu di động trỏ chuột Với hàm onClipEvent(enterFrame) viết, cá "rượt", chưa "bắt" Con cá cần nhận biết thời điểm chạm vào mục tiêu để cịn "la tống" lên
Thực ta cần bổ sung chút Trường hợp cá bắt kịp trỏ chuột xem trường hợp cá đứng n, khơng phải di chuyển theo phương ngang theo phương dọc Bạn bấm chọn cá sân khấu, mở bảng Actions (gõ phím F9) viết thêm vào hàm onClipEvent(enterFrame) để có nội dung sau:
onClipEvent(enterFrame) { caught = false;
if(_x + step < _root._xmouse) _x += step;
else if(_x - step > _root._xmouse) _x -= step;
else caught = true;
if(_y + step < _root._ymouse) _y += step;
else if(_y - step > _root._ymouse) _y -= step;
else if(caught == true) trace("Bắt nhé!"); }
(30)Tiếp theo, biết cá không cần di chuyển theo phương dọc, ta xét xem biến caught có trị true hay khơng Khi đó, caught có trị true, nghĩa xảy tình trạng cá không cần di chuyển theo phương ngang theo phương dọc, câu lệnh trace("Bắt nhé!"); thông báo trỏ chuột bị bắt Chạy thử chương trình giả vờ chậm chạp để cá bắt kịp trỏ chuột, bạn thấy rõ chi tiết bổ sung hàm onClipEvent(enterFrame) có hiệu lực Nhưng người chơi phải giả vờ thua, chơi dễ, ý nghĩa Ta cần làm cho người chơi bận rộn hơn, căng thẳng hơn, cách bày thêm luật chơi sau: bị cá đuổi, người chơi phải tóm biển Mỗi lần bấm trúng biển, người chơi thêm điểm, biển xuất ngẫu nhiên vị trí khác cá di chuyển nhanh Để có biển, bạn tạm vẽ hình ngơi đơn giản Bạn trỏ vào cơng cụ vẽ hình khung Rectangle Tool , giữ phím trái chuột chút xíu, chọn công cụ PolyStar Tool (công cụ vẽ đa giác hình sao) Ấn Ctrl+F3, bạn thấy bảng Properties mở ra, trình bày quy định liên quan đến hoạt động công cụ mà bạn "cầm tay" Bạn bấm nút Options để mở hộp thoại Tool Settings (hình 1) Trong đó, bạn chọn mục star Style bấm OK Trong bảng Properties, bạn chọn trước màu nét màu tơ cho hình vẽ
Trỏ vào sân khấu, bạn giữ phím trái chuột, kéo chuột qua phải, xuống dưới, để căng hình ngơi năm cánh Gõ phím V để chuyển qua cơng cụ chọn Selection Tool, ban căng khung chọn bao quanh hình Bạn gõ phím F8 để mở hộp thoại Convert to Symbol, gõ tên Star gõ Enter Thao tác tạo nhân vật "sao biển" mang tên Star Hình sân khấu trở thành thể nhân vật Star Ta cần lập trình để biển nhận biết trỏ chuột có chạm vào hay không người chơi bấm chuột Mỗi bị bấm trúng, biển có nhiệm vụ cộng điểm cho người chơi Gõ phím F9 để mở bảng Actions tương ứng với thể chọn (hình 2), bạn gõ đoạn mã sau:
onClipEvent(load) { score = 0;
}
onClipEvent(mouseDown) {
if(hitTest(_root._xmouse, _root._ymouse, true)) { score++;
trace("Điểm: " + score); }
(31)Hàm onClipEvent(load) biển tạo biến score để ghi điểm cho người chơi, có trị ban đầu Hàm onClipEvent(mouseDown), bạn nhớ, diễn đạt việc cần làm người chơi bấm chuột Để biết vị trí trỏ chuột có nằm hình hay khơng, ta dùng hàm hitTest() có sẵn nhân vật Flash Hàm hitTest() cho kết trị true trị false tùy theo trỏ chuột có chạm vào thể xét hay không Hai đối mục hàm hitTest() hoành độ tung độ trỏ chuột (_root._xmouse _root._ymouse) Nếu đối mục thứ ba false, hàm hitTest() kiểm tra xem trỏ chuột có nằm khung bao chữ nhật (bounding box) thể hay khơng Vì ta ghi đối mục thứ ba hàm hitTest() true, hàm hitTest() kiểm tra kỹ hơn, trả cho ta trị true trỏ chuột thực chạm vào hình Quan sát câu lệnh điều kiện hàm onClipEvent(mouseDown), bạn hiểu ngay: trỏ chuột chạm vào biển, trị biến score tăng thêm thông báo xuất bảng Output cho người chơi biết họ đạt điểm Thử chạy chương trình, bạn thấy tuy biển chưa di chuyển dự định trò chơi trở nên thú vị
Bài 14: Hàm tính trị ngẫu nhiên
Trong trò chơi thực hiện, ta dự định cho biển di chuyển ngẫu nhiên bấm trúng (xem người chơi nhặt biển biển khác xuất vị trí bất kỳ) Muốn vậy, hàm onClipEvent(mouseDown) biển, bạn gán trị ngẫu nhiên cho hoành độ _x tung độ _y biển Nhưng trước tiên bạn cần làm quen với hàm tính trị ngẫu nhiên random() lớp Math
(32)onClipEvent(mouseDown) {
if(hitTest(_root._xmouse, _root._ymouse, true)) { trace("Trị ngẫu nhiên: " + Math.random()); score++;
trace("Điểm: " + score); }
}
Thử chạy chương trình, bạn thấy bấm trúng biển, biển thông báo trị ngẫu nhiên bảng Output Bấm biển nhiều lần, bạn nhận trị ngẫu nhiên trả hàm Math.random() ln nhỏ Nói xác, hàm Math.random() cho ta trị ngẫu nhiên lớn nhỏ Muốn thu trị ngẫu nhiên khoảng tùy ý, ta phải "phóng lớn" trị trả hàm Math.random() Để cho rõ ràng, ta viết hàm để tính trị ngẫu nhiên khoảng tùy ý dùng hàm hàm onClipEvent(mouseDown) biển Chương trình biển chấp nhận hàm xử lý tình nên bạn phải viết hàm cần thiết chỗ khác Bấm vào chỗ trống sân khấu, bạn thấy chương trình biển biến Bảng Actions -Frame trước mắt bạn dùng để lập trình cho khung (hình 1) Bạn viết hàm tính trị ngẫu nhiên "ngon lành" hơn, gọi getRandom(min, max), sau:
function getRandom(min, max) { var num = Math.random(); num = num * (max - min); num = num + min;
(33)Hàm getRandom(min, max) cho trị ngẫu nhiên khoảng từ đến max cách nhân trị trả hàm Math.random() với khoảng cách max min, tức max - min, cộng kết với Câu lệnh return num; làm cho hàm getRandom(min, max) trả kết tính tốn gọi Đây lần bạn viết hàm có trả trị số Ngồi ra, bạn ý đến từ var câu lệnh var num = Math.random(); Câu lệnh tạo biến (variable) mang tên num để chứa trị trả hàm Math.random() Viết từ var tạo biến num, ta ngụ ý biến num biến tạo tạm thời hàm getRandom() Biến vây gọi biến cục bộ, xóa khỏi nhớ máy hàm getRandom() kết thúc công việc Bạn bấm vào biển để trở với chương trình biển bảng Actions -Movie Clip Trong hàm onClipEvent(mouseDown), bạn gọi hàm getRandom() vừa viết để thử tính trị ngẫu nhiên từ đến 400:
onClipEvent(mouseDown) {
if(hitTest(_root._xmouse, _root._ymouse, true)) { trace("Trị ngẫu nhiên: " + _root.getRandom(0, 400)); score++;
trace("Điểm: " + score); }
}
Có lẽ bạn thắc mắc: "Vì phải viết _root.getRandom(0, 400), thay viết đơn giản getRandom(0, 400)?" Nếu bạn không dùng tham chiếu _root, xem xét chương trình biển, Flash khơng biết phải đọc hàm getRandom() khung thời tuyến chính, khác với thời tuyến dùng bên thể nhân vật biển Thử chạy chương trình bấm nhiều lần vào biển, bạn thấy rõ hàm getRandom() ta cho trị ngẫu nhiên nhỏ 400 Để biển di chuyển khắp sân khấu, hoành độ _x biển phải có trị nhỏ chiều rộng sân khấu tung độ _y phải có trị nhỏ chiều cao sân khấu Bấm vào chỗ trống sân khấu để chọn biển, bạn thấy lại chương trình thời tuyến Bạn chỉnh sửa bổ sung để có nội dung sau:
function getRandomX() { return getRandom(0, 550); }
function getRandomY() { return getRandom(0, 400); }
function getRandom(min, max) {
return Math.random()*(max - min) + min; }
Như bạn thấy, ta định nghĩa thêm hai hàm mới: getRandomX() getRandomY() Hàm getRandomX() dùng để tạo trị ngẫu nhiên lớn nhỏ 550 Trong đó, 550 chiều rộng mặc định sân khấu Hàm getRandomX() thích hợp cho việc tạo hồnh độ ngẫu nhiên bao quát chiều rộng sân khấu Hàm getRandomX() khơng làm nhiều, dựa hồn tồn vào tính toán hàm getRandom(min, max) Chiều cao mặc định sân khấu 400, bạn hiểu hàm getRandomY() viết để dùng vào việc Ngồi ra, bạn hiểu cách tính tốn hàm getRandom(min, max), ta viết lại nội dung hàm dạng gọn hơn, có ý nghĩa tương đương Chuyển qua chương trình biển (bấm vào biển), bạn chỉnh sửa sau:
(34)if(hitTest(_root._xmouse, _root._ymouse, true)) { _x = _root.getRandomX();
_y = _root.getRandomY(); score++;
trace("Điểm: " + score); }
}
(35)Bài 15: Liên lạc thể hiện
Bạn làm cho biển xê dịch ngẫu nhiên tăng thêm điểm cho người chơi biển bấm trúng Khi đó, theo dự định, ta cịn phải làm cho cá chuyển động nhanh Điểm người chơi cao, cá bơi nhanh Có vậy, trò chơi hào hứng! Chắc chắn cá bắt trỏ chuột vào lúc Khi cá bắt trỏ chuột, trò chơi cần trở lại từ đầu: điểm người chơi gán lại trị số Điểm cao đạt thể "đẳng cấp" người chơi
Với mục tiêu vậy, biển cần liên lạc với cá để yêu cầu tăng tốc Ngược lại, cá phải yêu cầu biển cho người chơi điểm cá bắt trỏ chuột Để cá biển "nói chuyện" với nhau, trước hết bạn phải đặt tên cho chúng Cá thể nhân vật Fish, biển thể nhân vật Star, hai thể chưa có tên riêng Bạn bấm vào cá ấn Ctrl+F3 để mở bảng Properties Bạn bấm vào có dịng chữ <Instance Name>, gõ fish gõ Enter (đặt tên cho cá fish) Bạn bấm chọn biển Bảng Properties thay đổi, tương ứng với biển Bạn bấm vào có dịng chữ <Instance Name>, gõ star gõ Enter (đặt tên ngắn gọn cho biển star) Xong, bạn bấm vào tiêu đề bảng Properties để tạm dẹp Bạn mở bảng Actions (trình bày chương trình biển), viết thêm câu lệnh hàm onClipEvent(mouseDown) sau:
onClipEvent(mouseDown) {
if(hitTest(_root._xmouse, _root._ymouse, true)) { _x = _root.getRandomX();
_y = _root.getRandomY(); score++;
trace("Điểm: " + score); _root.fish.step++; }
}
Câu lệnh mà bạn vừa viết tăng thêm cho trị số biến step bên cá Để diễn đạt biến step cá chương trình biển, bạn phải ghi _root.fish.step, ghi đơn giản fish.step Tham chiếu _root trỏ đến sân khấu, nơi lưu giữ "tên tuổi" "diễn viên" Bạn cần điều chỉnh thêm chút xíu trước chạy thử chương trình: bấm-phải vào cá, trỏ vào mục Arrange trình đơn vừa ra, chọn mục Bring to Front Nhờ vậy, cá đặt phía trước biển, gây "khó dễ" cho bạn nhiều Thử chạy chương trình, bạn thấy câu lệnh có hiệu lực rõ ràng: điểm bạn tăng (bắt nhiều biển), cá hoảng hốt, sức bảo vệ biển Khi cá bắt trỏ chuột, người chơi không hấn Điều khơng cơng Bạn đóng cửa sổ chương trình nhìn vào bảng Actions (lúc trình bày chương trình cá) Bạn ý trường hợp "bắt trỏ chuột" diễn đạt phần cuối hàm onClipEvent(enterFrame) Bạn chỉnh sửa sau:
onClipEvent(enterFrame) {
else if(caught == true) { trace("Bắt nhé!"); _root.star.score = 0; step = 5;
(36)}
Câu lệnh _root.star.score = 0; gán trị số cho biến score bên biển, buộc người chơi trở lại mức xuất phát Để diễn đạt biến score biển chương trình cá, bạn phải viết _root.star.score, viết đơn giản star.score Câu lệnh step = 5; làm cho cá "bình tĩnh" trở lại, bơi chậm lúc đầu sau bắt trỏ chuột Chạy lại chương trình, vừa chơi vừa liếc nhìn bảng Output, bạn thấy cơng trò chơi thiết lập: cá bắt kịp trỏ chuột, "điểm tích lũy" bạn sạch! Khi trò chơi bạn chạy trang web, người chơi không thấy bảng Output Do vậy, bạn cần hiển thị điểm sân khấu Bạn bấm vào công cụ Text Tool (hoặc gõ phím T), căng khung nhỏ góc dưới, bên trái sân khấu gõ SCORE: Bạn mở lại bảng Properties cách bấm vào tiêu đề bảng Bấm vào ơ Text Type bảng Properties, bạn chọn Static Text (thay cho Dynamic Text), quy định khung chữ bạn có nội dung cố định, khơng thay đổi Người ta gọi là khung chữ tĩnh Nếu cần thay đổi phơng chữ cỡ chữ, bạn chọn dịng chữ SCORE: (kéo chuột ngang qua dịng chữ), chọn phơng chữ ô Font, bấm kép vào ô Font Size gõ trị số tùy ý (20 chẳng hạn) Bạn căng khung khác bên phải dòng chữ SCORE: để tạo khung chữ (hình 1) Trong bảng Properties (lúc tương ứng với khung chữ mới), bạn chọn phông chữ cỡ chữ giống dòng chữ SCORE Bấm vào ô Var, bạn gõ _root.star.score gõ Enter Thao tác tạo khung chữ động trình bày trị số biến _root.star.score (nội dung khung chữ thay đổi theo trị số biến _root.star.score) Chạy thử chương trình, bạn thấy khung chữ động thể điểm số (so với thơng báo bảng Output)
Bài 16: Vẽ biển
(37)Cụ thể, bạn bấm vào biển sân khấu, mở bảng Actions viết thêm vào chương trình biển sau:
onClipEvent(load) { score = 0;
highscore = 0; }
onClipEvent(mouseDown) {
if(hitTest(_root._xmouse, _root._ymouse, true)) { _x = _root.getRandomX();
_y = _root.getRandomY(); score++;
if(score > highscore) highscore = score; trace("Điểm: " + score); _root.fish.step++; }
}
(38)Khi trị chơi chạy tốt, bạn bước qua giai đoạn chăm chút "ngoại hình" Ta bắt đầu với việc "tút lại vẻ đẹp giai" biển Bạn bấm kép vào biển để chuyển qua chế độ chỉnh sửa nhân vật biển Muốn lấy tầm nhìn gần cho tiện việc "tân trang", bạn chọn công cụ Zoom Tool (hoặc gõ phím Z) bấm vào biển vài lần Nếu lỡ nhìn gần, bạn chọn Reduce hộp công cụ bấm vào biển để "lui xa" Bạn "cầm lấy" công cụ chọn , bấm vào bên ngồi biển để "thôi chọn" biển Đưa trỏ chuột vào cạnh biển, bạn thấy trỏ chuột đổi dạng , tỏ ý sẵn sàng giúp bạn chỉnh sửa đường nét biển Bạn nắm kéo cạnh biển để uốn cong tùy ý (hình 2) Thật tuyệt! Cứ thế, bạn uốn cong cạnh hình khơ cứng ban đầu để có đường nét mềm mại
Khi hài lịng hình dạng biển, bạn bấm kép vào dòng chữ Layer bảng Timeline , gõ tên Thân Thao tác đổi tên lớp giúp bạn nhớ lớp xét chứa thân biển Bạn bấm vào dấu chấm bên hình ổ khóa để lớp Thân "khóa cứng", khơng thể chỉnh sửa
Bạn tạo lớp Layer cách bấm vào biểu tượng Insert Layer , đổi tên Layer thành Mắt, ngụ ý lớp dùng để chứa mắt biển.
Vẽ mắt dễ, bạn chọn công cụ Oval Tool , bấm vào ô Fill Color , chọn màu tô màu đen vẽ hình trịn nhỏ Bạn bấm vào cơng cụ chọn , căng khung chọn bao quanh hình trịn đen vừa vẽ, ấn Ctrl+C để chép, ấn Ctrl+V để dán vào lớp Mắt Bạn kéo hai hình trịn đen vào biển, tạo nên cặp mắt
(39)Bài 17: Vẽ cá nóc
Mở lại trị chơi "bắt biển" Flash, bạn bấm kép vào hình trịn mà ta gọi cá để chuyển qua chế độ chỉnh sửa nhân vật Fish Bạn gõ phím Z để lấy công cụ Zoom Tool , căng khung chọn bao quanh hình trịn để có tầm nhìn gần, tập trung vào hình trịn
(40)(41)Bài 18: Diễn hoạt phận
(42)hợp Cách "chỉnh sửa" dễ dàng xóa hình vẽ tạm hiẹn có (ấn Ctrl+A để chọn tất gõ phím Delete), vẽ lại cách cẩn trọng Mỗi phần hình cần đặt lớp riêng Bạn vẽ hình trịn màu cam, di chuyển hình trịn cho điểm mốc nhân vật Eye nằm thấp so với tâm hình trịn (hình 1) Khi chọn hình trịn để di chuyển, bạn nhớ chọn đường biên hình trịn (bấm vào hình trịn, giữ phím Shift bấm vào biên hình trịn) Nếu có chưa ưng ý, bạn cần ấn Ctrl+Z để hủy bỏ thao tác vừa thực Bạn tạo lớp Layer vẽ hình ơ-van màu trắng Bạn ý di chuyển hình ô-van cho tâm trùng với điểm mốc nhân vật Eye (hình 1) Bạn tạo lớp Layer 3, vẽ hình trịn màu đen di chuyển hình trịn cho tâm trùng với điểm mốc (hình 1) Đó trịng đen mắt cá
Để lập trình cho trịng đen, ta cần chuyển tròng đen thành nhân vật riêng biệt Muốn vậy, trước hết bạn chọn tròng đen đường biên (để khỏi "vướng víu" đường biên trịng đen, bạn chọn đường biên đó, gõ phím Delete để xóa, dùng cơng cụ co dãn để điều chỉnh kích cỡ trịng đen cho phù hợp) Bạn gõ phím F8 để mở hộp thoại Convert to Symbol, gõ tên Pupil (tròng đen) gõ Enter Tròng đen trở thành thể nhân vật Pupil Với trịng đen tình trạng "được chọn", bạn gõ phím F9 để mở bảng Actions - Movie Clip (hình 2), viết hàm xử lý tình "di chuyển chuột" sau:
onClipEvent(mouseMove) {
a = Math.atan2(_ymouse, _xmouse); _x = 3*Math.cos(a);
(43)(44)Bài 19: Hình nhạc nền
Trò chơi Flash bạn gần hồn chỉnh, bạn thêm vào hình nhạc cho "sướng mắt tai" Do bạn chưa thật quen với công cụ vẽ Flash để tự vẽ hình nền, bạn nên tìm hình ảnh mạng Chẳng hạn, gõ từ chốt underwater images tìm kiếm Google, bạn tìm nhiều hình chụp nước
(45)(46)Khác với trường hợp hình xét, đoạn nhạc bạn không đưa vào sân khấu cách tự động Bạn phải chủ động quy định nhạc cách bấm vào khung (cũng khung nhất) lớp nền, bấm vào ô Sound bảng Properties, chọn đoạn nhạc cần thiết (hình 3) Theo mặc định, đoạn nhạc chọn phát lần Để đoạn nhạc lặp lại hồi hồi suốt trị chơi, bạn bấm vào ô Sound Loop, chọn Loop thay cho Repeat Vậy đủ, bạn ấn Ctrl+Enter để chạy trò chơi, nghe thử nhạc
Nếu quan sát thư mục chứa tập tin FLA SWF trò chơi, bạn ngạc nhiên tập tin SWF (được biên dịch từ tập tin FLA) bé so với tập tin FLA Tập tin SWF chứa thứ cần thiết trị chơi (chương trình, hình vẽ, hình nền, âm thanh) thường nhỏ nhiều so với tập tin MP3 dùng nhờ Flash nén âm tốt Bạn đưa nhiều đoạn nhạc vào thư viện để dễ lựa chọn đoạn nhạc mà bạn thực dùng trò chơi lưu trữ tập tin SWF
Bài 20: Câu lệnh tạo thể hiện
Bạn biết cách tạo thể nhân vật: trỏ vào tên nhân vật thư viện, kéo vào sân khấu Ngoài cách thức thủ cơng vậy, ta cịn tạo thể nhân vật câu lệnh ActionScript, nghĩa tạo thể vào lúc chạy chương trình Đó việc thường làm lập trình Flash ta khơng ln ln biết trước cần sân khấu Số lượng thể sân khấu thay đổi Mỗi thể xuất biến tùy lúc Thử hình dung diễn biến trò chơi Space Invaders quen thuộc, bạn thấy ngay: việc tạo thể cách linh hoạt vào lúc chạy nhu cầu thiết
(47)sân khấu trở thành thể nhân vật Oval Gõ phím F11 để mở bảng Library, bạn thấy rõ nhân vật Oval lưu trữ Bạn xóa thể nhân vật Oval sân khấu (bấm vào hình ơ-van, gõ phím Delete) Ta tạo thể nhân vật Oval sân khấu trống trơn câu lệnh thích hợp Trước làm điều đó, bạn bấm-phải vào tên Oval thư viện, chọn Linkage trình đơn vừa Trong hộp thoại Linkage Properties, bạn chọn mục Export for ActionScript (hình 1) bấm OK Thao tác nhằm khai báo với Flash rằng: "Khi tạo tập tin SWF, nhớ ghi vào nhân vật mang tên Oval" Nếu bạn không khai báo vậy, Flash sẽ không ghi nhân vật Oval vào tập tin SWF với lý đơn giản: nhân vật Oval không diện sân khấu Một tập tin SWF khơng có nhân vật Oval, chương trình ghi SWF tạo thể nhân vật Oval vào lúc chạy
Có lẽ bạn ngạc nhiên chuyện khai báo nêu trên: "Tại Flash không tự động ghi nhân vật thư viện vào tập tin SWF, dù có diện sân khấu không?" Nghĩ kỹ chút, bạn thấy "khó chịu" Flash mang đến lợi ích cho bạn Bạn lưu trữ nhiều thứ thư viện tập tin sản phẩm SWF nhỏ gọn, chứa đựng thứ thực dùng Trong trường hợp xét, nhân vật Oval sân khấu ta cần vào lúc chạy, phải "nói trước" để Flash hiểu rõ ý định ta Bạn gõ phím F9 để mở bảng Actions - Frame, nơi dùng để viết chương trình cho khung thời tuyến Ta dùng thuật ngữ thời tuyến (main timeline) để phân biệt với thời tuyến bên thể Bạn gõ đoạn mã sau bảng Actions - Frame:
attachMovie("Oval", "oval1", 1); attachMovie("Oval", "oval2", 2); attachMovie("Oval", "oval3", 3);
Ta dùng ba câu lệnh để tạo ba thể nhân vật Oval có tên oval1, oval2 oval3 Đối mục hàm attachMovie() tên nhân vật Đối mục thứ hai tên thể Đối mục thứ ba cho biết thể nằm "độ sâu" sân khấu Với cách viết trên, thể oval1 nằm sâu sân khấu Thể oval2 nằm oval1 thể oval3 nằm oval2 Ấn Ctrl+Enter để chạy chương trình, bạn thấy sân khấu có hình ơ-van Đó thể oval3 nằm cùng, chồng khít lên hai thể oval2 oval1 Theo mặc định, hàm attachMovie() tạo thể điểm gốc (0, 0) sân khấu Muốn thấy rõ ba thể hiện, bạn cần xê dịch chúng đơi chút Trở lại với chương trình viết, bạn gõ thêm đoạn mã sau: oval1._x += 100; oval1._y += 100;
oval2._x += 160; oval2._y += 100; oval3._x += 220; oval3._y += 100;
(48)Với thể tạo vào lúc chạy, bạn thay đổi thuộc tính chúng cách bình thường Chẳng hạn, bạn thay đổi biến _alpha thể hiện:
oval1._alpha = 50; oval2._alpha = 50; oval3._alpha = 50;
Đoạn mã viết thêm làm cho thể trở nên nửa suốt (hình 3)
Bài 21: Sao chép thể hiện
Bạn thử nghiệm câu lệnh tạo thể Từ sân khấu trống trơn, thể tạo vào lúc chạy chương trình Trong chương trình, bạn thay đổi thuộc tính thể cách bình thường Bạn mở lại tập tin FLA chứa câu lệnh thử nghiệm Ta tiếp tục tìm hiểu việc xóa bỏ thể chép thể vào lúc chạy
Trong bảng Actions - Frame chứa chương trình ứng với khung 1, bạn gõ thêm câu lệnh sau đoạn mã có:
attachMovie("Oval", "oval1", 1); attachMovie("Oval", "oval2", 2); attachMovie("Oval", "oval3", 3);
oval1._alpha = 50; oval2._alpha = 50; oval3._alpha = 50;
oval3.removeMovieClip();
(49)Có thể bạn ngờ ngợ: "Lẽ nên đặt tên cho oval4 tên oval3 dùng trước đó?" Đúng ta dùng tên oval3 cho thể khác, tạo trước Tuy nhiên, thể hiện bị xóa bỏ nên bạn dùng lại tên oval3 mà khơng gây xung đột Nhân tiện, xin nói nhỏ với bạn ta tạo thể có độ sâu với thể có, thể thay thể có độ sâu Cho dù bạn khơng dùng câu lệnh oval3.removeMovieClip(); để xóa bỏ thể oval3, câu lệnh oval1.duplicateMovieClip("oval3", 3); tự động xóa bỏ thể oval3 có trước độ sâu để tạo oval1 độ sâu Nếu khơng tin, bạn thử vơ hiệu hóa câu lệnh oval3.removeMovieClip(); (ghi dấu // đầu câu lệnh) chạy lại chương trình để thấy kết hình Với thể tạo vào lúc chạy, bạn cịn làm cho thay hình đổi dạng Bạn viết thêm hai câu lệnh sau:
//oval3.removeMovieClip();
oval1.duplicateMovieClip("oval3", 3); oval3._y += 100;
oval3.attachMovie("Oval", "oval1", 1); oval3.oval1._x += 40;
Câu lệnh oval3.attachMovie("Oval", "oval1", 1); nhằm tạo thể mang tên oval1 nhân vật Oval bên thể oval3 với độ sâu Bạn ý, độ sâu thể oval1 vừa thêm độ sâu bên oval3 Câu lệnh oval3.oval1._x += 40; dịch chuyển thể vừa thêm qua phải cho dễ phân biệt Thử chạy chương trình, bạn thấy kết hình
(50)
oval3.attachMovie("Oval", "oval1", 1); oval3.oval1._x += 40;
oval3._xscale = 50;
bạn thấy hai hình ơ-van oval3 bị ép Chắc bạn thắc mắc kinh khủng: "Sao lại dùng tên oval1? Tên oval1 dùng cho thể mà!" Bạn yên tâm, thể oval1 vừa tạo nằm bên oval3 Nhìn từ bên ngồi oval3, thể vừa thêm có tên oval3.oval1 Tên oval1 dùng hai phạm vi (scope) khác nên khơng có xung đột việc đặt tên
Bài 22: Nhân vật trống rỗng
Bạn mở lại tập tin FLA chứa đoạn mã thử nghiệm việc tạo thể vào lúc chạy chương trình Ta viết "nhăng nhít" khung thời tuyến chính, bạn cần bấm vào khung bảng Timeline, gõ F9 để mở bảng Actions - Frame Các câu lệnh viết tạo thể khác nhân vật Oval Bạn tạo nhân vật Oval từ trước cách vẽ hình ơ-van chuyển hình thành nhân vật
Bạn tạo thân nhân vật vào lúc chạy, không cần tạo trước nhân vật làm Đó loại nhân vật trống rỗng (empty movie clip) chưa có hình thù vào lúc tạo Sau tạo nhân vật vậy, bạn dùng câu lệnh thích hợp để vẽ vời "chân dung" cho Bạn đưa vào nhân vật trống rỗng thể nhân vật khác, tạo thành nhân vật phức hợp Trong thực tế, người ta thường tạo nhân vật trống rỗng đưa vào hình ảnh tải xuống từ máy chủ (khi việc tải xuống hoàn tất) Điều thực vào lúc chương trình chạy, khơng địi hỏi hình ảnh tải xuống khởi động, nhờ rút ngắn đáng kể thời gian khởi động chương trình Bạn ấn Ctrl+A gõ phím Delete để xóa câu lệnh viết Bạn viết đoạn mã sau để thử tạo nhân vật trống rỗng:
createEmptyMovieClip("myOvals", 1); myOvals._x = 100;
myOvals._y = 100; for(i = 1; i < 6; i++) {
myOvals.attachMovie("Oval", "oval" + i, i); }
Câu lệnh createEmptyMovieClip("myOvals", 1); tạo thể nhân vật trống rỗng thời tuyến chính, có tên myOvals đặt độ sâu Hai câu lệnh quy định hoành độ _x tung độ _y thể (dù chưa "mặt mũi") Vịng lặp for có nhiệm vụ lặp lại năm lần việc tạo thể nhân vật Oval bên myOvals Nhớ lại cách dùng hàm attachMovie(), bạn hiểu ngay: thể nhân vật Oval có tên oval1, , oval5 đặt độ sâu từ đến (các trị biến i) bên myOvals Để phân biệt dễ dàng thể oval1, , oval bên myOvals, ta cần làm cho chúng có vị trí khác Bạn viết thêm sau bên vòng lặp for:
(51)Năm câu lệnh vừa nêu xê dịch thể qua phải Các thể có hồnh độ _x khác Bạn ý, biểu thức myOvals.oval1._x dùng để diễn tả hoành độ _x thể oval1 bên thể myOvals Nếu bạn viết đơn giản oval1._x, Flash không thực yêu cầu bạn thời tuyến khơng tên oval1 Thử chạy chương trình, bạn thấy kết hình
Thay dùng đến năm câu lệnh để thay đổi hoành độ _x năm thể oval1, ,oval5, bạn viết lại theo cách khác, lịch lãm hơn, dùng câu lệnh vòng lặp for:
for(i = 1; i < 6; i++) {
myOvals.attachMovie("Oval", "oval" + i, i); eval("myOvals.oval" + i)._x += i*40;
}
/*
myOvals.oval1._x = 40; myOvals.oval2._x = 80; myOvals.oval3._x = 120; myOvals.oval4._x = 160; myOvals.oval5._x = 200;
*/
(52)Bài 23: Gán hành vi vào thể hiện
Bạn biết hành vi thể bao gồm hàm xử lý tình onClipEvent(mouseDown), onClipEvent(load), onClipEvent(enterFrame), Thông thường, bạn kéo nhân vật từ bảng Library vào sân khấu để tạo thể nhân vật Bạn quy định hành vi thể cách bấm chọn thể viết hàm xử lý tình cho thể chọn bảng Actions - Movie Clip
Đối với thể tạo vào lúc chạy chương trình, cách quy định hành vi thể có khác Trước chạy, thể khơng có sân khấu để bạn bấm chọn Do vậy, bạn gán hàm xử lý tình vào thể lúc chạy Bạn mở lại tập tin FLA dùng để thử nghiệm việc tạo thể vào lúc chạy, mở bảng Actions - Frame, xóa hết đoạn mã có ứng với khung viết đoạn mã thử nghiệm sau:
attachMovie("Oval", "oval1", 1); oval1._x = 200;
oval1._y = 100;
oval1.onMouseDown = function() { this._xscale += 5;
}
Ba câu lệnh đoạn mã vừa viết quen thuộc với bạn, chúng dùng để tạo thể oval1 từ nhân vật Oval quy định tọa độ cho thể Câu lệnh cuối quy định hàm xử lý tình onMouseDown thể oval1 Đó hàm gọi người dùng nhấn phím chuột Như bạn thấy, "quy định hàm xử lý tình onMouseDown thể oval1" nghĩa viết định nghĩa hàm cụ thể gán định nghĩa dó cho hàm onMouseDown oval1 Trước phép gán vậy, hàm onMouseDown oval1 chưa có nội dung Sau phép gán, hàm onMouseDown oval1 có nhiệm vụ cộng thêm cho thuộc tính _xscale oval1 Thử chạy chương trình bấm chuột nhiều lần vào sân khấu, bạn thấy hình ô-van ta phình theo phương ngang thuộc tính _xscale tăng dần lần bấm chuột Bạn để ý, ta viết this._xscale để rõ thuộc tính _xscale thể xét Nếu bạn viết _xscale, Flash hiểu thuộc tính _xscale sân khấu ta viết chương trình cho khung thời tuyến Khi đó, lần bấm chuột, sân khấu (cùng nội dung nó) phình từ điểm mốc góc trên, bên trái (gốc tọa độ sân khấu) Bạn viết thêm vài câu lệnh sau:
attachMovie("Oval", "oval2", 2); oval2._x = 200;
oval2._y = 150;
oval2.onMouseDown = oval1.onMouseDown;
Đoạn mã vừa thêm tạo thể nhân vật Oval, đặt tên oval2, nằm oval1 (độ cao 2) Câu lệnh cuối gán hàm onMouseDown oval1 cho hàm onMouseDown oval2 Chạy lại chương trình bấm chuột nhiều lần, bạn thấy hai hình ơ-van phình Điều nghĩa muốn hai thể có hành vi nhau, bạn không cần lặp lại định nghĩa hàm xử lý tình cho thể thứ hai, cần cho hai thể dùng chung hàm xử lý tình Chú ý chép thể hiện, bạn thu thể với thuộc tính giống hệt gốc hành vi thể khơng chép Bạn kiểm tra điều cách viết thêm:
oval1.duplicateMovieClip("oval3", 3); oval3._y += 100;
(53)trong đó, ta gọi hàm duplicateMovieClip oval1 để tạo oval1, lấy tên oval3, có độ cao (nghĩa nằm oval2) Câu lệnh cuối cho phép oval3 dùng chung hàm onMouseDown với oval1 Thử chạy chương trình, bạn thấy ba hình ô-van (oval1, oval2, oval3) phình bấm chuột (hình 1) Trở lại với đoạn mã xét, bạn ghi thêm dấu // trước câu lệnh cuối (để vơ hiệu hóa câu lệnh đó) Chạy lại lần bấm chuột nhiều lần, bạn thấy oval3 không thay đổi (hình 2) Điều chứng tỏ việc chép thể không bao gồm hành vi thể
Trong bảng Actions - Frame, bạn bấm nút Replace để mở hộp thoại Replace Trong ô Find what, bạn gõ onMouseDown Trong ô Replace with, bạn gõ onMouseUp (hình 3) Bấm Replace All, bạn thấy tất tên hàm onMouseDown chương trình ta thay bằng onMouseUp Thử chạy chương trình, bạn thấy hình ơ-van chưa phình nhấn phím chuột, phình bạn bng phím chuột
(54)Bài 24: Tạo nút bấm
Khi thử gán hàm xử lý tình onPress cho thể tạo lúc chạy chương trình, có lẽ bạn thấy hàm onPress thú vị hàm onMouseDown Hàm onPress gọi người dùng bấm trúng thể Chắc điều khiến bạn nghĩ đến việc tạo nút bấm chương trình Quả thực, ta vẽ hình để làm nút bấm Muốn chương trình làm người dùng bấm nút, cần định nghĩa hàm onPress thích hợp
Bạn mở tập tin FLA cửa sổ Flash để thực ý định nêu Trước hết, cần tạo nhân vật đóng vai nút bấm Bạn ấn Ctrl+F8 (hoặc chọn Insert > New Symbol) Khi hộp thoại Create New Symbol ra, bạn gõ Button để đặt tên cho nhân vật Bấm nút Advanced, bạn thấy hộp thoại mở rộng, bày quy định bổ sung (hình 1) Trong phần Linkage, bạn bật ô duyệt Export for ActionScript Chắc bạn nhớ, nhờ quy định này, Flash đưa nhân vật xét vào tập tin SWF nhân vật không diện sân khấu lúc biên dịch Tuy ta định tạo nút bấm, bạn đừng chọn Button phần Behavior lựa chọn nhằm tạo nút bấm theo cách cũ, tương thích với phiên trước Flash Bạn giữ nguyên lựa chọn Movie clip
(55)Bạn ấn Ctrl+F3 để mở bảng Properties Trong bảng Properties, bạn chọn Static text (khung chữ tĩnh) ô Text Type , điều chỉnh cỡ chữ ô Font Size Bạn bấm vào đâu đó bên ngồi khung chữ để tỏ ý kết thúc việc ghi chữ, gõ phím V (hoặc chọn Selection Tool ) để lấy công cụ chọn, kéo dịng chữ Start, đặt lên hình khung xanh cho cân xứng Bạn gõ phím mũi tên cần tinh chỉnh vị trí dịng chữ Start Bạn bấm vào Scene1 để kết thúc việc tạo hình cho nhân vật Button Muốn biết nhân vật Button tạo thư viện hay chưa, bạn gõ phím F11 để mở xem bảng Library Bạn gõ phím F9 để mở bảng Actions - Frame viết chương trình (cho khung 1) sau:
attachMovie("Button", "button1", 1); button1._x = 200;
button1._y = 200;
button1.onPress = function() { trace("Bạn bấm nút."); }
(56)Bài 25: Nút bấm khởi động
Bạn thấy cách thức tạo nút bấm đơn giản: cần định nghĩa hàm xử lý tình onPress nhân vật dùng làm nút bấm Muốn cho nút bấm "chuyên nghiệp" hơn, bạn tạo ba khung chốt liên tiếp thời tuyến nút bấm, đặt tên _up, _over, _down Đó tên bắt buộc theo quy ước Flash, bạn đừng đặt tên khác (chú ý đừng viết thiếu dấu gạch chân _) Quan sát thời tuyến nút bấm, bạn thấy khung đặt tên có gắn cờ hiệu màu đỏ để phân biệt với khung khơng có tên
Hình ảnh khung _up diện mạo nút bấm trạng thái bình thường Khi bạn trỏ vào nút bấm, Flash hiển thị hình ảnh khung _over nút bấm Khi bạn bấm nút, Flash chuyển qua khung _down nút bấm Ở khung _up, _over _down, ta phải viết câu lệnh stop(); để lệnh ngừng, ngăn không cho hiển thị khung Nếu không làm vậy, khung _up, _over _down tự động hiển thị liên tiếp, lặp lặp lại vào lúc chạy, khiến bạn thấy nút bấm nhấp nháy liên tục Ta dùng nút bấm Start có làm nút khởi động trị chơi "bắt biển" trước Nhờ nút khởi động Start, người chơi chủ động bắt đầu trị chơi họ sẵn sàng (hình 1) Khi người chơi bị cá bắt được, trị chơi cần kết thúc với trạng thái tĩnh Muốn chơi tiếp, người chơi lại bấm nút Start Nhờ vậy, người chơi kịp "hoàn hồn" để xem điểm số mà đạt
Nếu mở tập tin chứa nút bấm Start, bạn đóng tập tin Bạn mở lại tập tin FLA trò chơi "bắt biển" ấn Ctrl+Shift+O (hoặc chọn File > Import > Open External Library) Trong hộp thoại Open as Library vừa ra, bạn tìm tập tin FLA chứa nút bấm Start bấm kép vào Thao tác mở cửa sổ Library tập tin chọn, có nút bấm Start cần dùng Trong thời tuyến chính, bạn chọn khung lớp Layer mở bảng Actions - Frame (gõ phím F9) Bạn viết thêm sau vào bên đoạn mã có:
play = false;
(57)button1._y = 10;
button1.onPress = function() { play = true;
star.score = 0; }
Để tạo nút bấm Start (nhân vật Button) sân khấu, bạn dùng hàm attachMovie biết quy định tọa độ thích hợp cho nút bấm Biến play đóng vai trị "cờ hiệu", quy định trạng thái trò chơi Lúc đầu, ta gán trị false cho biến play Trong hàm onPress nút Start (hàm gọi bấm nút Start), ta gán trị true cho biến play cho điểm số trở lại trị Điểm số lưu giữ biến star.score, tức biến score bên biển có tên star Tiếp theo, bạn cần chỉnh sửa hành vi biển cá cho chúng "án binh bất động" biến play có trị false Bạn bấm vào sân khấu, bấm vào biển, quan sát chương trình bảng Actions - Movie Clip viết thêm vào hàm onClipEvent(mouseDown) sau:
onClipEvent(mouseDown) {
if(!_root.play) return;
if(hitTest(_root._xmouse, _root._ymouse, true)) {
Khi biến play thời tuyến (biến _root.play) có trị false, biểu thức !_root.play có trị true, hàm onClipEvent(mouseDown) kết thúc ngay, khơng làm Nghĩa biến play có trị false, biển khơng "nhúc nhích" chi hết dù bạn bấm trúng Bạn bấm vào cá để chuyển qua chương trình chỉnh sửa hàm onClipEvent(enterFrame) sau:
onClipEvent(enterFrame) {
if(!_root.play) return;
caught = false;
if(_x + step < _root._xmouse)
else if(caught == true) { //trace("Bắt nhé!"); //_root.star.score = 0; _root.play = false;
step = 5; }
}
(58)(59)Bài 26: Thao tác dãy
Trong trò chơi "bắt biển" thực hiện, bạn có hai nhân vật (sao biển cá nóc) bạn gọi tên chúng (star fish) cần "liên hệ công tác" Thử hình dung trị chơi có nhiều thể nhiều nhân vật khác nhau, không ngừng sinh đi, bạn thấy cách thức quản lý "thủ cơng" thể trị chơi "bắt biển" không phù hợp Trong trường hợp vậy, số lượng thể biến động lúc chơi, bạn biết trước vào lúc lập trình
Để chuẩn bị cho việc lập trình trò chơi phức tạp hơn, bạn cần biết đến khái niệm dãy (array) Nhờ đưa thể vào dãy, bạn không cần đặt tên riêng cho thể Lúc đó, thể "xếp hàng" nhớ máy tính, thể xác định tên dãy kèm theo chỉ số (index), cho biết vị trí dãy Xin nói ngay, xếp hàng nhớ khơng có nghĩa xếp hàng sân khấu Bạn đừng nhầm nha Bạn mở tập tin FLA mới, gõ phím F9 để mở bảng Actions - Frame ứng với khung gõ câu lệnh tạo dãy sau: arr = new Array(); Với câu lệnh vậy, ta tạo dãy có tên arr Người ta nói arr biến trỏ đến dãy Nói cho phức tạp, câu lệnh vừa nêu tạo đối tượng (object) thuộc lớp (class) Array arr biến trỏ đến đối tượng Bạn ghi tiếp hai câu lệnh sau để đặt trị số vào vị trí thứ dãy hiển thị phần tử thứ bảng Output:
arr = new Array();
arr[0] = 0; trace(arr[0]);
Bạn để ý, gọi tên phần tử dãy, ta ghi tên dãy, kèm theo số phần tử đặt cặp dấu ngoặc vuông Chỉ số phần tử dãy 0, khơng phải Thử chạy chương trình, bạn thấy phần tử thứ dãy arr (trị số 0) xuất bảng Output Bạn viết thêm câu lệnh để đặt trị số 10 vào vị trí thứ hai dãy (ứng với số 1):
arr = new Array(); arr[0] = 0;
arr[1] = 10;
trace(arr);
Ngoài ra, bạn sửa câu lệnh trace(arr[0]); thành trace(arr); để in bảng Output toàn dãy arr, thay in phần tử Với câu lệnh trace(arr), Flash tự biết phải ghi phần tử dãy phân cách dấu phẩy Trong trường hợp xét, dãy có hai phần tử, bạn thấy kết bảng Output sau: 0,10 Giả sử bạn cần đặt trị số 20 vào vị trí thứ ba, trị số 30 vào vị trí thứ tư, Bạn dùng vịng lặp sau cho nhanh:
arr = new Array(); arr[0] = 0;
arr[1] = 10;
for(i = 2; i < 10; i++) arr[i] = i*10;
trace(arr);
trace("arr.length:" + arr.length);
(60)Thử chạy chương trình, bạn có kết bảng Output hình Chiều dài dãy 10, chiếm mười trị số (hình 2) Mười vị trí dãy ứng với số từ đến
Khi đặt trị số vào dãy, bạn không thiết phải theo thứ tự Bạn thử ghi thêm hai câu lệnh sau:
arr = new Array(); arr[0] = 0;
arr[1] = 10;
for(i = 2; i < 10; i++) arr[i] = i*10;
arr[14] = 200; arr[12] = 100;
trace(arr);
trace("arr.length:" + arr.length);
Hai câu lệnh vừa thêm "ngang nhiên" ghi trị số 200 vào vị trí ứng với số 14, "bất chợt" ghi trị số 100 vào vị trí ứng với số 12 Thử chạy chương trình, bạn thấy kết sau:
0,10,20,30,40,50,60,70,80,90,undefined,undefined,100,undefined,200 arr.length:15
(61)Bài 27: Hành vi dãy
Bạn làm quen với dãy biết cách đặt trị số vào dãy, tạo thành phần tử dãy Khi đặt trị số vào dãy, bạn vị trí dãy Dãy tự động dài theo nhu cầu bạn Thao tác dãy có lẽ khiến bạn hình dung dãy chẳng qua "ô chứa" xếp thành hàng nhớ máy tính Điều chưa đủ Dãy đối tượng có khả quản lý "ơ chứa" Dãy có hành vi (hàm) định Bạn yêu cầu dãy thực nhiều việc "ly kỳ"
Bạn mở lại tập tin FLA có đoạn mã thử nghiệm dãy khung Bạn xóa đoạn mã có, viết đoạn mã khác sau:
arr = new Array(); for(i = 0; i < 5; i++) { trace("Đưa vào: " + i); arr.push(i);
trace(arr); }
Đoạn mã tạo dãy mang tên arr, dùng vòng lặp for để "đẩy" trị số từ đến vào dãy Ta đẩy trị số vào dãy cách trao trị số cho hàm push dãy Nói khác đi, ta yêu cầu dãy "nhét" trị số vào "lòng" Trong trường hợp này, ta không quan tâm đến số phần tử dãy, cần nhớ luật lệ xếp hàng đơn giản: phần tử vào trước đứng trước, phần tử vào sau đứng sau Trong lần lặp, câu lệnh trace(arr); in bảng Output toàn nội dung dãy Nhờ vậy, chạy thử chương trình, bạn theo dõi diễn biến bên dãy, thấy dãy từ từ dài nào:
Đưa vào: 0
Đưa vào: 0,1
Đưa vào: 0,1,2 Đưa vào: 0,1,2,3 Đưa vào: 0,1,2,3,4
Dãy có hàm khác gọi pop, xem hàm ngược push Khi bạn gọi hàm pop dãy, phần tử đứng sau "bật" khỏi dãy cho bạn "hứng" Nghĩa hàm pop trả phần tử sau dãy, đồng thời loại khỏi dãy, làm cho chiều dài dãy giảm đơn vị Bạn viết thêm đoạn mã sau:
while(arr.length > 0) {
trace("Lấy ra: " + arr.pop()); trace(arr);
}
(62)Trong vòng lặp while vừa viết, câu lệnh trace("Lấy ra: " + arr.pop()); bạn sửa arr.pop() thành arr.shift() ấn Ctrl+Enter để chạy lại chương trình Bạn thấy hàm shift khác với hàm pop chỗ: làm cho phần tử đầu tiên, phần tử sau cùng, bật khỏi dãy Khi phần tử bị loại khỏi dãy, phần tử thứ hai tự động dịch lên, trở thành phần tử đầu tiên, phần tử thứ ba nối đuôi, trở thành phần tử thứ hai, Kết phần tử dãy xê dịch Tên gọi shift (xê dịch) xuất phát từ Tiếp tục "chơi đùa" với dãy, bạn viết thêm vòng lặp for sau:
for(i = 0; i < 5; i++) { trace("Đưa vào: " + i); arr.unshift(i);
trace(arr); }
Nghĩa sau lấy phần tử khỏi dãy, ta lại đưa trị số từ đến vào dãy, lần ta gọi hàm unshift dãy, không gọi hàm push Quan sát kết bảng Output, bạn hiểu ngay: hàm unshift luôn đưa phần tử vào vị trí dãy, khơng phải vị trí sau Phần tử chen vào vị trí đầu tiên, đẩy phần tử có sẵn sau Bạn thu dãy trị số ngược: 4,3,2,1,0
Hàm unshift hàm shift tạo nhiều xê dịch dãy nên tốn thời gian hàm push hàm pop Tuy vậy, có trường hợp mà việc thêm phần tử vào dãy vị trí nhu cầu thực
Dãy cịn có khả tự thứ tự Bạn viết thêm ba câu lệnh sau: trace("Sắp thứ tự:");
(63)trace(arr);
Để thứ tự dãy, bạn cần gọi hàm sort dãy Trước gọi hàm sort, nội dung dãy 4,3,2,1,0 Sau gọi hàm sort, nội dung dãy có thứ tự "nhỏ trước, lớn sau": 0,1,2,3,4 Đối với dãy chứa chuỗi, hàm sort dãy giúp bạn có thứ tự vần (alphabet order) dãy Bạn thử hình dung: ta cho người dùng chương trình nhập tên hát Chỉ cần lưu tên hát dãy gọi hàm sort dãy, bạn có danh sách hát thứ tự theo vần Bạn nên xóa hết đoạn mã có tự viết đoạn mã thử nghiệm khả thứ tự chuỗi theo vần hàm sort dãy
Bài 28: Vui đùa với dãy
Bạn biết đến khái niệm dãy (array) Ta tiếp tục "quậy" với dãy thêm chút nữa, chuẩn bị cho việc thực trị chơi có dùng đến dãy Điều cần thiết giống bạn vui đùa với bóng trước đá bóng thực
Bạn mở tập tin Flash viết đoạn mã sau bảng Actions - Frame: arr = ["mãng cầu", "dừa", "đu đủ", "xoài"];
trace(arr);
subarr = arr.slice(0,1); trace(subarr); subarr = arr.slice(2,3); trace(subarr); subarr = arr.slice(2); trace(subarr);
Đoạn mã vừa nêu giúp bạn biết cách để tạo dãy với phần tử sẵn làm quen với hàm slice dãy Phần tử "mãng cầu" Các phần tử "dừa", "đu đủ", "xoài" (tức "cầu vừa đủ xài") Sau tạo dãy arr, ta dùng câu lệnh trace(arr); để in dãy arr bảng Output, xem thử dãy arr có chứa thứ mà ta đặt vào hay chưa Hàm slice giúp bạn cắt lấy một phần dãy, tạo dãy Dãy bị cắt thực cịn ngun, khơng bị tí tẹo "Dãy con" thu chứa đựng số phần tử "dãy gốc" Nói rõ hơn, dãy dùng chung số phần tử với dãy gốc Khi viết arr.slice(0, 1), bạn "xắn" vào dãy arr, "trước mặt" phần tử thứ vị trí "trước mặt" phần tử thứ hai vị trí Lát cắt lấy chứa phần tử thứ nhất, tức "mãng cầu" Ta đặt tên cho dãy thu từ hàm slice subarr dùng hàm trace kiểm tra nội dung dãy subarr Khi viết arr.slice(2, 3), ta có lát cắt từ vị trí (phần tử "đu đủ") đến vị trí (phần tử "xoài") Dãy thu gồm phần tử "đu đủ", khơng có phần tử "xồi" Nói chung, bạn cần nhớ phần tử ứng với đối mục thứ hàm slice có mặt kết hàm slice phần tử ứng với đối mục thứ hai khơng Khi viết arr.slice(2), bạn gọi hàm slice cung cấp đối mục Flash tự hiểu bạn muốn cắt từ vị trí (phần tử "đu đủ") đến hết dãy arr Dãy thu gồm có "đu đủ" "xồi" Chạy thử chương trình nhìn vào bảng Output, bạn thấy rõ nội dung dãy gốc dãy hàm slice tạo ra:
mãng cầu,dừa,đu đủ,xoài mãng cầu
đu đủ đu đủ,xoài
Bạn viết thêm câu lệnh gọi hàm slice "ly kỳ" hơn: subarr = arr.slice(); trace(subarr);
subarr = arr.slice(-2); trace(subarr); subarr = arr.slice(-3,-2); trace(subarr); subarr = arr.slice(-3,3); trace(subarr);
(64)tính từ dãy, khơng phải tính từ đầu dãy bình thường Vị trí cuối dãy có số -1, vị trí áp cuối có số -2, Khi viết arr.slice(-2), bạn thu dãy arr, từ với vị trí áp cuối ("đu đủ") đến hết dãy arr Khi viết arr.slice(-3, -2), bạn thu dãy từ vị trí -3 ("dừa") đến vị trí -2 ("đu đủ") Dãy có "dừa", khơng có "đu đủ" Bạn dùng đồng thời số âm số dương gọi hàm slice Khi bạn viết arr.slice(-3, 3), Flash dư sức hiểu dãy lấy từ vị trí -3 ("dừa") đến vị trí ("xồi") Nhìn vào kết chương trình (hình 1), bạn kiểm tra xem Flash "suy nghĩ" có giống hay khơng
Cần nhắc lại hàm slice không làm "sứt mẻ" dãy arr Ở cuối đoạn mã có, bạn thử ghép dãy arr với dãy subarr hàm có tên concat in kết quả: trace(arr.concat(subarr)); Nhờ hàm concat arr, bạn thu "dãy gộc" dài arr, bao gồm phần tử arr subarr Bạn thử xem Nếu muốn "xắn" vào dãy arr làm dãy arr lát cắt, bạn phải dùng hàm khác, gọi splice Bạn xóa đoạn mã có viết đoạn mã sau:
arr = ["mãng cầu", "dừa", "đu đủ", "xoài"]; trace(arr);
arr.splice(1,1); trace(arr); arr.splice(1,0,"cam"); trace(arr); arr.splice(0,2,"bưởi"); trace(arr); arr.splice(-1,1); trace(arr);
(65)Bài 29: Dãy nhiều chiều
Bạn thấy ta đặt số chuỗi vào dãy Phần tử dãy thứ Nếu phần tử dãy lại dãy khác, bạn có dãy hai chiều (2D array) Để làm quen với dãy hai chiều, bạn mở tập tin Flash gõ đoạn mã sau bảng Actions - Frame (ứng với khung 1):
arr = new Array(); for(i = 0; i < 3; i++) {
arr[i] = ["mãng cầu", "dừa", "đu đủ", "xoài"]; }
Trong đoạn mã trên, ta tạo dãy mang tên arr, dùng vòng lặp for để tạo phần tử dãy arr Nhìn kỹ, bạn thấy với cách dùng vịng lặp vậy, dãy arr có ba phần tử (chiều dài dãy 3) phần tử lại dãy khác, chứa phần tử ("mãng cầu", "dừa", "đu đủ", "xoài") Để in bảng Output phần tử dãy arr, bạn viết thêm đoạn mã sau:
for(i = 0; i < arr.length; i++) { for(j = 0; j < arr[i].length; j++) trace(arr[i][j]);
}
Trong đó, ta dùng hai vịng lặp for Vịng lặp for bên ngồi for(i = 0; i < arr.length; i++) giúp bạn xem xét phần tử arr[i] dãy arr Bạn ý: arr.length chiều dài dãy arr Trong trường hợp xét, arr.length có trị Tuy nhiên, bạn nên viết arr.length, đừng viết Nhờ vậy, muốn sửa đổi chiều dài dãy, chẳng hạn sửa thành 5, bạn cần sửa vòng lặp for for(i = 0; i < 3; i++), không cần sửa thêm chỗ khác Vì phần tử arr[i] lại dãy, vòng lặp for bên for(j = 0; j < arr[i].length; j++) giúp bạn in phần tử dãy Để phần tử thứ j dãy arr[i], bạn viết cách tự nhiên: arr[i][j] Ấn Ctrl+Enter để chạy chương trình, bạn thấy tên bốn loại trái lặp lại ba lần Để "dãy con" arr[i] in hàng, cho dễ phân biệt với "dãy cha" arr, bạn sửa lại đoạn mã in dãy arr sau:
for(i = 0; i < arr.length; i++) { trace(arr[i].join("|"));
(66)Thay in phần tử dãy arr[i], ta gọi hàm join dãy arr[i] để nối phần tử dãy arr[i] thành chuỗi Dấu vạch đứng dùng làm "mối nối" hai phần tử Nhờ có hàm join, bạn thu kết hình 1, cho thấy rõ ràng dãy arr có ba phần tử phần tử lại dãy Kết in giúp bạn hình dung dãy hai chiều bảng, số i "dãy cha" số hàng số j "dãy con" số cột
Trong ví dụ vừa xét, dãy giống hệt Để thấy dãy khác nhau, bạn xóa đoạn mã có, viết đoạn mã thử nghiệm khác sau:
arr = new Array(); for(i = 0; i < 5; i++) { arr[i] = new Array(); for(j = 0; j < 6; j++) { arr[i][j] = "[" + i + j + "]"; }
}
for(i = 0; i < arr.length; i++) { trace(arr[i].join(" ");
}
(67)Trong ví dụ vừa xét, dãy arr[i] có chiều dài (6) Thực ra, dãy hồn tồn có chiều dài khác Nếu phần tử dãy arr[i][j] lại dãy, bạn có dãy ba chiều (3D array) Để diễn đạt phần tử "dãy cháu" arr[i][j], bạn phải dùng ba số, chẳng hạn: arr[i][j][k] Cứ thế, bạn có dãy nhiều chiều (khiếp!) Bạn yên tâm, dãy hai chiều đủ sức đáp ứng phần lớn nhu cầu thực tế
Bài 30: Chỉ mục dãy
Nếu vui đùa với dãy qua trước có kinh nghiệm định với ngơn ngữ lập trình khác, bạn nhận khái niệm dãy Flash (nói cụ thể hơn, ngơn ngữ ActionScript) có nhiều nét thú vị, khác lạ Ta tìm hiểu thêm nét khác lạ nữa: bên cạnh cách thức truy xuất phần tử dãy số, bạn truy xuất phần tử dãy chuỗi gán cho phần tử Cụ thể, bạn xóa nội dung có bảng Actions - Frame cửa sổ Flash gõ đoạn mã thử nghiệm sau:
arr = new Array();
arr["custard apple"] = "mãng cầu"; arr["coconut"] = "dừa";
arr["papaya"] = "đu đủ"; arr["mango"] = "xoài"; trace(arr["custard apple"]); trace(arr["coconut"]); trace(arr["papaya"]); trace(arr["mango"]);
(68)Ta gọi chuỗi tương ứng với phần tử dãy mục phần tử (thuật ngữ số khơng thích hợp trường hợp này) Nếu tạo phần tử dãy mục tương ứng, bạn phải truy xuất phần tử mục, dùng số Bạn hiểu điều thử truy xuất phần tử dãy có số:
arr = new Array();
arr["custard apple"] = "mãng cầu"; arr["coconut"] = "dừa";
arr["papaya"] = "đu đủ"; arr["mango"] = "xoài"; trace(arr["custard apple"]); trace(arr["coconut"]); trace(arr["papaya"]); trace(arr["mango"]);
trace(" -"); trace(arr[0]); trace(arr[1]); trace(arr[2]); trace(arr[3]);
Với câu lệnh viết thêm, bạn thu kết sau bảng Output, cho thấy rõ dùng số thay cho mục:
(69)Việc sử dụng mục để truy xuất phần tử dãy thường xảy dãy thể Để khảo sát dãy thể hiện, bạn mở tập tin Flash tạo bốn thể hình vng có màu khác Cụ thể, bạn ấn Ctrl+F8 để mở hộp thoại Create New Symbol (hình 2), gõ tên Tile0, chọn Export for ActionScript (điều cần thiết ta tạo thể nhân vật Tile0 câu lệnh, cách kéo nhân vật từ bảng Library vào sân khấu)
(70)Để có nhân vật Tile1 hình vng giống hệt Tile0, khác màu tơ, bạn chép Tile0 cho nhanh Bạn gõ phím F11 để mở bảng Library (nếu bảng Library chưa mở), bấm phải vào mục Tile0 bảng Library, chọn Duplicate Hộp thoại Duplicate vừa (hình 4), bạn gõ Tile1 để đặt tên cho sao, chọn Export for ActionScript bấm OK
(71)vẽ Bạn chọn mục Scene1 để kết thúc việc chỉnh sửa nhân vật Tile1, trở với sân khấu Theo cách tương tự, bạn tạo hai hình vng (nhân vật Tile2 Tile3) với màu tô khác Bạn mở bảng Actions - Frame (ứng với khung 1), gõ đoạn mã sau để tạo bốn thể bốn nhân vật có (Tile0, Tile1, Tile2, Tile3) xếp chúng thành hàng ngang:
for(i = 0; i < 4; i++) {
attachMovie("Tile" + i, "tile" + i, i); this["tile" + i]._x = 120 * i;
this["tile" + i]._y = 20; }
Ấn Ctrl+Enter để chạy thử, bạn có kết hình
Đoạn mã vừa viết tạo thể mang tên tile0, tile1, tile2, tile3 từ nhân vật Tile0, Tile1, Tile2, Tile3 Ta quy định vị trí thể cách gán trị số thích hợp cho thuộc tính _x _y thể Hai câu lệnh vòng lặp nhằm quy định vị trí cho thể tương đương với câu lệnh sau:
this["tile0"]._x = 0; this["tile0"]._y = 20; this["tile1"]._x = 120; this["tile1"]._y = 20; this["tile2"]._x = 240; this["tile2"]._y = 20; this["tile3"]._x = 360; this["tile3"]._y = 20;
Như bạn thấy, ta truy xuất thể tile0 cách viết this["tile0"] Từ chốt this dãy tạo sẵn, chứa thể tạo thời tuyến Trong dãy đó, mục thể tên thể Cách truy xuất thể nêu thích hợp cho vòng lặp, rất thuận tiện bạn phải điều khiển nhiều thể sân khấu
Bài 31: Trị chơi "lật hình"
(72)khiển nhiều thể sân khấu Ta xem xét trị chơi "lật hình" quen thuộc, người chơi bấm chuột để lật hai hình liên tiếp, hai hình giống nhau, chúng khơng bị úp xuống trở lại Trị chơi kết thúc hình lật lên Thành tích người chơi thể số lần bấm chuột (số lần bấm chuột tốt) thời gian hồn thành trò chơi
Ta việc đơn giản: xếp hình thành hàng cột Bạn thử hình dung ta có 16 hình, xếp thành hàng, cột, có cặp hình giống Trong trước, bạn tạo hình vng khác (có màu tơ khác nhau) Ta cần có thêm hình vng khác thư viện Library để có đủ hình khác Trước mắt, ta tạo hình vng khác cách tơ màu khác Sau này, chương trình chạy tốt, bạn vẽ thêm hình vui mắt vào hình vng Library lấy hình từ mạng Bạn mở lại tập tin FLA tạo trước, gõ phím F11 để mở bảng Library Trong bảng Library, bạn bấm-phải vào mục Tile0, chọn Duplicate Hộp thoại Duplicate ra, bạn gõ tên Tile4, chọn Export for ActionScript bấm OK Thao tác chép nhân vật Tile0, tạo nhân vật Tile4 Để nhân vật Tile4 có màu tơ khác với Tile0, bạn lại bấm-phải vào mục Tile0 bảng Library, chọn Edit để chuyển qua chế độ chỉnh sửa nhân vật Bạn chọn màu tô khác ô Fill Color , chọn công cụ tô bấm vào hình vng Tile4 miền vẽ Để có nhân vật Tile5 có màu tơ khác, bạn lặp lại thao tác để chép nhân vật Tile0 thành nhân vật Tile5 chọn màu tô cho Tile5 khác với màu tô dùng Cứ thế, bạn tạo thêm nhân vật Tile6 Tile7 để có thảy nhân vật hình vng (từ Tile0 đến Tile7) với màu tơ khác Gõ phím F9 để mở bảng Actions - Frame, bạn xóa đoạn mã viết từ trước, viết đoạn mã khác sau:
tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile" + n%8, "tile" + i + j, n); n++;
tiles[i][j] = this["tile" + i + j]; tiles[i][j]._x = 120 * j; tiles[i][j]._y = 120 * i; }
}
(73)Vịng lặp ngồi có số i chạy từ đến Trong lần lặp theo số i, ta tạo phần tử dãy tiles: tiles[i] = new Array(); Nhờ vậy, dãy tiles có phần tử, phần tử lại dãy khác, tạm gọi dãy Vịng lặp có số j chạy từ đến 3, có nhiệm vụ đưa phần tử vào dãy vừa tạo (mỗi dãy có phần tử) Trong lần lặp theo số j, ta lại tạo thể từ nhân vật Library Bạn ý cách đặt tên cho thể Khi biến i có trị số 0, biến j có trị số 0, thể tạo có tên "tile" + i + j, tức tile00 Tương tự, i 0, j 1, thể có tên tile01, Do câu lệnh tiles[i][j] = this["tile" + i + j]; thể tile00 đưa vào dãy tiles, trở thành phần tử tiles[0][0] Tương tự, thể tiles01 trở thành phần tử tiles[0][1] dãy tiles, Hai câu lệnh quy định vị trí cho thể hiện:
tiles[i][j]._x = 120 * j; tiles[i][j]._y = 120 * i;
tương đương với nhiều câu lệnh sau: tiles[0][0]._x = 0;
tiles[0][0]._y = 0; tiles[0][1]._x = 120; tiles[0][1]._y = 0; tiles[0][2]._x = 240; tiles[0][2]._y = 0;
tiles[1][0]._x = 0; tiles[1][0]._y = 120; tiles[1][1]._x = 120; tiles[1][1]._y = 120; tiles[1][2]._x = 240; tiles[1][2]._y = 120;
(74)(75)Bài 32: Xáo hình ngẫu nhiên
Bạn viết chương trình để xếp hình vào 16 vị trí (4 hàng, cột), hình xuất hai lần Để mảng hình ta khơng nằm sát biên biên trái sân khấu, bạn nên chỉnh sửa chút việc quy định vị trí hình chương trình bảng Actions - Frame: tiles = new Array();
n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile" + n%8, "tile" + i + j, n); n++;
tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 20 + 120 * j; // Xê dịch 20 pi-xôn tiles[i][j]._y = 20 + 120 * i; // Xê dịch 20 pi-xôn }
}
Viết thêm nghĩa bạn chừa lề lề trái khoảng 20 pi-xôn (điểm ảnh) Do khoảng cách hai hình 20 pi-xơn, hình có chiều rộng chiều cao 100 pi-xơn, sân khấu ta cần có kích thước 500 pi-xơn x 500 pi-xôn Bạn ấn Ctrl +F3 để mở bảng Properties Trong bảng Properties, bạn bấm nút Size Hộp thoại Document Properties xuất hiện, giúp bạn quy định chiều rộng chiều cao sân khấu (hình 1) Xong, bạn bấm OK, ấn Ctrl+F3 để dẹp bảng Properties
(76)vào văn bản, bạn đóng hộp thoại Symbol, chọn biểu tượng (kéo chuột ngang qua biểu tượng), ấn Ctrl+C để chép
(77)Bạn chuyển qua cửa sổ Word, chép biểu tượng khác, trở cửa sổ Flash, bấm kép vào biểu tượng nhân vật Tile1 danh sách nhân vật bảng Library, thực lại thao tác tương tự nhân vật Tile1 Cứ thế, bạn chỉnh sửa nhân vật để chúng có diện mạo định Xong xi, bạn ấn Ctrl+Enter Kết tương tự hình
(78)hình đó, hốn đổi vị trí chúng lặp lại thao tác nhiều lần Nếu lặp lại thao tác hốn đổi vị trí hai hình chọn ngẫu nhiên chừng 200 lần chẳng hạn, chắn bạn thu kết xếp thực ngẫu nhiên Để thực ý định vừa nêu, bạn viết thêm vào chương trình có bảng Actions - Frame sau:
tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile" + n%8, "tile" + i + j, n); n++;
tiles[i][j] = this["tile" + i + j]; tiles[i][j]._x = 20 + 120 * j; tiles[i][j]._y = 20 + 120 * i; }
}
shuffleTiles();
function getRandom(min, max) {
return Math.floor(Math.random()*(max - min) + min); }
function shuffleTiles() { for(i = 0; i < 200; i++) { r1 = getRandom(0, 3); c1 = getRandom(0, 3); r2 = getRandom(0, 3); c2 = getRandom(0, 3); tx = tiles[r1][c1]._x; ty = tiles[r1][c1]._y;
tiles[r1][c1]._x = tiles[r2][c2]._x; tiles[r1][c1]._y = tiles[r2][c2]._y; tiles[r2][c2]._x = tx;
tiles[r2][c2]._y = ty; }
}
(79)(80)Bài 33: Úp hình lật hình
Bạn viết hàm xáo hình ngẫu nhiên cho trị chơi "lật hình", bạn hốn đổi nhiều lần vị trí hai hình chọn ngẫu nhiên: tiles[r1][c1] tiles[r2][c2] Điều nghĩa hình hàng r1, cột c1 lấy vị trí hình hàng r2, cột c2 ngược lại Nói khác đi, sau lần hoán đổi, phần tử dãy tiles[r1][c1] trỏ đến hình hàng r2, cột c2, phần tử dãy tiles[r2][c2] trỏ đến hình hàng r1, cột c1 Như vậy, sau nhiều lần hoán đổi, rốt phần tử tiles[r][c] khơng cịn trỏ đến hình hàng r, cột c Ta phần tử tiles[r][c] nằm hàng nào, cột khơng điều khiển trị chơi nữa!
Để ngăn chặn tình trạng hồn tồn hỗn loạn vậy, hốn đổi vị trí hình tiles[r1][c1] tiles[r2][c2], bạn cần gán hình vào phần tử dãy phù hợp, làm cho tiles[r1][c1] trỏ đến hình hàng r1, cột c1 tiles[r2][c2] trỏ đến hình hàng r2, cột c2 Cụ thể, bạn cần viết thêm vào hàm shuffleTiles() chương trình ta sau:
function shuffleTiles() { for(i = 0; i < 200; i++) { r1 = getRandom(0, 3); c1 = getRandom(0, 3); r2 = getRandom(0, 3); c2 = getRandom(0, 3); tx = tiles[r1][c1]._x; ty = tiles[r1][c1]._y;
tiles[r1][c1]._x = tiles[r2][c2]._x; tiles[r1][c1]._y = tiles[r2][c2]._y; tiles[r2][c2]._x = tx;
tiles[r2][c2]._y = ty; t = tiles[r1][c1];
tiles[r1][c1] = tiles[r2][c2]; tiles[r2][c2] = t;
} }
Đoạn mã vừa bổ sung thực việc hoán đổi hai phần tử dãy tiles[r1][c1] tiles[r2][c2] Để hoán đổi, ta thực giải thuật quen thuộc: đặt biến t để lưu tạm tiles[r1][c1], gán trị tiles[r2][c2] cho tiles[r1][c1], cho tiles[r2][c2] lấy trị biến t Sau việc hoán đổi vậy, tiles[r1][c1] trỏ đến hình hàng r1, cột c1 (hình mới, trước nằm hàng r2, cột c2) tiles[r2][c2] trỏ đến hình hàng r2, cột c2 (hình mới, trước nằm hàng r1, cột c1) Bạn hoàn toàn yên tâm phần tử dãy tiles[r][c] ln trỏ đến hình hàng r, cột c
(81)hình giống "úp xuống" cách che chúng lại với hình khác, đóng vai "mặt sau" Khi người chơi bấm vào hình nào, ta cho hình "mặt sau" biến đi, để lộ hình "mặt trước"
Trước hết, cần tạo hình "mặt sau" Bạn gõ phím F11 để mở bảng Library, bấm-phải vào một nhân vật có danh sách nhân vật, Tile0 chẳng hạn, chọn Duplicate trình đơn vừa Thao tác nhằm chép nhân vật Tile0 Khi thấy hộp thoại Duplicate Symbol (hình 1), bạn gõ tên Back (mặt sau) chọn Export for ActionScript Nếu quên chọn Export for ActionScript, bạn tạo thể nhân vật Back vào lúc chạy chương trình. Xong, bạn bấm nút OK Trong danh sách nhân vật bảng Library có thêm nhân vật mang tên Back, có "mặt mũi" giống hệt nhân vật Tile0
Bạn bấm kép vào "mặt mũi" nhân vật Back để chuyển qua chế độ chỉnh sửa nhân vật Bạn xóa biểu tượng "mặt cười" (bấm trúng biểu tượng, gõ phím Delete) Bạn nên chọn màu tô khác cho "mặt sau", tức tô màu khác cho hình vng nằm lớp Layer Nếu lớp Layer bị khóa, bạn cần bấm vào ổ khóa lớp Layer để "mở khóa" (ổ khóa biến mất) Bạn chọn màu tơ , chọn cơng cụ tơ bấm vào hình vng để tơ Bạn bấm vào Scene để trở với sân khấu, viết thêm vào chương trình sau:
tiles = new Array(); backs = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); backs[i] = new Array(); for(j = 0; j < 4; j++) {
(82)n++;
tiles[i][j] = this["tile" + i + j]; tiles[i][j]._x = 20 + 120 * j; tiles[i][j]._y = 20 + 120 * i; backs[i][j] = this["back" + i + j]; backs[i][j]._x = 20 + 120 * j; backs[i][j]._y = 20 + 120 * i; }
}
Ta tạo 16 thể nhân vật Back để che đậy cho 16 hình "mặt trước" Câu lệnh backs = new Array(); tạo dãy mang tên backs để quản lý hình "mặt sau" Cũng dãy tiles có, phần tử dãy backs lại dãy, thể câu lệnh backs[i] = new Array(); vòng lặp Dãy backs[i] dùng để chứa hình "mặt sau" hàng i Câu lệnh attachMovie("Back", "back" + i + j, n + 100); tạo thể nhân vật Back, dùng cho hàng i, cột j Thể gán cho phần tử dãy backs[i][j] câu lệnh backs[i][j] = this["back" + i + j]; giống ta làm với dãy tiles Trong câu lệnh tạo thể nhân vật Back, ta quy định độ cao (cũng gọi "độ sâu") n + 100 Điều bảo đảm cho hình "mặt sau" nằm cao hình "mặt trước" Nhờ vậy, hình "mặt sau" che khuất hình "mặt trước" Với hai câu lệnh: backs[i][j]._x = 20 + 120 * j;
backs[i][j]._y = 20 + 120 * i;
(83)Để hình "mặt sau" biến người chơi bấm chuột trúng nó, bạn viết thêm hàm xử lý tình bấm chuột cuối chương trình sau:
function getRandom(min, max) {
}
function shuffleTiles() {
}
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse)) { backs[i][j]._visible = false;
} } } }
(84)nào dãy tiles, ta gán trị false cho thuộc tính _visible hình "mặt sau" vị trí tương ứng, làm cho hình "mặt sau" biến mất, xem hình "mặt trước" "lật lên" Bạn chạy thử chương trình "lật" vài hình xem (hình 3)
Bài 34: Những lỗi "nhỏ nhặt"
Khi chạy chương trình viết, thử bấm chuột để lật vài hình, bạn thấy có tượng lạ: bấm phát lật hai hình lân cận! Đó "tiện lợi" khơng mong đợi Điều ngày nghĩa hình "được thêm" cảm thấy cú bấm chuột trúng vào nó!
(85)Để khắc phục lỗi xét, ta sửa chương trình thay sửa khung bao bên nhân vật Bạn bấm vào Scene để thoát khỏi chế độ chỉnh sửa nhân vật, trở lại bảng Actions - Frame viết thêm vào câu lệnh gọi hàm hitTest() sau:
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { backs[i][j]._visible = false;
} } } }
(86)Để tìm hiểu xem vậy, bạn ghi thêm hai câu lệnh theo dõi diễn biến bên hàm shuffleTiles() sau:
function shuffleTiles() { for(i = 0; i < 200; i++) { r1 = getRandom(0, 3); c1 = getRandom(0, 3); r2 = getRandom(0, 3); c2 = getRandom(0, 3);
trace("r1:" + r1 + ", c1:" + c1); trace("r2:" + r2 + ", c2:" + c2); tx = tiles[r1][c1]._x;
ty = tiles[r1][c1]._y;
Hai câu lệnh vừa thêm nhằm in bảng Output số ngẫu nhiên hàng cột hàm getRamdom() sinh Chạy lại chương trình, bạn thấy số ngẫu nhiên bảng Output đại khái sau:
(87)
r1:1, c1:2 r2:1, c2:0 r1:1, c1:1 r2:1, c2:2
Theo dõi số ngẫu nhiên hàm getRandom() sinh ra, bạn thấy khơng có số Dường khơng có lúc số xuất cách ngẫu nhiên Câu lệnh getRandom(0, 3); cho trị ngẫu nhiên tối đa Bạn sửa lại định nghĩa hàm getRandom() chút, không dùng hàm Math.floor() để làm tròn kết trả về:
function getRandom(min, max) {
//return Math.floor(Math.random()*(max - min) + min); return Math.random()*(max - min) + min;
}
Chạy chương trình quan sát bảng Output, bạn thấy có trị ngẫu nhiên lớn (ở dạng thập phân) khơng có trị Khi số hàng cột 2.5 chẳng hạn, Flash tự động xem Hàm Math.random() cho trị ngẫu nhiên từ đến gần 1, không cho trị ngẫu nhiên Để có trị ngẫu nhiên từ đến 3, ta viết getRandom(0, 4) thay cho getRandom(0, 3) Giải pháp tốt sửa chút định nghĩa hàm getRandom() để đối mục thứ hai (max) hàm tự động cộng thêm 1:
function getRandom(min, max) {
return Math.floor(Math.random()*(max + - min) + min); }
Chạy chương trình quan sát bảng Output, bạn thấy ta có số số ngẫu nhiên: r1:3, c1:2 r2:3, c2:3 r1:0, c1:1 r2:3, c2:2 r1:2, c1:1 r2:1, c2:2 r1:2, c1:3
Nhờ vậy, hàng thứ tư cột thứ tư thay đổi ngẫu nhiên, khơng cịn "bất khả xâm phạm" trước
Bài 35: Tìm hình giống nhau
(88)nguyên trạng thái Ta xem hai hình "hồn thành nhiệm vụ" Người chơi tiếp tục lật hình khác cố gắng ghi nhớ vị trí hình để lật liên tiếp hai hình giống Khi khơng cịn hình bị "úp", trị chơi kết thúc
Hiện tại, chương trình ta, hàm xử lý tình bấm chuột khơng kiểm tra cả, giữ nguyên trạng thái hình lật Để thực việc kiểm tra vừa nêu, hình cần có biến cho biết loại hình gì, đặt tên type Hình cần chứa biến gọi solved chẳng hạn, nhận trị true false biết "hoàn thành nhiệm vụ" hay chưa Ngoài ra, ta cần biến để ghi nhận lần bấm chuột xét lần thứ mấy, đặt tên count Phải có đủ thơng tin vậy, chương trình "suy xét" hành động thích hợp người dùng bấm chuột Biến type cần có trị sao? Nhìn lại phần đầu chương trình, bạn thấy ta dùng biểu thức n % để thu trị số từ đến (các nhân vật đánh số từ đến 7) Hai thể giống hai thể ứng với số thứ tự, nghĩa tạo từ nhân vật Ta gọi hai thể loại Bạn hiểu ngay: biến type cần có trị từ đến Ta cần lấy trị biểu thức n % để gán cho biến type hình xem xét vịng lặp phần đầu chương trình Bạn viết thêm vào phần đầu chương trình sau:
tiles = new Array(); backs = new Array(); n = 0;
type = 0; count = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); backs[i] = new Array(); for(j = 0; j < 4; j++) { type = n%8;
attachMovie("Tile" + type, "tile" + i + j, n); attachMovie("Back", "back" + i + j, n + 100); n++;
tiles[i][j] = this["tile" + i + j]; tiles[i][j]._x = 20 + 120 * j; tiles[i][j]._y = 20 + 120 * i; tiles[i][j].type = type; tiles[i][j].solved = false;
backs[i][j] = this["back" + i + j]; backs[i][j]._x = 20 + 120 * j; backs[i][j]._y = 20 + 120 * i; }
}
(89)lập trình Pascal) thói quen tốt, giúp chương trình rõ ràng, dễ hiểu Khơng trường hợp người lập trình đọc lại đoạn mã viết khơng hiểu lúc trước viết gì! Nhờ lưu giữ thơng tin quan trọng tạo hình cho trị chơi, bạn có sở để thực điều cần làm người dùng bấm chuột Trong hàm xử lý tình bấm chuột, bạn viết thêm sau:
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { //backs[i][j]._visible = false;
if(!tiles[i][j].solved) { } return; } } } }
Bạn cần xóa câu lệnh backs[i][j]._visible = false; ta khơng đơn giản phơi hình bấm, mà phải cân nhắc cẩn thận Khi xem xét hình bấm, trước tiên bạn cần biết "hồn thành nhiệm vụ" hay chưa cách dùng câu lệnh if(!tiles[i][j].solved) Nếu biến solved bên hình xét có trị false (chưa "hoàn thành nhiệm vụ"), ta cần tiếp tục xem xét Nếu biến solved bên hình xét có trị true (hình xét "hồn thành nhiệm vụ") khơng cần làm hết Câu lệnh return; thể điều Khi hình bấm chưa "hoàn thành nhiệm vụ", ta cần nhận biết lần bấm chuột xét lần thứ mấy, từ định cần làm cho thích hợp Trong cặp dấu gộp { } theo sau câu lệnh if(!tiles[i][j].solved), bạn diễn đạt suy nghĩ sau:
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { //backs[i][j]._visible = false;
if(!tiles[i][j].solved) { if(count == 0) {
backs[i][j]._visible = false; count = 1;
}
else if(count == 1) {
backs[i][j]._visible = false; }
(90)return; }
} } }
Nếu lần bấm chuột xét lần thứ (trị biến count 0), ta gán trị cho biến count Nhờ vậy, xem xét lần bấm chuột, thấy biến count có trị 1, ta biết lần bấm chuột thứ hai Trong hai lần bấm chuột, điều cần làm phơi hình bấm câu lệnh backs[i][j]._visible = false; (cho hình "mặt sau" biến đi) Trong lần bấm chuột thứ hai, ta cần so sánh hình xét với hình bấm lần trước Như vậy, cần phải có thêm hai biến để ghi nhớ số hàng cột lần bấm chuột thứ Bạn tiếp tục viết thêm:
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { //backs[i][j]._visible = false;
if(!tiles[i][j].solved) { if(count == 0) {
backs[i][j]._visible = false; count = 1;
r = i; c = j; }
else if(count == 1) {
backs[i][j]._visible = false; if(r == i && c == j)
return;
if(tiles[r][c].type == tiles[i][j].type) { tiles[i][j].solved = true;
tiles[r][c].solved = true; count = 0;
} else {
backs[i][j]._visible = true; backs[r][c]._visible = true; count = 0;
(91)}
Trong lần bấm chuột thứ nhất, ta dùng hai biến r c để ghi nhớ số hàng cột hình bấm Trong lần bấm chuột thứ hai, hình bấm hình trước khơng cần làm hết Điều thể câu lệnh điều kiện:
if(r == i && c == j) return;
Nếu hình bấm xét khác với hình bấm lần trước, ta cần so sánh biến type bên hai hình, xem có giống không Nếu giống, ta gán trị true cho biến solved hình để "đánh dấu", cho biết chúng "hồn thành nhiệm vụ" Nếu khơng giống, hai hình xét "úp" trở lại Dù giống hay không giống, ta cho biến count trở trị 0, kết thúc đợt kiểm tra Bạn chạy thử chương trình xem
Bài 36: Đồng hồ bấm giây
Khi chạy thử trò chơi lật hình viết, bạn thấy tượng: sau lật hình bấm vào hình để lật, hình thứ hai (hình bấm sau) giống với hình thứ (hình bấm trước), lật lên Trong trường hợp hình thứ hai khơng giống hình thứ nhất, "khơng thèm" lật lên cho bạn thấy "mặt mũi" Lơ-gích hàm xử lý tình bấm chuột khơng sai Tuy nhiên, hình thứ hai lật lên úp xuống lập tức, thời gian ngắn chu kỳ cập nhật hình Flash Do vậy, bạn khơng thấy hình lật lên, úp xuống
Điều ta mong muốn hình lật lên bấm Nếu hình bấm sau khơng giống hình bấm trước, hình cần hiển thị thời gian vừa đủ trước úp xuống để người chơi kịp nhận biết hình Muốn vậy, bạn cần sử dụng "đồng hồ bấm giây" (timer) Flash Khi hình thứ hai lật lên, ta "bấm đồng hồ" Nếu hình thứ hai khơng giống hình thứ nhất, sau khoảng thời gian định trước đó, ta cho hình úp xuống trở lại Cụ thể, thao tác "bấm đồng hồ" thực cách gọi hàm getTimer() Nếu bạn lưu trị trả hàm getTimer() vào biến time chẳng hạn, trị biến time cho biết thời điểm "bấm đồng hồ", tức thời điểm gọi hàm getTimer() Trong chương trình, bạn sửa đổi sau:
tiles = new Array(); backs = new Array(); n = 0;
type = 0; count = 0; time = 0;
this.onMouseUp = function() { for(i = 0; i < 4; i++) {
for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { //backs[i][j]._visible = false;
(92)}
else if(count == 1) {
if(tiles[r][c].type == tiles[i][j].type) {
} else {
//backs[i][j]._visible = true; //backs[r][c]._visible = true; //count = 0;
rr = i; cc = j; count = 2;
time = getTimer(); } } } return; } } } }
this.onEnterFrame = function() { if(getTimer() < time + 500) return;
if(count == 2) {
backs[r][c]._visible = true; backs[rr][cc]._visible = true; count = 0;
} }
(93)giây) khơng làm Điều nghĩa ta thực việc cần thiết sau nửa giây trôi qua Sau nửa giây trơi qua, ta xét xem biến count có trị số hay khơng (đang có thao tác bị trì hỗn hay không) Nếu trị count (quả thực có thao tác bị trì hỗn), ta thực thao tác đó: che giấu hình thứ hình thứ hai (cho chúng úp xuống trở lại) gán trị bình thường cho biến count Bạn chạy thử chương trình để thấy trì hỗn mà ta vừa thực thực có hiệu lực: hình thứ hai khơng giống hình thứ nhất, lật lên nửa giây úp xuống Có lẽ bạn thấy cần tiếp tục cải tiến: sau 16 hình lật lên, nên cho phép người chơi bắt đầu lần chơi (thay phải chạy lại chương trình) Ta chọn cách tương tác đơn giản: người chơi bấm vào chỗ sân khấu để bắt đầu lần chơi Điều nghĩa hàm xử lý tình bấm chuột onMouseUp(), bạn cần xét đến trường hợp 16 hình lật lên Trong trường hợp đó, để bắt đầu lần chơi kế tiếp, ta cho hình úp xuống gọi hàm shuffleTiles() để xáo hình Để biết nhận biết dễ dàng trường hợp 16 hình lật lên, bạn cần có biến đếm Có thể đặt tên cho biến solutions Bạn viết thêm vào chương trình sau:
tiles = new Array(); backs = new Array(); n = 0;
type = 0; count = 0; time = 0; solutions = 0;
this.onMouseUp = function() { if(solutions == 8) {
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { tiles[i][j].solved = false; backs[i][j]._visible = true; }
}
solutions = 0; shuffleTiles(); return;
}
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { if(!tiles[i][j].solved) {
if(count == 0) {
}
(94)if(tiles[r][c].type == tiles[i][j].type) { tiles[i][j].solved = true;
tiles[r][c].solved = true; count = 0;
solutions++; } else { } } } return; } } } }
Như bạn thấy, hàm xử lý tình bấm chuột onMouseUp(), so sánh hình thứ hai với hình thứ thấy chúng giống nhau, ta lại tăng trị biến solution thêm Nhờ vậy, trò chơi chấm dứt, 16 hình lật lên, biến solutions có trị Cũng hàm xử lý tình bấm chuột onMouseUp(), ta viết thêm câu lệnh điều kiện if(solutions == 8) để xét đến trường hợp 16 hình lật lên Trong trường hợp ấy, hàm onMouseUp() cho trò chơi trở trạng thái ban đầu khơng làm Cho trị chơi trở trạng thái ban đầu nghĩa che giấu hình, gán trị false cho biến solved hình, cho biến solutions trở trị xáo hình nhờ hàm shuffleTiles() Trị chơi lật hình ta xem hoàn chỉnh Bạn chơi thử xem nha Trò chơi cần cải tiến Chẳng hạn, bạn dùng biến để ghi nhớ số lần bấm chuột hiển thị biến phía sân khấu chẳng hạn (bạn cần mở rộng kích thước sân khấu) Người hồn tất trị chơi với số lần bấm chuột dĩ nhiên người chơi giỏi Tồn mã nguồn chương trình trình bày để bạn tiện theo dõi:
tiles = new Array(); backs = new Array(); n = 0;
type = 0; count = 0; time = 0; solutions = 0; for(i = 0; i < 4; i++) { tiles[i] = new Array(); backs[i] = new Array(); for(j = 0; j < 4; j++) { type = n%8;
attachMovie("Tile" + type, "tile" + i + j, n); attachMovie("Back", "back" + i + j, n + 100); n++;
(95)tiles[i][j]._x = 20 + 120 * j; tiles[i][j]._y = 20 + 120 * i; tiles[i][j].type = type; tiles[i][j].solved = false;
backs[i][j] = this["back" + i + j]; backs[i][j]._x = 20 + 120 * j; backs[i][j]._y = 20 + 120 * i; }
}
shuffleTiles();
function getRandom(min, max) {
return Math.floor(Math.random()*(max - + 1) + min); }
function shuffleTiles() { for(i = 0; i < 200; i++) { r1 = getRandom(0, 3); c1 = getRandom(0, 3); r2 = getRandom(0, 3); c2 = getRandom(0, 3);
tx = tiles[r1][c1]._x; ty = tiles[r1][c1]._y;
tiles[r1][c1]._x = tiles[r2][c2]._x; tiles[r1][c1]._y = tiles[r2][c2]._y;
tiles[r2][c2]._x = tx; tiles[r2][c2]._y = ty;
t = tiles[r1][c1];
tiles[r1][c1] = tiles[r2][c2]; tiles[r2][c2] = t;
} }
this.onMouseUp = function() { if(solutions == 8) {
(96)backs[i][j]._visible = true; }
}
solutions = 0; shuffleTiles(); return;
}
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) {
if(tiles[i][j].hitTest(_root._xmouse, _root._ymouse, true)) { if(!tiles[i][j].solved) {
if(count == 0) {
backs[i][j]._visible = false; count = 1;
r = i; c = j; }
else if(count == 1) {
backs[i][j]._visible = false; if(r == i && c == j)
return;
if(tiles[r][c].type == tiles[i][j].type) { tiles[i][j].solved = true;
tiles[r][c].solved = true; count = 0;
solutions++; }
else { rr = i; cc = j; count = 2;
time = getTimer(); } } } return; } } } }
(97)if(getTimer() < time + 500) return;
if(count == 2) {
backs[r][c]._visible = true; backs[rr][cc]._visible = true; count = 0;
} }
Bài 37: Trị chơi ráp hình
(98)q dễ, khơng q khó) Bạn nên tìm hình đơn giản, hình chuột Mickey trắng trơn chẳng hạn (hình 1), cho người chơi đốn hình dù hình nằm lộn xộn Cụ thể, ta phân hình có kích thước 400x400 (tính "pi-xơn", cịn gọi "điểm ảnh") thành 16 ơ, có kích thước 100x100 Bạn thực việc với chương trình Paint có sẵn Windows Trong cửa sổ Paint, bạn chọn cơng cụ Rectangle (cơng cụ vẽ hình khung) vẽ hình khung có kích thước 400x400 Bạn trỏ vào góc trên, bên trái miền vẽ, giữ phím trái chuột, kéo chuột qua phải, xuống dưới, đồng thời nhìn vào góc dưới, bên phải cửa sổ Paint để biết kích thước hình khung vẽ Khi thấy kích thước hiển thị 401x401, bạn thả phím chuột Hình khung vừa vẽ có kích thước 400x400 (tính ln đường biên) Tiếp theo, bạn đưa hình mà bạn tìm vào hình khung vừa vẽ: bấm-phải vào miền vẽ, chọn mục Paste From trình đơn vừa ra, tìm chọn tập tin hình cần thiết thư mục Khi hình chọn xuất cửa sổ Paint, bạn trỏ vào hình kéo vào hình khung Nếu hình chọn lớn khung hình 400x400, bạn trỏ vào góc hình kéo cho hình nhỏ lại Bạn bấm vào bên ngồi hình chọn để thực dán vào miền vẽ Paint Bên cạnh hình khung 400x400, bạn vẽ hình khung nhỏ có kích thước 100x100 Bạn bấm vào cơng cụ Select (công cụ chọn), "căng" khung chọn bao quanh khung hình nhỏ ấn Ctrl+C để chép
(99)(100)Để lưu hình thành tập tin, bạn bấm vào công cụ chọn , trỏ vào góc trên, bên trái hình, kéo chuột qua phải, xuống dưới, đến góc dưới, bên phải hình Bạn ý, hình có đường biên riêng biệt dầy pi-xôn Bạn chọn ô hình cho xác hình 4, đừng chọn nhầm đường biên hình bên cạnh Để bảo đảm xác, bạn nên lấy tầm nhìn gần trước chọn cách bấm vào "kính lúp" bấm vào ô hình xét Muốn trở lại tầm nhìn bình thường, bạn lại bấm vào kính lúp bấm-phải vào miền vẽ Chọn xong hình, bạn bấm-phải vào hình, chọn mục Copy To trình đơn vừa ra, gõ tên tương ứng, chẳng hạn Tile23 (ơ hình hàng 2, cột 3) gõ Enter Paint lưu hình chọn thành tập tin hình bitmap có tên đầy đủ Tile23.bmp
Bài 38: Sắp xếp mẩu hình
Sau có 15 mẩu hình cắt từ hình chuột Mickey hình mà bạn thích, bạn cần đưa mẩu hình vào Flash chuyển thành nhân vật Cụ thể, Flash, bạn chọn File > Import > Import to Stage (hoặc ấn Ctrl+R) Trong hộp thoại Import, bạn tìm chọn mẩu hình Tile11.bmp Flash hiển thị cửa sổ thông báo, hỏi "This file appears to be part of a sequence of images Do you want to import all of the images in the sequences?" Thông báo tử tế đề nghị lấy vào Flash tất hình mà Flash nghĩ thuộc loạt hình Bạn nên bấm No để từ chối Ta chủ động lấy mẩu hình vào sân khấu Flash làm việc cần thiết, không sợ nhầm lẫn
(101)Registration, bạn bấm vào nhỏ góc trên, bên trái để quy định điểm mốc nhân vật Điểm mốc góc trên, bên trái giúp bạn dễ dàng quy định vị trí nhân vật lập trình Tiếp theo,
bạn chọn Export for ActionScript Bạn đừng quên thao tác này, không, bạn không tạo thể nhân vật vào lúc chạy chương trình Xong, bạn bấm OK
Thao tác vừa thực làm cho mẩu hình trở thành nhân vật thư viện Bạn gõ phím Delete để xóa mẩu hình có sân khấu Nó khơng cịn cần thiết Ta tạo xếp mẩu hình sân khấu thơng qua chương trình Bạn lặp lại thao tác vừa nêu với mẩu hình thứ hai: lấy hình Tile12.bmp vào sân khấu, chuyển mẩu hình thành nhân vật xóa Cứ thế, bạn chuyển tất mẩu hình có thành nhân vật thư viện Flash Khi có đầy đủ 15 nhân vật (ứng với 15 mẩu hình), việc cần làm viết chương trình để đưa tất mẩu hình vào sân khấu Trước tiên, ta xếp mẩu hình vị trí, việc xáo hình ngẫu nhiên tính đến sau Bạn gõ phím F9 để mở bảng Actions - Frame gõ đoạn mã sau (gần giống đoạn mã xếp hình trị chơi lật hình):
tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
r = i + 1; c = j + 1;
(102)tiles[i][j] = this["tile" + i + j]; tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; }
}
Với kinh nghiệm từ trò chơi lật hình, bạn hiểu ý nghĩa đoạn mã nêu Biến lặp i j chạy từ đến số hàng cột tên nhân vật chạy từ đến 4, ta cần tạo thêm biến r c cho số hàng cột:
r = i + 1; c = j + 1;
Trong vòng lặp, trị số i 0, trị số j 0, câu lệnh attachMovie("Tile" + r + c, "tile" + i + j, n++);
tương đương với câu lệnh attachMovie("Tile11", "tile00", 0);
Câu lệnh tạo thể từ nhân vật Tile11, gán tên tile00 đặt thể độ cao (đối mục thứ ba) Khi gọi hàm attachMovie(), bạn ý cho độ cao n (gọi "độ sâu" được) tăng dần để thể tạo có độ cao khác Biểu thức n++ nghĩa "lấy trị số biến n, tăng trị số biến n đơn vị" Nhờ vậy, sau lần lặp, trị số n tăng thêm đơn vị Khi trị số i trị số j (tức trị số r trị số c 4), ta bỏ qua, khơng gọi hàm attachMovie() ta khơng có mẩu hình hàng 1, cột (vị trí trống) Cũng trị chơi lật hình, ta quản lý thể dãy chiều tên tiles Hai câu lệnh tiles[i][j]._x = 100 * j;
tiles[i][j]._y = 100 * i;
quy định vị trí cho mẩu hình Chúng xếp sát nhau, khơng có khoảng hở Chạy thử chương trình, bạn thấy rõ điều Có thể chạy chương trình, bạn thấy thiếu mẩu hình Hiện tượng chứng tỏ bạn quên chọn Export for ActionScript chuyển mẩu hình thành nhân vật Giả sử bạn thấy thiếu mẩu hình hàng 1, cột chạy chương trình, bạn sửa sai cách gõ phím F11 để mở bảng Library, bấm-phải vào dịng Tile13 MovieClip, chọn Linkage trình đơn vừa Trong hộp thoại Linkage Properties (hình 2), bạn chọn Export for ActionScript bấm OK
(103)thoại Document Properties để mở bảng màu, chọn màu đậm làm màu Nhờ vậy, người chơi thấy rõ vị trí trống sân khấu Xong, bạn bấm OK
(104)Bài 39: Hàm dịch chuyển hình
Bạn viết đoạn mã để hiển thị mẩu hình trị chơi ráp hình Mọi mẩu hình đặt vị trí chạy chương trình Có lẽ bạn nghĩ đến việc cần làm xáo trộn mấu hình theo cách giống trị chơi lật hình mà ta thực Tuy nhiên, "bình tâm" chút, bạn thấy việc xáo trộn vị trí mẩu hình hồn tồn ngẫu nhiên dẫn đến tình trạng không giải được: người chơi đưa mẩu hình trở vị trí cách trượt mẩu hình vào vị trí trống Để bảo đảm tình trạng xáo trộn giải được, ta phải tạo tình trạng xuất phát từ tình trạng trật tự, cách trượt mẩu hình vào vị trí trống
Như vậy, việc cần làm viết hàm có chức dịch chuyển mẩu hình cạnh bên vị trí trống vào vị trí trống Muốn làm việc đó, trước hết ta cần có hai biến ghi nhớ số hàng số cột vị trí trống, đặt tên blankx blanky Mỗi mẩu hình cần có hai biến ghi nhớ số hàng số cột hành nó, đặt tên currentx currenty, giúp ta biết vị trí hành mẩu hình "Sao nhỉ? Trong dãy hai chiều tiles, số hàng số cột mẩu hình cho biết vị trí cịn gì?" Có thể bạn nghĩ theo kinh nghiệm từ trị chơi lật hình Trong trị chơi lật hình, thay đổi vị trí hình sân khấu, ta thay đổi vị trí dãy hai chiều Nhờ vậy, số hàng cột hình dãy hai chiều ln thể vị trí hành hình sân khấu Ví dụ, tiles[2][3] ln ln trỏ đến hình hàng 2, cột Trong trị chơi ráp hình, ta khơng nên làm Mẩu hình thay đổi vị trí sân khấu vị trí dãy hai chiều khơng nên thay đổi Nhờ số hàng cột mẩu hình dãy hai chiều khơng đổi, ta ln biết vị trí nó, ln biết người chơi hồn tất việc ráp hình hay chưa Ví dụ, mẩu hình tiles[2][3], ta ln biết vị trí hàng 2, cột 3, cịn vị trí hành (ở hàng cột đó) thể theo cách khác, biến currentx biến currenty mẩu hình, nói cụ thể biến tiles[2][3].currentx biến tiles[2][3].currenty Ta gọi hàm dịch chuyển mẩu hình moveTile gọi hàm người chơi bấm vào mẩu hình Trong bảng Actions - Frame khung 1, bạn viết thêm sau:
tiles = new Array(); n = 0;
blankx = 3; blanky = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
r = i + 1; c = j + 1;
attachMovie("Tile" + r + c, "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; tiles[i][j].currentx = j; tiles[i][j].currenty = i;
(105)} }
function doPress() { moveTile(this); }
function moveTile(t) { tempx = blankx; tempy = blanky; blankx = t.currentx; blanky = t.currenty; t.currentx = tempx; t.currenty = tempy; t._x = t.currentx * 100; t._y = t.currenty * 100; }
Như bạn thấy, ta thêm hai biến blankx blanky Biến blankx có trị ban đầu 3, biến blanky có trị ban đầu vị trí trống ban đầu hàng 0, cột Để tạo biến currentx currenty bên mẩu hình tiles[i][j], bạn "tự nhiên" sử dụng hai biến đó, gán số cột j cho tiles[i][j].currentx gán số hàng i cho tiles[i][j].currenty Có lẽ bạn quen với "tự nhiên" ngôn ngữ ActionScript dùng Flash: muốn tạo biến, đơn giản dùng nó, khơng cần câu lệnh khai báo Câu lệnh tiles[i][j].onPress = doPress; quy định hàm doPress gọi xảy tình onPress Khác với tình onMouseDown, tình onPress nhân vật Flash xảy người dùng ấn phím chuột trỏ chuột trỏ vào nhân vật Hàm doPress gọi hàm moveTile với đối mục this, this từ dùng để nhân vật phát sinh tình Hàm moveTile(t) có đối mục mầu hình (thể nhân vật đó) Chức hàm moveTile dịch chuyển hình vào vị trí trống Để dịch chuyển mẩu hình vào vị trí trống, trước hết ta hoán đổi trị biến blankx blanky với trị biến currentx currenty nhân vật Bao vậy, muốn hoán đổi trị hai biến, ta cần có biến trung gian Trong hàm moveTile, biến tempx tempy biến trung gian Sau hoán đổi trị biến blankx, blanky với trị biến currentx currenty mẩu hình, ta thực thay đổi vị trí mẩu hình sân khấu cách gán hoành độ tung độ vào hai biến _x _y mẩu hình Ví dụ, số hàng currentx số cột currenty 3, hoành độ mẩu hình * 100 (tức 200 pi-xơn) tung độ mẩu hình * 100 (tức 300 pi-xơn) Chạy thử chương trình bấm vào mẩu hình bất kỳ, bạn thấy mẩu hình nhảy vào vị trí trống, vị trí cũ mẩu hình trở thành vị trí trống Điều chứng tỏ hàm moveTile hoạt động tốt, chưa thực điều ta mong muốn Cần áp đặt thêm điều kiện: mẩu hình cạnh vị trí trống phép dịch chuyển vào vị trí trống Bạn diễn đạt điều kiện cách viết thêm vào hàm doPress sau: function doPress() {
if( (Math.abs(this.currentx - blankx) == && this.currenty == blanky) || (this.currentx == blankx && Math.abs(this.currenty - blanky) == 1) ) { moveTile(this);
} }
(106)(107)Bài 40: Dịch chuyển hình tự động
Trong trị chơi xếp hình, bạn viết hàm moveTile để dịch chuyển hình vào vị trí trống Hàm gọi người chơi bấm vào mẩu hình cạnh vị trí trống Bạn bắt đầu chơi cách dịch chuyển lung tung mẩu hình để tạo tình trạng xáo trộn đố người khác tái lập tình trạng trật tự lúc đầu Thay tự tay xáo trộn hình, ta viết hàm shuffleTiles để làm chuyện "lung tung" gọi hàm lúc khởi động trị chơi, sau mẩu hình xếp đặt trật tự sân khấu
Tự động dịch chuyển lung tung mẩu hình nghĩa chọn ngẫu nhiên mẩu hình cạnh vị trí trống để đưa vào vị trí trống lặp lặp lại nhiều lần Khi nói đến việc chọn ngẫu nhiên, bạn nhớ đến hàm tạo trị số ngẫu nhiên getRandom mà ta viết thực trị chơi lật hình Vâng, ta viết lại hàm Bạn mở bảng Actions - Frame khung 1, viết thêm câu lệnh gọi hàm shuffleTiles, viết thêm định nghĩa hàm shuffleTiles viết thêm hàm lấy trị số ngẫu nhiên quen thuộc getRandom:
tiles = new Array(); n = 0;
blankx = 3; blanky = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
r = i + 1; c = j + 1;
attachMovie("Tile" + r + c, "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; tiles[i][j].currentx = j; tiles[i][j].currenty = i;
tiles[i][j].onPress = doPress; }
}
shuffleTiles();
function shuffleTiles() { for(k = 0; k < 100; k++) { rand = getRandom(-1, 1); if(getRandom(0, 1)) { changex = blankx + rand; changey = blanky;
(108)else {
changex = blankx;
changey = blanky + rand; }
} }
function getRandom(min, max) {
return Math.floor(Math.random()*(max - + 1) + min); }
Trong định nghĩa hàm shuffleTiles, trước mắt ta tính đến việc chọn ngẫu nhiên mẩu hình cạnh vị trí trống Đó mẩu hình so với vị trí trống có hồnh độ có tung độ, có hồnh độ có tung độ Để định chọn "hơn 1" "kém 1", ta gọi hàm getRandom(-1, 1) để có trị số ngẫu nhiên từ -1 đến Để định trị số ngẫu nhiên getRandom(-1, 1) cộng vào hoành độ tung độ vị trí trống, ta lại dùng hàm getRandom để "tung đồng xu", nghĩa dùng biểu thức getRandom(0, 1) với tư cách điều kiện câu lệnh if Nếu biểu thức getRandom(0, 1) cho trị khác 0, trị số ngẫu nhiên cộng vào hoành độ Ngược lại, biểu thức getRandom(0, 1) cho trị 0, trị số ngẫu nhiên cộng vào tung độ Biến changex changey lưu giữ hồnh độ tung độ mẩu hình chọn ngẫu nhiên Tuy vậy, trước di chuyển mẩu hình vào vị trí trống, ta cần kiểm tra xem kết chọn ngẫu nhiên có cho tọa độ "dùng được" hay khơng Chẳng hạn, vị trí trống hàng tọa độ chọn ngẫu nhiên ứng với vị trí cao rõ ràng tọa độ khơng phải tọa độ mẩu hình thực Bạn viết thêm sau vào định nghĩa hàm shuffleTiles:
function shuffleTiles() { for(k = 0; k < 100; k++) { rand = getRandom(-1, 1); if(getRandom(0, 1)) { changex = blankx + rand; changey = blanky;
} else {
changex = blankx;
changey = blanky + rand; }
if(changex >= && changex <= && changey >= && changey <= 3) { for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
if(tiles[i][j].currentx == changex && tiles[i][j].currenty == changey) moveTile(tiles[i][j]);
(109)} }
Đoạn mã vừa bổ sung kiểm tra xem biến changex changey có trị số từ đến hay không Nếu biến changex changey có trị số hợp lý (đều lớn nhỏ 3), ta dò tìm mẩu hình tương ứng với tọa độ dãy hai chiều tiles Khi dị tìm, bạn ý ta bỏ qua không xét trường hợp số hàng số cột dãy hai chiều ta khơng có phần tử Khi tìm mẩu hình cần thiết (trị số currentx phần tử trị số changex trị số currenty phần tử trị số changey), ta trao mẩu hình cho hàm moveTile để mẩu hình dịch chuyển vào vị trí trống Việc chọn ngẫu nhiên mẩu hình dịch chuyển hình vào vị trí trống lặp đi, lặp lại 100 lần Điều đủ gây tình trạng xáo trộn "nghiêm trọng" Thử chạy chương trình, bạn thấy (hình 1)
(110)Bạn kéo nút bấm Start vào sân khấu trị chơi xếp hình, đặt góc dưới, bên trái, ấn Ctrl + F3 để mở bảng Properties (trình bày thuộc tính nút bấm) Trong Instance Name, bạn gõ solve để đặt tên cho nút bấm (hình 3)
(111)Bạn chọn Scene để thoát khỏi chế độ chỉnh sửa, mở bảng Actions - Frame ứng với khung viết thêm hàm xử lý tình onPress onRelease cho nút bấm mang tên solve sau: tiles = new Array();
n = 0; blankx = 3; blanky = 0;
for(i = 0; i < 4; i++) {
}
shuffleTiles();
solve.onPress = function() { for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
tiles[i][j]._x = j * 100; tiles[i][j]._y = i * 100; }
}
(112)for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
tiles[i][j]._x = tiles[i][j].currentx * 100; tiles[i][j]._y = tiles[i][j].currenty * 100; }
}
function shuffleTiles() {
Trong hàm xử lý tình onPress nút bấm solve (hàm gọi nhấn nút solve), ta làm cho mẩu hình trở vị trí cách quy định lại tọa độ mẩu hình dựa vào số mẩu hình dãy hai chiều tiles Ví dụ, với mẩu hình hàng 2, cột (trị i 2, trị j 3) dãy tiles, vị trí có hồnh độ * 100 tung độ * 100 Trong hàm xử lý tình onRelease nút bấm solve (hàm gọi buông nút solve), ta tái lập vị trí hành mẩu hình đơn giản cách quy định lại tọa độ mẩu hình dựa vào hai biến currentx currenty bên mẩu hình
(113)Bài 41: Điều khiển dòng chữ
Trong trò chơi xếp hình, bạn tạo nút bấm Solve Nhân tiện, bạn nên tạo thêm nút bấm Reset để "chơi lại từ đầu" Nút bấm Reset diện nhiều trị chơi Với trị chơi xếp hình, nút bấm Reset cần thiết: giúp người chơi "xóa bàn chơi lại" tình trạng lộn xộn hành trở nên tắc tị, khơng giải Để có nút bấm Reset, bạn cần chép nút bấm Solve thư viện Hàm xử lý tình onPress nút bấm Reset cần gọi hàm shulffleTiles có sẵn
Cụ thể, bạn gõ phím F11 để mở bảng Library, bấm-phải vào nhân vật Button, chọn Duplicate Trong hộp thoại Duplicate Symbol vừa ra, bạn gõ Reset để đặt tên cho nút bấm gõ Enter Trong khung hiển thị bảng Library, nút bấm có nhãn Solve Bạn bấm kép vào nút bấm Reset khung hiển thị để vào chế độ chỉnh sửa nhân vật Nút bấm Reset xuất bên bảng Timeline Bạn gõ T để chọn công cụ Text Tool, bấm vào dịng chữ Solve, xóa dịng chữ gõ Reset (hình 1)
(114)trình Gõ phím F9 để mở bảng Actions - Frame, bạn viết hàm xử lý tình onPress cho nút bấm mới:
tiles = new Array(); n = 0;
blankx = 3; blanky = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
} }
shuffleTiles();
reset.onPress = function() { shuffleTiles();
}
solve.onPress = function() {
(115)(116)Bạn chọn công cụ Selection Tool , bấm vào chỗ trống sân khấu để chọn khung chữ vừa tạo Mở bảng Actions - Frame, bạn tạo thêm biến mang tên steps chương trình để đếm số lần bấm chuột dùng trị số biến làm nội dung dòng chữ moves:
tiles = new Array(); n = 0;
blankx = 3; blanky = 0; steps = 0;
moves.text = steps;
function doPress() {
if( (Math.abs(this.currentx - blankx) == && this.currenty == blanky) || (this.currentx == blankx && Math.abs(this.currenty - blanky) == 1) ) { steps++;
moveTile(this); }
}
(117)Bài 42: Hiển thị câu chào mừng
Có lẽ bạn thấy trị chơi ráp hình cịn "thiêu thiếu", chưa hồn chỉnh chưa có câu chào mừng người chơi giành thắng lợi cuối nhiều trò chơi khác Khi đó, người chơi đạt đến mục tiêu tái lập xác trật tự mẩu hình
Muốn biết người chơi đạt đến mục tiêu hay chưa, ta cần kiểm tra sau lần người chơi di chuyển mẩu hình, xét xem tất mẩu hình vào vị trí hay chưa Muốn biết mẩu hình vị trí hay chưa, ta cần xem biến currentx currenty mẩu hình có trùng với số cột j số hàng i dãy tiles hay chưa Chỉ cần phát mẩu hình sai vị trí, ta kết luận người chơi chưa đạt mục tiêu Chỉ người chơi đạt mục tiêu, ta hiển thị câu chào mừng, đại khái nhiều trò chơi khác: "You've won!" (bạn thắng) Bạn nhớ ta tùy ý điều khiển nội dung dịng chữ mang tên moves, việc hiển thị câu chào mừng dễ dàng: cần sửa nội dung dòng chữ moves, thêm vào câu chào mừng sau số bước giành thắng lợi Cụ thể, bạn cần viết thêm hàm kiểm tra testForWin gọi hàm hàm xử lý tình bấm chuột doPress:
function doPress() {
if( (Math.abs(this.currentx - blankx) == && this.currenty == blanky) || (this.currentx == blankx && Math.abs(this.currenty - blanky) == 1) ) { steps++;
moveTile(this); testForWin(); }
}
function testForWin() { solved = true;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
if(tiles[i][j].currentx != j || tiles[i][j].currenty != i) { solved = false;
break; } } }
if(solved)
moves.text = steps + " You've won!"; else
moves.text = steps; }
(118)
Với bổ sung trên, hàm kiểm tra testForWin gọi người chơi bấm chuột vào mẩu hình để xê dịch mẩu hình vào vị trí trống Trong hàm testForWin, ta dùng biến gọi solved gán trị ban đầu true Biến solved có tác dụng "cờ hiệu" thể tình trạng trị chơi Biến solved có trị true trường hợp người chơi giải trò chơi Ngược lại, biến solved có trị false Hai vịng lặp for dùng để dị tìm mẩu hình dãy tiles Với mẩu hình, biến currentx khác với số cột j biến currenty khác với số hàng i, biến solved nhận trị false, ngụ ý "trò chơi dang dở, người chơi chưa đạt mục tiêu" Sau hai vòng lặp for, ta xét đến tình trạng "cờ hiệu" solved Nếu trị solved true, nội dung dòng chữ moves gồm số bước trải qua người chơi câu chào mừng "You've won!" Ngược lại, trị solved false, dòng chữ moves thể số bước Sau chiến thắng, muốn chơi lại từ đầu, người chơi phải bấm nút Reset Khi đó, ta phải dẹp bỏ câu chào mừng Điều cần thực hàm xử lý tình bấm nút Reset:
reset.onPress = function() { shuffleTiles();
steps = 0;
moves.text = steps; }
Hai câu lệnh vừa thêm hàm xử lý tình onPress nút bấm Reset nhằm làm cho biến steps trở trị dùng biến steps làm nội dung dòng chữ moves (khơng cịn câu chào mừng nữa) Trị chơi ta xem hoàn chỉnh Bạn chạy thử xem Dưới toàn mã nguồn trị chơi xếp hình để bạn tiện tham khảo:
tiles = new Array(); n = 0;
blankx = 3; blanky = 0; steps = 0;
moves.text = steps; for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
r = i + 1; c = j + 1;
attachMovie("Tile" + r + c, "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; tiles[i][j].currentx = j; tiles[i][j].currenty = i;
tiles[i][j].onPress = doPress; }
(119)shuffleTiles();
reset.onPress = function() { shuffleTiles();
steps = 0;
moves.text = steps; }
solve.onPress = function() { for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
tiles[i][j]._x = j * 100; tiles[i][j]._y = i * 100; }
}
solve.onRelease = function() { for(i = 0; i < 4; i++)
for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
tiles[i][j]._x = tiles[i][j].currentx * 100; tiles[i][j]._y = tiles[i][j].currenty * 100; }
}
function shuffleTiles() { for(k = 0; k < 200; k++) { rand = getRandom(-1, 1); if(getRandom(0, 1)) { changex = blankx + rand; changey = blanky;
} else {
changex = blankx;
changey = blanky + rand; }
if(changex >= && changex <= && changey >= && changey <= 3) { for(i = 0; i < 4; i++)
(120)if(i == && j == 3) continue;
if(tiles[i][j].currentx == changex && tiles[i][j].currenty == changey) moveTile(tiles[i][j]);
} } } }
function getRandom(min, max) {
return Math.floor(Math.random()*(max - + 1) + min); }
function doPress() {
if( (Math.abs(this.currentx - blankx) == && this.currenty == blanky) || (this.currentx == blankx && Math.abs(this.currenty - blanky) == 1) ) { steps++;
moveTile(this); testForWin(); }
}
function testForWin() { solved = true;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(i == && j == 3) continue;
if(tiles[i][j].currentx != j || tiles[i][j].currenty != i) { solved = false;
break; } } }
if(solved)
moves.text = steps + " You've won!"; else
moves.text = steps; }
(121)tempy = blanky; blankx = t.currentx; blanky = t.currenty; t.currentx = tempx; t.currenty = tempy; t._x = t.currentx * 100; t._y = t.currenty * 100; }
Bài 43: Trị chơi tìm số nhỏ nhất
Theo đề nghị bạn đọc, ta dựa vào kiến thức, kinh nghiệm có để thực trị chơi với luật chơi sau: "Khi bấm chọn có giá trị nhỏ có bảng biến Nếu bấm sai q lần trị chơi kết thúc Mỗi bấm điểm Khi kết thúc có thơng báo số điểm đạt Mỗi lần chơi lại, ô xếp ngẫu nhiên theo trật tự khác loại bỏ số ô đồng thời bổ sung thêm số ô có giá trị khác"
(122)có nội dung thay đổi tùy ý vào lúc chạy chương trình Trước hết, để có nhân vật "ơ chứa số", ta cần vẽ hình khung sân khấu trống trơn Sau quy định màu viền màu tô mong muốn, bạn dùng cơng cụ vẽ hình khung Rectangle Tool để vẽ sân khấu hình vng Để có hình vng, bạn giữ phím Shift kéo chuột Tuy nhiên, ta tùy ý quy định lại chiều rộng chiều cao hình khung Vẽ xong, bạn ấn Ctrl+A để chọn hình vừa vẽ, ấn Ctrl+F3 để mở bảng Properties ứng với hình Bạn quy định chiều rộng 100 ô W chiều cao 100 H Để tạo dịng chữ động, bạn bấm chọn công cụ Text Tool , căng khung chữ vừa vặn với chiều rộng hình vng có (hình 1) Trong bảng Properties ứng với khung chữ, bạn chọn Dynamic Text ô Text type Bấm vào ô Instance Name, bạn gõ tên label cho dịng chữ động Trong Font Size, bạn chọn cỡ chữ lớn (26) Bạn bấm nút Text (fill) color, chọn màu chữ tương phản với màu tơ hình vng Bạn đừng quên bấm nút Align Center để dòng chữ động "gióng giữa" Điều giúp dịng chữ động nằm hình vng cách cân đối Hiện tại, dịng chữ động chưa cần có nội dung Nội dung dòng chữ động tạo vào lúc chạy chương trình
(123)Theo "thói quen" trị chơi lật hình ráp hình, ta tạo 16 thể nhân vật Tile (sau này, bạn tùy ý sửa lại chi tiết trò chơi), xếp thành hàng, cột Như vậy, sân khấu nên có kích thước 400 x 430 Chiều cao 430 pi-xôn đủ cho hàng (mỗi hàng có chiều cao 100 pi-xơn) "dịng tình trạng" (có chiều cao 30 pi-xơn) để thơng báo điểm số người chơi hiển thị thông tin khác, cần Bạn gõ phím V để dùng cơng cụ chọn Selection Tool, bấm vào sân khấu Bảng Properties bày thuộc tính sân khấu Bạn bấm nút Size để mở hộp thoại Document Properties (hình 3), quy định chiều rộng chiều cao sân khấu mục Dimensions Nhân tiện, bạn bấm nút Background color để chọn màu thích hợp Bạn bấm OK để đóng hộp thoại
(124)tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; tiles[i][j].label.text = 10; }
}
Câu lệnh tiles[i][j].label.text = 10; dùng để thử nghiệm việc hiển thị nội dung dòng chữ động label thể cách gán số 10 cho thuộc tính text dịng chữ động Chạy thử chương trình, bạn có kết hình
(125)có thể trở "kho số" để chọn Thao tác cần thiết bắt đầu lại trò chơi Thực ý định vừa nêu, bạn bổ sung dãy chứa trị số vào chương trình gọi hàm để chọn ngẫu nhiên trị số, đưa vào dãy khác (cái khay):
nums = [ 2.2, 1.2, 3.65, 0.71, 0.31, 0.01, 3.25, 0.45, 2.25, 5.2, 2.5, 0.09, 0.65, 4.6, 0.37, 0.25, 3.75, 1.7, 0.48, 5.5 ];
shuffleNumbers(); tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) {
}
function shuffleNumbers() { tray = new Array();
for(i = 0; i < nums.length; i++) if(getRandom(0, 1))
tray.push(nums[i]); else
tray.unshift(nums[i]); }
function getRandom(min, max) {
return Math.floor(Math.random()*(max - + 1) + min); }
Trong đoạn mã vừa viết, hàm shuffleNumbers lấy ngẫu nhiên số từ dãy cho (dãy nums), đưa vào dãy trung gian (dãy tray) Cụ thể, sau tạo dãy tray trống rỗng, hàm shuffleNumbers "tung đồng xu" dựa vào hàm getRandom quen thuộc Nếu hàm getRandom cho trị số khác 0, trị số lấy từ dãy nums đưa vào cuối dãy tray hàm push dãy tray Nếu hàm getRandom cho trị số 0, trị số lấy từ dãy nums đưa vào đầu dãy tray hàm unshift dãy tray Sau có dãy tray chứa trị số dãy nums cách lộn xộn, bạn dùng hàm pop dãy tray để lấy trị số cuối khỏi dãy tray, hiển thị hình:
shuffleNumbers(); tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
(126)}
Với cách viết trên, sau lần lặp, trị số cuối dãy tray rời khỏi dãy đó, vào dịng chữ động hình Để tráo trộn thực triệt để hơn, bạn lại "tung đồng xu" để định lấy trị số khỏi dãy tray cuối dãy (bởi hàm pop dãy) đầu dãy (bởi hàm shift dãy):
shuffleNumbers(); tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i; //tiles[i][j].label.text = 10; if(getRandom(0, 1))
tiles[i][j].label.text = tray.shift(); else
tiles[i][j].label.text = tray.pop(); }
}
(127)Bài 44: Trình bày số dãy
Để tạo trị chơi tìm số nhỏ nhất, bạn thực việc đưa số từ dãy vào ô sân khấu cách ngẫu nhiên Việc thực xếp ô sân khấu Tuy nhiên, thao tác lấy số ngẫu nhiên đưa vào ô thực lặp đi, lặp lại có biến (trường hợp người chơi bấm trúng có số nhỏ nhất) Vì vậy, ta nên tách thao tác thành hàm riêng biệt để dùng lại cần thiết Bạn sửa chương trình sau:
nums = [ 2.2, 1.2, 3.65, 0.71, 0.31, 0.01, 3.25, 0.45, 2.25, 5.2, 2.5, 0.09, 0.65, 4.6, 0.37, 0.25, 3.75, 1.7, 0.48, 5.5 ];
shuffleNumbers(); tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
(128)}
displayNumbers();
function displayNumbers() { for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
if(getRandom(0, 1))
tiles[i][j].label.text = tray.shift(); else
tiles[i][j].label.text = tray.pop(); }
} }
function shuffleNumbers() {
}
Như bạn thấy, ta có hàm mang tên displayNumbers chứa đoạn mã thực thao tác lấy số ngẫu nhiên đưa vào ô Hàm displayNumbers gọi sau ô xếp hồn chỉnh sân khấu Vì vậy, ta không thực thao tác lấy số ngẫu nhiên đưa vào ô xếp ô sân khấu trước
Trong hàm displayNumbers, để dự trù trường hợp có biến mất, ta phải xét thuộc tính _visible Nếu có thuộc tính _visible false bỏ qua, không xét đến (diễn đạt câu lệnh continue;) Các cịn diện nhận trị số từ "cài khay" (dãy tray) cách bình thường
Hiện tại, trị số lấy từ dãy nums hiển thị Tuy nhiên, trị chơi bổ ích (và khó hơn) số trị số hiển thị dạng biểu thức (dạng phân số biểu thức có phép tính chẳng hạn) Muốn đạt điều đó, ta cần lưu trị số thuộc tính ơ, cịn nhãn label ô dùng để hiển thị biểu thức tương ứng Trước hết, bạn viết thêm dãy exps (tức "expression") song song với dãy nums sau:
nums = [ 2.2, 1.2, 3.65, 0.71, 0.31, 0.01, 3.25, 0.45, 2.25, 5.2, 2.5, 0.09, 0.65, 4.6, 0.37, 0.25, 3.75, 1.7, 0.48, 5.5 ];
exps = [ "2 1/5", "1 1/5", "3,65", "0,71", "0,31", "1/100", "3,25", "45/100", "2 1/4", "5 1/5", "2 1/2", "0,09", "0,65", "4,6", "0,37", "1/4", "3 3/4", "1,7", "0,48", "5 1/2" ];
shuffleNumbers();
Dãy exps gọi "song song" với dãy nums theo nghĩa: hai phần tử hai dãy vị trí tương ứng với Ví dụ, chuỗi "2 1/5" (phần tử thứ dãy exps) ứng với trị số 2.2 (phần tử thứ dãy nums) Tương tự, chuỗi "1/100" (phần tử dãy exps có số 5) ứng với trị số 0.01 (phần tử dãy nums có số 5)
(129)
function displayNumbers() { var num, str;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
if(getRandom(0, 1)) num = tray.shift(); else
num = tray.pop();
str = getString(num); tiles[i][j].num = num; tiles[i][j].label.text = str; }
} }
function getString(num) {
for(var t = 0; t < nums.length; t++) { if(nums[t] == num)
return exps[t]; }
}
Trong hàm displayNumbers, trị số lấy ngẫu nhiên từ "cái khay" (dãy tray) lưu tạm vào biến num Để biết trị số cho biểu diễn chuỗi nào, ta viết thêm hàm mang tên getString Hàm getString thực nhiệm vụ đơn giản: dị tìm xem trị số cho trị số dãy nums, tìm trị số trả kết chuỗi tương ứng dãy exps Bạn ý, ta viết var trước biến t nhằm tạo biến t tạm thời, dùng hàm getString mà
Trong hàm displayNumbers, ta trao trị số biến num cho hàm getString để có chuỗi biểu diễn tương ứng, lưu chuỗi biến tạm thời str Điều thể câu lệnh str = getString(num); Sau đó, ta lưu trị số biến num vào thuộc tính gọi num: tiles[i] [j].num = num; chuỗi biểu diễn tương ứng dùng làm nội dung nhãn label: tiles[i] [j].label.text = str;
(130)Bài 45: Giải thuật tìm số nhỏ nhất
Để tạo trị chơi tìm số nhỏ nhất, bạn thực xong việc hiển thị ngẫu nhiên trị số ô Ta thực bước tiếp theo: diễn đạt việc cần làm người chơi bấm vào ô đó, nghĩa định nghĩa hàm xử lý tình onPress Khi đó, rõ ràng ta cần đọc trị số ô hiển thị, tìm trị số nhỏ trị số so sánh trị số bấm với trị số nhỏ để biết người chơi chọn hay không Nếu đúng, ta cho ô chọn biến
Bạn viết thêm vào chương trình sau:
n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i;
(131)} }
displayNumbers(); function doPress() { tray = new Array(); for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
tray.push(tiles[i][j].num); }
}
var = tray[0];
for(i = 1; i < tray.length; i++) { = Math.min(min, tray[i]); }
if(this.num == min) this._visible = false; }
Nhân xếp ô sân khấu, ta quy định hàm xử lý tình onPress hàm doPress: tiles[i][j].onPress = doPress; Thay cho tên hàm doPress, bạn đặt tên khác tùy ý Trong định nghĩa hàm doPress, để thuận tiện cho việc tìm trị số nhỏ nhất, ta đặt trị số ô hiển thị vào "cái khay" tray trống rỗng Với câu lệnh var = tray[0]; ta giả sử trị số nhỏ trị số dãy tray Sau đó, ta so sánh với trị số lại dãy Mỗi phát trị số nhỏ min, ta gán trị số cho Điều thực thuận lợi nhờ hàm Math.min (hàm lớp Math) Khi trao hai trị số, hàm Math.min trả cho ta kết số nhỏ hai số cho Nhờ câu lệnh = Math.min(min, tray[i]); sau "duyệt" qua dãy tray, ta tìm số nhỏ dãy tray Câu lệnh if(this.num == min) nhằm so sánh trị số num ô chọn với trị số nhỏ Nếu trị số num chọn trị số nhỏ nhất, ta gán trị false cho thuộc tính _visible ô, làm cho ô chọn biến Bạn ý, hàm xử lý tình huống, biến this biến trỏ đến thể mà tình xảy Trong trường hợp xét, biến this hàm doPress trỏ đến thể mà xảy tình bấm chuột Bạn chạy thử chương trình để kiểm tra hiệu hàm doPress
(132)Việc cần làm cộng điểm cho lần người chơi chọn trị số nhỏ Ngoài ra, để thêm phần căng thẳng, người chơi chọn sai bị trừ điểm người chơi chọn sai ba lần, trị chơi trở lại từ đầu (mọi tái điểm số trở 0) Bạn thấy ngay: ta cần có thêm biến score để ghi nhớ điểm biến để đếm số lần chọn sai, gọi wrong chẳng hạn Ý định vừa nêu diễn đạt chương trình sau:
tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i;
tiles[i][j].onPress = doPress; }
(133)function init() { score = 0; wrong = 0;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { tiles[i][j]._visible = true; }
}
shuffleNumbers(); displayNumbers(); }
function doPress() { tray = new Array(); for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
tray.push(tiles[i][j].num); }
}
var = tray[0];
for(i = 1; i < tray.length; i++) { = Math.min(min, tray[i]); }
if(this.num == min) { score += 5;
this._visible = false; }
else { score -= 5; wrong++; }
if(wrong > 3) init(); }
(134)(135)
Bài 46: Những cải tiến trước mắt
Trị chơi tìm số nhỏ ta "nên vóc nên hình" Cũng trị chơi ráp hình thực hiện, bạn cần làm vài việc để hồn chỉnh trị chơi Trước hết, sau người chơi bấm vào ô, ta cần kiểm tra xem người chơi thắng hay chưa Nếu người chơi làm cho biến mất, chương trình cần hiển thị câu chào mừng Ngược lại, ta cần hiển thị điểm số Bạn viết thêm cuối hàm xử lý tình bấm chuột doPress sau:
function doPress() {
if(wrong > 3) init();
if(testForWin())
result.text = score + " You've won!" else
result.text = score; }
function testForWin() { for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(tiles[i][j]._visible) return false; }
}
return true; }
function displayNumbers() {
(136)cơng cụ Free Transform Tool để điều chỉnh kích thước nút bấm cho phù hợp Bạn gõ phím V để chuyển qua công cụ chọn , bấm kép vào nút bấm để chuyển qua chế độ chỉnh sửa, chọn công cụ Text Tool (hoặc gõ phím T), bấm vào nhãn nút bấm, sửa nhãn nút bấm thành Reset Bạn sửa nhãn nút bấm thành Reset khung khung nút bấm Bạn bấm vào Scene1 để thoát khỏi chế độ chỉnh sửa, ấn Ctrl + F3 để mở bảng Properties (trình bày thuộc tính nút bấm) Trong ô Instance Name, bạn gõ reset để đặt tên cho nút bấm (hình 1)
Bạn ấn Ctrl +F3 để dẹp cửa sổ Properties, chuyển qua công cụ chọn , bấm vào sân khấu để chọn nút bấm Reset, mở lại bảng Actions - Frame viết thêm vào chương trình sau:
init();
reset.onPress = init; function init() { score = 0; wrong = 0;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { tiles[i][j]._visible = true; }
}
(137)}
function doPress() {
Ta viết thêm câu lệnh reset.onPress = init; để quy định người chơi bấm nút Reset, hàm init gọi Trong hàm init, bạn cần thêm câu lệnh result.text = score; để câu chào mừng (nếu có) biến Nhờ vậy, trị chơi thực trở tình trạng lúc đầu Chạy thử chương trình bấm nút Reset nhiều lần, bạn thấy trị số xuất ô chưa thực hỗn loạn Nguyên nhân thuộc cách chọn trị ngẫu nhiên Bạn xem lại hàm displayNumbers:
function displayNumbers() {
if(getRandom(0, 1)) num = tray.shift(); else
num = tray.pop();
Trong hàm displayNumbers, ta dùng hàm getRandom(0, 1) để chọn ngẫu nhiên hai trường hợp Tuy nhiên xác suất để có trị xác suất để có trị khác trả hàm getRandom không ngang Trong đoạn mã nêu trên, hàm getRandom(0, 1) cho trị ngẫu nhiên từ đến 1, nghĩa gồm có trị 0, trị trị trung gian Do vậy, xác suất để có trị khác lớn xác suất để có trị
Bạn sửa lại, chọn ngẫu nhiên trị số từ dãy tray theo cách khác sau:
function displayNumbers() { var num, str;
var k;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
/*
if(getRandom(0, 1)) num = tray.shift(); else
num = tray.pop(); */
k = getRandom(0, tray.length-1); num = tray[k];
tray.splice(k, 1);
(138)} }
Đoạn mã thay nhằm chọn số k ngẫu nhiên dãy tray Bạn ý, số phần tử dãy tray chạy từ đến tray.length-1 (chiều dài dãy trừ 1) Cụ thể, dãy tray có chiều dài 20 (có 20 phần tử), số phần tử dãy tray chạy từ đến 19 Sau chọn ngẫu nhiên số k dãy tray, ta gán phần tử vị trí k cho biến num: num = tray[k]; loại bỏ phần tử khỏi dãy tray: tray.splice(k, 1); Đối mục hàm splice số phần tử cần lấy khỏi dãy Đối mục thứ hai hàm splice số lượng phần tử kể từ phần tử cần lấy khỏi dãy Trong trường hợp xét, đối mục thứ hai ta cần lấy phần tử khỏi dãy tray lần lặp Nói cho gọn, đoạn mã thay giúp bạn lấy ngẫu nhiên phần tử vị trí dãy tray khỏi dãy tray Điều giúp cho ô nhận trị ngẫu nhiên tốt Phần trình bày tồn chương trình để bạn tiện tham khảo:
nums = [ 2.2, 1.2, 3.65, 0.71, 0.31, 0.01, 3.25, 0.45, 2.25, 5.2, 2.5, 0.09, 0.65, 4.6, 0.37, 0.25, 3.75, 1.7, 0.48, 5.5 ];
exps = [ "2 1/5", "1 1/5", "3,65", "0,71", "0,31", "1/100", "3,25", "45/100", "2 1/4", "5 1/5", "2 1/2", "0,09", "0,65", "4,6", "0,37", "1/4", "3 3/4", "1,7", "0,48", "5 1/2" ];
tiles = new Array(); n = 0;
for(i = 0; i < 4; i++) { tiles[i] = new Array(); for(j = 0; j < 4; j++) {
attachMovie("Tile", "tile" + i + j, n++); tiles[i][j] = this["tile" + i + j];
tiles[i][j]._x = 100 * j; tiles[i][j]._y = 100 * i;
tiles[i][j].onPress = doPress; }
} init();
reset.onPress = init; function init() { score = 0; wrong = 0;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { tiles[i][j]._visible = true; }
}
(139)}
function doPress() { tray = new Array(); for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
tray.push(tiles[i][j].num); }
}
var = tray[0];
for(i = 1; i < tray.length; i++) { = Math.min(min, tray[i]); }
if(this.num == min) { score += 5;
this._visible = false; }
else { score -= 5; wrong++; }
if(wrong > 3) init();
if(testForWin())
result.text = score + " You've won!" else
result.text = score; }
function testForWin() { for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(tiles[i][j]._visible) return false; }
}
(140)}
function displayNumbers() { var num, str;
var k;
for(i = 0; i < 4; i++) { for(j = 0; j < 4; j++) { if(!tiles[i][j]._visible) continue;
k = getRandom(0, tray.length-1); num = tray[k];
tray.splice(k, 1); str = getString(num); tiles[i][j].num = num; tiles[i][j].label.text = str; }
} }
function getString(num) {
for(var t = 0; t < nums.length; t++) { if(nums[t] == num)
return exps[t]; }
}
function shuffleNumbers() { tray = new Array();
for(i = 0; i < nums.length; i++) if(getRandom(0, 1))
tray.push(nums[i]); else
tray.unshift(nums[i]); }
function getRandom(min, max) {
(141)