TRANG CHỦ
CHUYÊN MỤC
HỌC HỎI
TAG
ABOUT
Tìm kiếm
Lập trình games với Love2D - Chương 9 - Tập tin và phạm vi
2023-10-22 07:48:10
Love2D
Học Lập Trình Lua
100 lượt xem
0 bình luận
### Tập tin Với nhiều file, mã của chúng ta sẽ trông ngăn nắp hơn và dễ điều hướng hơn. Tạo một file mới có tên ```example.lua```. Đảm bảo rằng nó nằm trong cùng thư mục với file ```main.lua```. Bên trong file này, tạo một biến. Mình sẽ đặt ```--! file:``` ở đầu mỗi file để nói rõ bạn phải đặt code ở file nào. Điều này chỉ dành cho hướng dẫn, nó không có tác dụng gì (nó chỉ là lời bình luận) và bạn không cần phải sao chép nó. Nếu một khối mã không có phần này trong các hướng dẫn sau này thì nó sẽ nằm trong ```main.lua``` hoặc file được đề cập trước đó. ```lua --! file: example.lua test = 20 ``` Bây giờ vào ```main.lua```, đặt ```print(test)```. Khi bạn chạy trò chơi, bạn sẽ thấy nó ```test``` bằng ```nil```. Điều này là do chúng ta phải tải tập tin trước. Chúng tôi thực hiện việc này bằng ```require``` cách truyền tên tệp dưới dạng chuỗi làm đối số đầu tiên. ```lua --! file: main.lua -- Không cần phần mở rộng (đuôi) .lua -- Không cần love.load hay gì cả require("example") print(test) ``` Chúng ta không cần thêm ".lua" vào tên tập tin vì Lua làm điều này cho chúng ta. Bạn cũng có thể đặt tệp vào thư mục con, nhưng trong trường hợp đó hãy đảm bảo bao gồm toàn bộ đường dẫn. ```lua --Với require chúng ta sử dụng (.) thay vì (/) require("path.to.example") ``` Bây giờ khi bạn in ```test```, sau khi chúng tôi tải ```example.lua```, bạn sẽ thấy số đó là 20. Mã đầy đủ: | example.lua ```lua --! file: example.lua test = 20 ``` | main.lua ```lua --! file: main.lua -- Không cần phần mở rộng (đuôi) .lua -- Không cần love.load hay gì cả require("example") print(test) ``` ```test``` trong trường hợp này chúng ta gọi là biến toàn cục (global variable) hay gọi tắt là "global". Đó là một biến mà chúng ta có thể sử dụng ở mọi nơi trong dự án của mình. Ngược lại với biến toàn cục, là biến cục bộ (local variable) hay gọi tắt là "local". Bạn tạo một biến cục bộ bằng cách viết ```local``` trước tên biến. ```lua --! file: example.lua local test = 20 ``` Chạy trò chơi bạn thấy một lần ```nil``` nữa. Điều này là do phạm vi (scope) của nó . ### Phạm vi - Scope Các biến cục bộ được giới hạn trong phạm vi của chúng. Trong trường hợp ```test```, phạm vi là file ```example.lua```. Điều này có nghĩa là ```test``` có thể được sử dụng ở mọi nơi trong file đó, nhưng không được sử dụng trong các file khác. Nếu chúng ta tạo một biến cục bộ bên trong một khối, như hàm, câu lệnh ```if``` hoặc vòng lặp ```for```, thì trong đó sẽ là phạm vi của biến. ```lua --! file: example.lua if true then local test = 20 end print(test) --Output: nil ``` ```test``` là ```nil```, bởi vì chúng ta in nó ngoài phạm vi của nó. Các tham số của hàm giống như các biến cục bộ. Chỉ tồn tại bên trong hàm. Để thực sự hiểu cách thức hoạt động của phạm vi (scope), hãy xem đoạn mã sau: | example.lua ```lua --! file: example.lua local test = 20 function some_function(test) if true then local test = 40 print(test) --Output: 40 end print(test) --Output: 30 end some_function(30) print(test) --Output: 20 ``` | main.lua ```lua --! file: main.lua test = 10 require("example") print(test) --Output: 10 ``` Nếu bạn chạy trò chơi, nó sẽ in: 40, 30, 20, 10. Chúng ta hãy xem mã này từng bước một. Đầu tiên chúng ta tạo biến ```test``` trong ```main.lua```, nhưng trước khi in nó, chúng ta yêu cầu ```example.lua```. Trong ```example.lua``` chúng ta tạo một biến cục bộ ```test```, biến này không ảnh hưởng đến biến toàn cục trong ```main.lua```. Có nghĩa là giá trị chúng tôi cung cấp cho biến cục bộ mà chúng tôi tạo này không được cấp cho biến toàn cục. Chúng ta tạo một hàm được gọi ```some_function(test)``` và sau đó gọi hàm đó. Bên trong hàm đó, tham số ```test``` không ảnh hưởng đến biến cục bộ mà chúng ta đã tạo trước đó. Bên trong câu lệnh ```if```, chúng ta tạo một biến cục bộ khác có tên là ```test```, biến này không ảnh hưởng đến tham số ```test```. Bản in đầu tiên nằm bên trong câu lệnh ```if``` và nó là 40. Sau câu lệnh ```if ```, chúng ta in lại và bây giờ là 30, đây là giá trị chúng ta chuyển làm đối số. Tham số ```test``` không bị ảnh hưởng bởi ```test``` bên trong câu lệnh ```if```. Bên trong câu lệnh ```if```, biến cục bộ được ưu tiên hơn tham số. Ngoài hàm ```some_function``` chúng ta còn in ```test```. Lần này là 20. Phần biến ```test``` được tạo ở đầu ```example.lua``` không bị ảnh hưởng bởi phần biến ```test``` bên trong của hàm. Và cuối cùng chúng ta in ```test``` bằng ```main.lua```, và nó là 10. Biến toàn cục không bị ảnh hưởng bởi các biến cục bộ bên trong ```example.lua```. Và khi tạo biến cục bộ, bạn cũng không cần phải gán giá trị ngay. ```lua local test test = 20 ``` ### Trả về một giá trị - Return Nếu bạn thêm câu lệnh ```return``` ở ngoài phạm vi của file (không ở trong bất kỳ hàm nào), nó sẽ được trả về khi bạn sử dụng ```require``` để tải file. Ví dụ: ```lua --! file: example.lua local test = 99 return test ``` ```lua --! file: main.lua local hello = require "example" print(hello) --Ouput: 99 ``` ### Khi nào và tại sao phải dùng biến cục bộ (local)? Cách làm tốt nhất là luôn sử dụng các biến cục bộ (local) và có nhiều lý do cho việc đó. Trước hết, Lua truy cập biến cục bộ (local) nhanh hơn biến toàn cục (global), sự khác biệt rất nhỏ, có lẽ không lớn hơn 0,000001 giây, nhưng khi bạn sử dụng nhiều biến global thì nó sẽ tăng lên. Một lý do khác là với biến global, bạn có nhiều khả năng mắc lỗi hơn. Bạn có thể vô tình sử dụng cùng một biến hai lần ở các vị trí khác nhau, như thay đổi biến đó thành giá trị nào đó ở vị trí 1, nơi sẽ không có ý nghĩa nếu đặt giá trị đó ở vị trí 2. Nếu bạn định chỉ sử dụng một biến trong một phạm vi nhất định thì nên dùng biến đó là local. Ở chương trước chúng ta đã tạo một hàm để tạo hình chữ nhật. Trong hàm này, chúng ta có thể tạo biến cục bộ (local) ```rect``` vì chúng ta chỉ sử dụng nó trong hàm đó. Chúng ta vẫn sử dụng hình chữ nhật đó bên ngoài hàm nhưng chúng ta truy cập nó từ bảng ```listOfRectangles``` mà chúng ta thêm nó vào. Chúng ta không tạo ```listOfRectangles``` local vì chúng ta sử dụng nó trong nhiều chức năng. ```lua function love.load() listOfRectangles = {} end function createRect() local rect = {} rect.x = 100 rect.y = 100 rect.width = 70 rect.height = 90 rect.speed = 100 -- Đặt hình chữ nhật mới vào danh sách table.insert(listOfRectangles, rect) end ``` Chúng ta vẫn có thể biến nó thành cục bộ (local) bằng cách tạo biến bên ngoài hàm ```love.load```. ```lua -- Bằng cách khai báo nó ở đây chúng ta có thể truy cập nó ở mọi nơi trong file này. local listOfRectangles = {} function love.load() -- Nó trống nên chúng ta có thể xóa chức năng love.load này end ``` Vì vậy, có những thời điểm nào có thể sử dụng toàn cục (global) không? Mọi người có nhiều ý kiến về điều này. Một số người sẽ khuyên bạn đừng bao giờ sử dụng Global. Tôi nói với bạn rằng sẽ ổn thôi, đặc biệt là với người mới bắt đầu, sử dụng các biến toàn cục global khi bạn cần chúng trong nhiều file. Tương tự như biến global ```love```. Chỉ cần bạn nhớ rằng local nhanh hơn. Lưu ý rằng trong suốt hướng dẫn này, tôi sử dụng rất nhiều global, nhưng điều này là để làm cho mã ít hơn và dễ giải thích hơn. ### Bản tóm tắt Với ```require``` chúng ta có thể tải các file lua khác. Khi bạn tạo một biến, bạn có thể sử dụng nó trong tất cả các file. Trừ khi bạn tạo một biến cục bộ (local), bị giới hạn trong phạm vi của nó. Các biến cục bộ không ảnh hưởng đến các biến có cùng tên nằm ngoài phạm vi của chúng. Luôn thử sử dụng các biến cục bộ (local) thay vì các biến toàn cục (global) vì chúng nhanh hơn. ------ [Trước](/learn/detail?learnId=8) | [Mục lục](/learn/search?keyword=Lập%20trình%20games%20với%20Love2D) | [Kế tiếp](/learn/detail?learnId=10)
Gợi ý bài học liên quan
Awesome Love2D
Lập trình games với Love2D - Visual Studio Code
Lập trình games với Love2D - Chương 24
Lập trình games với Love2D - Chương 23
Lập trình games với Love2D - Chương 22