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

Game Studio


Hướng dẫn: animation bằng physics trong Corona SDK

Trong bài hướng dẫn về lập trình cho animation, chúng ta học được cách animation thông qua transition.to() và "enterFrame" listeners. Trong hướng dẫn này, chúng ta sẽ thảo luận về cách animation một đối tượng bằng cách sử dụng phương pháp dựa trên physics.

Nếu bạn đã sử dụng physics trong ứng dụng của bạn, di chuyển các đối tượng với "enterFrame" listeners hay transition có thể gây xung đột với physics engine. Tại sao? Bởi vì physics engine di chuyển tất cả mọi thứ theo đúng nghĩa vật lý, ví dụ như mô phỏng các lực tương tác/trọng lực, vận tốc, vv... Vì vậy, nếu bạn cần di chuyển các đối tượng mà là physical bodies, bạn nên làm điều này với các API và các thuộc tính trong thư viện physics (tất nhiên có một số ngoại lệ, nhưng thông thường bạn nên sử dụng các phương pháp physics để kiểm soát các đối tượng physics).  

Trong hướng dẫn này, chúng ta sẽ tạo ra một platform cơ bản và nó di chuyển qua lại dọc theo trục ngang, tương tự như platform thường được tìm thấy trong nhiều trò chơi platformer 2D ví dụ như Mario.

Code cơ bản

Điều này khá đơn giản: thiết lập physics engine, tạo ra một đối tượng platform, và tạo cho nó một physical body. Tiếp theo, tạo ra hai hình chữ nhật vô hình được thiết lập như là "sensors" (sensors chỉ để phát hiện va chạm mà không tạo bất kỳ phản ứng vật lý nào khác). Cuối cùng, áp dụng một vận tốc ổn định cho platform này, và khi nó va chạm với một hình chữ nhật sensors, đảo ngược vận tốc của nó để di chuyển platform theo một hướng khác.

-- 1) Set up the physics engine

local physics = require("physics")

physics.start()

physics.setDrawMode( "hybrid" )  -- "hybrid" for testing; "default" for gameplay

 

-- 2) Create the platform

local platform = display.newRect( display.contentCenterX, 250, 100, 25 )

platform:setFillColor( 1,0,0 )

physics.addBody( platform, "kinematic" )

platform.travelDistance = 200  -- Set the total travel distance

platform.speed = 40  -- Set the speed for the platform

platform.id = 1  -- Set platform ID for collision detection with sensors (see below)

 

-- 3) Create the sensor objects

local leftSensor = display.newRect( 0, platform.y, 10, platform.height )

leftSensor.isVisible = false

physics.addBody( leftSensor, "dynamic", { isSensor=true } )

leftSensor.gravityScale = 0  -- Make the sensor float (no effect from gravity)

leftSensor.id = 1  -- Set sensor ID for collision detection with respective platform

leftSensor.x = platform.x - ( platform.travelDistance * 0.5 )

 

local rightSensor = display.newRect( 0, platform.y, 10, platform.height )

rightSensor.isVisible = false

physics.addBody( rightSensor, "dynamic", { isSensor=true } )

rightSensor.gravityScale = 0  -- Make the sensor float (no effect from gravity)

rightSensor.id = 1  -- Set sensor ID for collision detection with respective platform

rightSensor.x = platform.x + ( platform.travelDistance * 0.5 )

 

-- 4) Set up the collision handler function/listener

local function onCollision( self, event )

    if ( "began" == event.phase and self.id == event.other.id ) then

        local vx,vy = self:getLinearVelocity()

        self:setLinearVelocity( -vx, -vy )

    end

end

platform.collision = onCollision

platform:addEventListener( "collision", platform )

 

-- 5) Set the platform in motion

platform:setLinearVelocity( platform.speed, 0 )

 

1) Thiết lập physics engine

Vì chúng ta đang sử dụng physics, chúng ta phải kích hoạt các engine. Trong ví dụ này, chúng ta chỉ đơn giản là khởi động engine và thiết lập hiển thị là chế độ " hybrid" để chúng ta có thể thấy các physics engine theo dõi/phát thảo các đối tượng khác nhau (đặc biệt là các sensors vô hình).

2) Tạo nền tảng

Trong ví dụ này, chúng ta tạo ra một hình chữ nhật vector đơn giản với kích thước khoảng 100 × 25pixel, xoay theo chiều ngang với một tọa độ y250, và sau đó chúng ta tô màu (fill) cho nó với màu đỏ. Tiếp theo, chúng ta sử dụng physics.addBody() để làm cho nó một đối tượng physics. Lưu ý rằng trong cùng một line, chúng ta thiết lập cho nó là một physics dạng kinematic - điều này là bởi vì, trong hầu hết các platform game, các nhân vật và các đối tượng khác bị ảnh hưởng bởi lực hấp dẫn, nhưng platform chuyển động lại được "thả nổi" trong không khí và không bị ảnh hưởng. Mặc dù chúng ta có thể làm cho các platform này “miễn dịch” với lực hấp dẫn (sử dụng object.gravityScale), nhưng nó vẫn bị các lực khác tác dụng như nhân vật nhảy lên nó, điều này có thể làm cho các platform di chuyển ra khỏi trục dự định của nó. Vì vậy, một giải pháp tốt hơn là để làm cho nó một đối tượng kinematic, có nghĩa là nó sẽ được “miễn dịch” với tất cả các lực bên ngoài, bao gồm cả lực hấp dẫn, các đối tượng khác chạm vào nó, vv...

