Game Studio
Liên kế mạng xã hội

Game Studio


Hướng dẫn: Animation với "enterFrame" listeners

Trong Corona có hai phương pháp của ảnh động (animation): sprite animation và procedural animation. Sprite animation (hướng dẫn) liên quan đến việc sử dụng nhiều khung hình (frames) được hiển thị trong một chu kỳ mà tạo một cảm giác chuyển động bên trong đối tượng . Ngược lại, procedural animation liên quan đến việc sử dụng kỹ thuật lập trình để di chuyển, xoay, scale hoặc thay đổi trạng thái của đối tượng.

Hướng dẫn trước đã chỉ ra cách tạo procedural animation bằng cách sử dụng transitions. Tuần này, chúng ta sẽ thảo luận làm thế nào để thao tác đối tượng bằng cách sử dụng "enterFrame" event.

Tổng quan

Khi một ứng dụng đang chạy, Corona sẽ cập nhật màn hình 30 lần mỗi giây hoặc 60 lần mỗi giây,thường được gọi là frames per second hoặc fps. Bạn có thể kiểm soát tốc độ này thông qua các giá trị fps bên trong tập tin config.lua của ứng dụng:
Mã (Lua):
application = {
    content = {
        scale = "letterbox",
        width = 320,
        height = 480,
        fps = 60,  -- 30 or 60
    },
}
Khi các ứng dụng đang chạy, mỗi lần (frame) khi Corona chuẩn bị cập nhật màn hình, nó tạo ra một event được gọi là "enterFrame". Sử dụng event này song song với một event listener, bạn có thể animate một đối tượng bằng cách thay đổi một số khía cạnh của nó mỗi frame.

Thiết lập cơ bản

Hãy xem xét một trò chơi cổ điển như Space Invaders®. Trong trò chơi này, aliens di chuyển qua lại trong một khuôn mẫu được thiết lập, và đôi khi một UFO đặc biệt sẽ zoom to lên khắp màn hình. Hãy minh họa làm thế nào để di chuyển mà UFO bằng cách sử dụng một "enterFrame" listener:
Mã (Lua):
local ufo = display.newCircle( 340, 15, 10 )

local timeToMove = 5  -- animate trong  5 seconds
local fps = 60
local numberOfTicks = fps * timeToMove  -- tức là 300 ticks
local finalDestination = -20
local distanceToMove = ufo.x - finalDestination  -- tức là 360 points
local pointsPerTick = distanceToMove / numberOfTicks  -- 1.2 points mỗi  tick
Thiết lập này có lẽ là dài hơn một chút so với những gì bạn sẽ viết, nhưng nó rất hữu ích để giải thích các hàm toán học có liên quan. Thời gian được dựa trên “tick” của đồng hồ hay frame, vì vậy trong một trò chơi 60 fps, sẽ có 60 event được tạo ra mỗi giây. Nếu chúng ta muốn di chuyển UFO của chúng ta trên một màn hình 320 điểm(points) trong suốt 5 giây, chúng ta phải tính toán chính xác số lượng bao nhiêu để di chuyển nó trên mỗi tick.

Points và pixels

Corona sử dụng một kích thước "khu vực nội dung" ảo với chiều rộng và chiều cao được quy định tại config.lua (xem ở trên). Tuy nhiên, điều này sẽ thường không "khớp" chính xác với độ rộng của pixel trên một thiết bị thực. Ví dụ, iPhone 6 màn hình là 750 ixels rộng và màn hình iPad Air là 1536 pixels rộng. Như vậy, đối với animation dựa trên frame của UFO trên màn hình, sẽ rất hữu ích khi chuyển đổi mỗi vị trí thay đổi thành points.

Trong ví dụ này, chúng ta có tổng số 300 "ticks" để di chuyển UFO trên màn hình, vì fps là 60 và chúng tôi sẽ di chuyển nó trong khoảng thời gian 5 giây (60 × 5 = 300). UFO bắt đầu tại một vị trí x=340, tức là 20 điểm bên ngoài cạnh phải của khu vực nội dung (320 + 20), và đích của nó là một vị trí x= -20, tức là 20 điểm bên ngoài cạnh trái của khu vực nội dung. Như vậy, khoảng cách thực tế của quá trình di chuyển sẽ là 360 điểm (340 – (-20) = 360). Vì chúng ta cần phải biết có bao nhiêu điểm để di chuyển đối tượng từng ticks, chúng ta chỉ đơn giản là chia khoản cách cho số tick (360/300) để có được một kết quả là 1,2.

Sử dụng "enterFrame" event

Bây giờ chúng ta đã có những tính toán để di chuyển UFO, chúng ta hãy viết một hàm mà sẽ thực hiện trên mỗi tick:
Mã (Lua):
function ufo:enterFrame()
    self:translate( -pointsPerTick, 0 )
    if self.x <= finalDestination then
        Runtime:removeEventListener( "enterFrame", self )
    end
end

Runtime:addEventListener( "enterFrame", ufo )
Bên ngoài hàm - trong dòng cuối cùng của ví dụ này - chúng ta thêm "enterFrame" event listener vào Runtime và truyền vào trong đối tượng hiển thịufo. Điều này sẽ bắt đầu quá trình animation dựa trên frame.

Đối với các hàm khai báo, chúng ta "đính kèm" hàm vào đối tượng UFO bằng cách sử dụng : để các đối tượng được truyền vào trong. Điều này được gọi là phương pháp đối tượng Lua, và bằng cách đó, chúng ta có thể truy cập đối tượng UFO trong hàm như là self.

Bên trong hàm, trên mỗi frame, chúng ta di chuyển UFO về bên trái. Biết được giá trị của pointsPerTick1.2, nó chỉ đơn giản là trừ x của đối tượng bằng cách sử dụng object:translate(). Các code bổ sung để kiểm tra khi UFO đi đếm điểm đích cuối cùng của nó là -20, tại thời điểm đó chúng ta remove các "enterFrame" event listener, kết thúc quá trình di chuyển của UFO.

Tất nhiên điều này đơn giản là chỉ di chuyển dọc theo trục x, và điều này có thể dễ dàng được thực hiện thông qua một transition, nhưng animation dựa trên frame có khả năng có thể được sử dụng cho các kịch bản phức tạp hơn như di chuyển một đối tượng trong một mô hình, di chuyển kẻ thù qua lại nhiều lần, di chuyển game backgrounds, vv...

Delta time

Lưu ý rằng khi làm việc với các animation dựa trên frame, bạn sẽ cần phải quan tâm đến các biến động "delta" time. Điều này là bởi vì, ở bên trong, frames không được đảm bảo sẽ kích hoạt chính xác mỗi lúc, và tùy thuộc vào bao nhiêu hoạt động khác đang diễn ra trong ứng dụng của bạn, sự không chính xác này có thể ảnh hưởng đến animation tổng thể. Nếu chính xác là điều cần thiết với bạn, xin vui lòng tham khảo hướng dẫn này, trong đó vạch ra tận dụng delta time như thế nào.

Kết luận

Như bạn có thể thấy, "enterFrame" event cung cấp thêm một lựa chọn để animation trong Corona, đặc biệt khi các animation cần thiết lại vượt quá khả năng của một transition duy nhất. Ngoài ra bạn cũng cần tham khảo thêm bài viết này để biết những gì cần phải làm khi sử dụng enterFrame.
 Theo coronaviet.com

 

Xem thêm:

Corona SDK