Phần trước là tạo các gói quà, xếp thành hàng, tiếp theo là gán lệnh sao cho banh chạm tới khối quà sẽ biến mất.
Các bài
- Phần 1: Dựng hình
- Phần 2: Chuyển động quả banh lăn
- Phần 3: Di chuyển camera theo đối tượng
- Phần 4: Dựng Vách
- Phần 5: Rải các khối quà
- Phần 6: Hiệu ứng va chạm
- Phần 7: Tính điểm va chạm
- Phần 8: Xuất game
Bước 1: Gán lệnh va chạm lên quả banh
Có 2 cách để tạo ra hiệu ứng biến mất là Destroy (phá hủy) và inactive (ngưng kích hoạt). Destroy sẽ xóa bỏ toàn bộ các đối tượng con và các component của chúng khỏi scene. Giải pháp an toàn hơn là inactive giống như ta bỏ kiểm active trong bảng lệnh inspector
- Trong Hierarchy: Click Player
- Trong inspector: bảng lệnh PlayerController, click menu context > edit
Thêm hàm OnTriggerEnter
OnTriggerEnter
: Hàm này được gọi khi quả banh (player game object) chạm vào gói quà (trigger collider). Lưu ý là các sự kiện kích hoạt chỉ được gởi đi khi 1 trong 2 đối tượng đã được gắn RigidBody.Collider other
: code va chạm được nhập trong Player (là trigger collider - tác nhân bị chạm), và sẽ chạm vào những đối tượng khác (là other)CompareTag
: lệnh nhận diện đối tượng có Tag là "Pick Up" (Khai báo trong Inspector)SetActive (false)
: là inactive, tương tự bỏ kiểm ở mục active trong Inspectorother.gameObject
là đối tượng khác với đối tượng đang mang code (Player, trái banh)
Bước 2: Tạo Tag cho prefab Pick Up
Trong dòng code CompareTag
, các đối tượng được nhận diện qua Tag. Như vậy phải đặt Tag cho prefab Pick-Up
- Trong Project: Click chọn Pick Up trong thư mục Prefabs
- Trong inspector: Click Tag: Add Tag..
- Click dấu "+", và New Tag Name: Pick Up
- Động tác trên chỉ là tạo Tag mới, tiếp theo phải gán Tag mới vào prefab bằng cách
- click chọn lại Pick Up trong Prefabs
- chọn Tag: Pick Up trong Inspector
Chạy thử sẽ thấy banh đụng khối quà nhưng sẽ không có chuyện gì xảy ra. Đó là vì Physics engine trong Unity không cho phép các đối tượng chồng lấp nhau. Điều này là hợp lý vì trong thực tế các đối tượng là các khối rắn không lồng vào nhau được. Khi có 2 đối tượng chồng lấp ở frame nào thì physics engine lập tức sẽ phân tích tốc độ, vòng xoay, hình dạng...của đối tượng để tính toán va chạm. Một trong những yếu tố chính là vật bị va chạm là static hay dynamic (đứng yên hay chuyển động)
- Static object là các đối tượng tĩnh, như là bức tường, nền nhà,..
- Dynamic object là các đối tượng đang di chuyển như trái banh lăn, hoặc một chiếc xe đang chạy
Trong phép tính về va chạm, các hình khối static xem như sẽ không bị ảnh hưởng bởi va chạm (đứng yên) nhưng các đối tượng dynamic sẽ bị ảnh hưởng (văng ra, dội ngược,..). Trong game này, trái banh là dynamic object, sẽ bị dội ngược khi va đụng khối quà - khối quà là một static object. Tuy nhiên, physics engine vẫn có thể cho phép các đối tượng đi xiên qua nhau, đánh dấu lần va chạm và tính khối lượng đối tượng bằng cách chuyển Static object thành một trigger (một yếu tố kích hoạt) để sử dụng hàm "OnTrigger". Bằng cách này, game có thể chuyển cảnh khi nhân vật đi vào cửa thoát (trigger được đặt ở giữa lối đi cửa).
Bước 3: Gán thuộc tính Trigger cho prefab Pick Up
- Trong inspector: Bật Is Trigger trong bảng lệnh Box ColliderIs Trigger sẽ xem đối tượng chạm (trái banh) là một yếu tố kích hoạt sự kiện, và bỏ qua các tính chất vật lý
- Chạy thử chương trình: Các khối quà biến mất khi banh chạm
Bước 4: Tối ưu game
Mọi chuyện đến đây có vẻ như đã thành công. Tuy nhiên về mặt lập trình chúng vẫn còn chưa tối ưu lắm. Tính năng tối ưu của Unity sẽ tính toán và lưu tất cả các static colliders có trong khung cảnh vào trong cache (bộ nhớ). Do static colliders là các đối tượng đứng yên nên Unity sẽ chỉ tính toán và update mỗi khi có sự thay đổi. Nói tóm lại hễ là static collider thì không nên là một đối tượng chuyển động. Các khối quà, là static collider, dù là đứng yên nhưng lại xoay liên tục. Và điều này làm game phải update bộ nhớ liên tục, rất tốn tài nguyên. Để chuyển các khối quà thành dynamic collider chỉ cần áp RigidBody component, vì mọi đối tượng đã gán collider và RigidBody đều được xem là Dynamic. Áp RigidBody componet cho Prefab "Pick Up"
- Trong Project: Chọn Pick Up trong thư mục Prefab
- Trong inspector: Chọn Component > Physic > RigidBody
Ngay khi áp RigidBody các gói quà sẽ rơi xuống và xiên qua nền do
- Do Use Gravity được kích hoạt theo mặc định làm khối quà có trọng lực. Bạn có thể bỏ kiểm Use Gravity để các khối quà mất trọng lực nhưng chúng vẫn phản ứng với các lực vật lý khác.
- Các khối quà là Trigger nên chúng không chạm được vào nền (chỉ có cái khác va chạm với chúng mà thôi).
Cách tốt hơn là bật Is Kinematic cùng với Use Gravity. Lúc này các khối quà thành kinematic rigid body. Chúng có thể chuyển động nhưng không bị tác động các lực vật lý, và chắc chắn không bị rơi xuống. Đây là giải pháp tối ưu cho các đối tượng bị va chạm (là Trigger - yếu tố kích hoạt) mà cần phải chuyển động
(bài kế tiếp sẽ tạo lệnh đếm số gói quà mà banh chạm được)
[embed]https://youtu.be/XtR29MmzuT0[/embed] Link Video giới thiệu game: https://unity3d.com/learn/tutorials/projects/roll-ball-tutorial/introduction-roll-ball?playlist=17141
Dịch we need to have a brief discussion about Unity's physics system. Let's look at one of our cubes and our player. As an aside we can select two or more game objects at the same time and inspect them all. When we select multiple game objects note how the inspector changes to show the common components and property values of the selected game objects. The inspector also allows for multi-object editing. Using multi-object editing I'm going to disable the mesh renderer on both the player's sphere and the selected cube with a single click. This leaves us with the two green outlines of the collider volumes for these two objects. How do collisions work in Unity's physics engine? The physics engine does not allow two collider volumes to overlap. When the physics engine detects that any two or more colliders will overlap that frame the physics engine will look at the objects and analyse their speed and rotation and shape and calculate a collision. One of the major factors in this calculation is whether the colliders are static or dynamic. Static colliders are usually non-moving parts of your scene, like the walls, the floor, or the fountain in the courtyard. Dynamic colliders are things that move like the player's sphere or a car. When calculating a collision the static geometry will not be affected by the collision. But the dynamic objects will be. In our case the player's sphere is dynamic, or moving geometry, and it is bouncing off the static geometry of the cubes. Just as it bounces off the static geometry of the walls. The physical engine does not allow two collisions volume overlap. When the physical tool discovers any two or more collisions will overlap that frame the physical engine will look at the object and analyse their speed and rotation and shape and calculate a collision. One of the major factors in this calculation is whether the colliders are static or dynamic. Static colliders are usually non-moving parts of your scene, like the walls, the floor, or the fountain in the courtyard. Dynamic colliders are things that move like the player's sphere or a car. When calculating a collision the static geometry will not be affected by the collision. But the dynamic objects will be. In our case the player's sphere is dynamic, or moving geometry, and it is bouncing off the static geometry of the cubes. Just as it bounces off the static geometry of the walls. The physics engine can however allow the penetration or overlap of collider volumes. When it does this the physics engine still calculates the collider volumes and keeps track of the collider overlap. But it doesn't physically act on the overlapping objects, it doesn't cause a collision. We do this by making our colliders in to triggers, or trigger colliders. When we make our colliders in to a trigger, or trigger collider, we can detect the contact with that trigger through the OnTrigger event messages. When a collider is a trigger you can do clever things like place a trigger in the middle of a doorway in, say, an adventure game, and when the player enters the trigger the mini-map updates and a message plays 'you have discovered this room'. Or every time your player walks around that corner spiders drop from the ceiling because the player has walked through a trigger. For more information on OnCollision and on trigger messages see the lessons linked below. We are using OnTriggerEnter in our code rather than OnCollisionEnter. So we need to change our collider volumes in to trigger volumes. To do this we must be out of play mode. Let's select the prefab asset and look at the box collider component. Here we select Is Trigger and again the power of prefabs all of our PickUp objects are now using trigger colliders. Let's save our scene, enter play mode and test. And as our player enters the trigger we pickup the objects. Excellent. Let's exit play mode. Everything looks great. We only have one issue. We have made one small mistake, and this is related to how Unity optimises it's physics. As a performance optimisation Unity calculates all the volumes of all the static colliders in a scene and holds this information in a cache. This makes sense as static colliders shouldn't move, and this saves recalculating this information every frame. Where we have made our mistake is by rotating our cubes. Any time we move, rotate, or scale a static collider Unity will recalculate all the static colliders again and update the static collider cache. To recalculate the cache takes resources. We can move, rotate or scale dynamic colliders as often as we want and Unity won't recache any collider volumes. Unity expects us to move colliders. We simply need to indicate to Unity which colliders are dynamic before we move them. We do this by using the rigid body component. Any game object with a collider and a rigid body is considered dynamic. Any game object with a collider attached but no physics rigid body is expected to be static. Currently our PickUp game objects have a box collider but no rigid body. So Unity is recalculating our static collider cache every frame. The solution is to add a rigid body to the PickUp objects. This will move the cubes from being static colliders to being dynamic colliders. Let's save and play. And our cubes fall through the floor. Gravity pulls them down, and as they are triggers they don't collide with the floor. Let's exit play mode. If we look at the rigid body component we could simply disable Use Gravity, which would prevent the cubes from being pulled downwards. This is only a partial solution however. If we did this, even though our cubes would not respond to gravity they would still respond to physics forces There is a better solution. And that is to select Is Kinematic. When we do this we set this rigid body component to be a kinematic rigid body. A kinematic rigid body will not react to physics forces and it can be animated and moved by it's transform. This is great for everything from objects with colliders like elevators and moving platforms, to objects with triggers, like our collectables that need to be animated or moved by their transform.