Ngoài ra, chúng tôi thiết lập một vài thuộc tính khác cho platform này, bao gồm cả travelDistance - được sử dụng để tính toán nơi đặt các sensors. Chúng tôi cũng lưu giữ speed  cho platform này và cung cấp cho nó một giá trị id, điều này sẽ được sử dụng để đảm bảo rằng nó chỉ đáp ứng/phản ứng khi nó va chạm với các sensors của nó, không phải với các sensors của các platform khác (trong trường hợp chúng tôi tạo ra nhiều platform di chuyển trong một thiết lập phức tạp hơn).

3) Tạo các đối tượng sensors

Như thể hiện trong hướng dẫn sử dụng với "enterFrame" listeners, chúng ta có thể theo dõi vị trí của platform trên mỗi runtime frame và sau đó, khi nó vượt qua một điểm nhất định trên con đường của nó, ta sẽ thay đổi hướng của nó. Vấn đề với cách tiếp cận này là nếu chúng ta quyết định bổ sung nhiều platform để thiết lập một level phức tạp hơn, chúng ta sẽ cần một listener riêng biệt cho mỗi platform, và phải liên tục theo dõi vị trí của các platform.

May mắn thay, bởi vì chúng ta đang sử dụng physics, chúng ta có thể giải quyết event thay đổi hướng theo một cách tiện lợi hơn dựa vào physics. Chúng ta làm điều này bằng cách tạo ra hai đối tượng sensors đối diện với các cạnh của trục platform chuyển động - về cơ bản đây là "bức tường" vô hình mà platform sẽ va chạm. Một lần nữa, chúng ta sử dụng các hình chữ nhật vector đơn giản để thiết lập chiều cao giống như platform. Lưu ý rằng vị trí x bắt đầu từ 0 không phải là vị trí cuối cùng (chúng ta sẽ tính toán nó).

Trong 2 line tiếp theo, chúng ta tạo ra đối tượng vô hình, sau đó chúng tôi làm cho nó thành một physics body. Một khác biệt quan trọng là chúng ta thiết lập loại vật lý là dynamic (loại mặc định). Trong khi điều này có vẻ phản trực quan, vì các sensor sẽ không di chuyển hoặc bị ảnh hưởng bởi lực/trọng lực, va chạm sẽ chỉ xảy ra nếu ít nhất có một body thuộc loại dynamic. Hãy nhớ rằng chúng ta thiết lập platform là " kinematic", vì vậy trong trường hợp này, các sensor phải là "dynamic" để tạo ra một đáp ứng va chạm (đọc thêm tính chất của kinematic để biết thêm). Trong cùng một line, lưu ý rằng bảng "options" chứa isSensor = true để thiết lập body thành sensor. Cuối cùng, trên line tiếp theo, chúng ta thiết lập gravityScale 0 để cho các sensor không rơi/đáp ứng với lục của trọng lực.

Trên line tiếp theo, chúng ta bổ sung một thuộc tính cho các id của các sensor, thiết lập để các id giống như platform. Giá trị này sẽ được sử dụng trong xử lý va chạm có điều kiện kiểm tra xem liệu platform này đã va chạm với một sensor của chính nó. Mở rộng theo ý tưởng này, nếu chúng ta quyết định tạo ra nhiều platform để thiết lập một level phức tạp hơn, mỗi platform sẽ có một giá trị id duy nhất, và mỗi sensor của nó sẽ có cùng giá trị id.

Bước cuối cùng trong việc tạo ra các sensor, chúng ta thiết lập vị trí x của nó dựa trên vị trí x của platform trừ đi một nữa quảng đường di chuyển của platform.

Toàn bộ quá trình này sẽ được lặp lại cho các sensor thứ 2 (rightSensor), và vị trí x của nó được thiết lập dựa trên vị trí x của platform cộng thêm một nữa quảng đường di chuyển của platform.

Nếu chúng ta chạy code của chúng ta vào thời điểm này, các đối tượng trong simulation sẽ trông như thế này:

4) Thiết lập các hàm/listener xử lý va chạm

Chúng ta cần một hàm để xử lý khi va chạm xảy ra. Trong trường hợp này, chúng ta đang sử dụng bảng event để chúng ta cung cấp tham số self của đối tượng như là bảng event thực tế.

Trong ví dụ này, chúng ta chỉ quan tâm đến khởi đầu của va chạm ("began" phase) và chúng ta chỉ quan tâm đến những va chạm nếu các platform (self) chạm vào một trong những sensor có cùng giá trị id. Nếu cả hai điều kiện được đáp ứng, chúng ta đảo ngược hướng của platform bằng cách lấy vận tốc tuyến tính hiện tại và sau đó chúng tôi lại áp dụng lại hướng cho nó bằng cách sử dụng giá trị âm.

5) Thiết lập chuyển động cho platform

Để thiết lập chuyển động cho platform, chúng ta lấy giá trị speed  thiết lập cho nền tảng này và áp dụng nó vào tham số x của object:setLinearVelocity() (đối số y có thể lưu giữ là 0 hoặc nil trong ví dụ này, vì nền tảng này được chỉ di chuyển theo chiều ngang). Theo cách này, nền tảng này sẽ liên tục "di chuyển qua lại" giữa hai bộ cảm biến.

Như bạn có thể thấy, physics là một cách đơn giản và hữu hiệu để "animation" di chuyển cho các đối tượng trong một trò chơi. Kết hợp với phát hiện va chạm và các phương pháp khác, các platform di động và vô số các kịch bản khác được dễ dàng đạt được bằng cách sử dụng được xây dựng trong physics engine của Corona.

Xem thêm:

animation