2.1 - Máy trạng thái - Finite State Machine |
Trong chương này, chúng ta sẽ học cách sử dụng FSM trong Unity3D qua một trò xe tăng đơn giản. Chúng ta sẽ tìm hiểu code cùng các thành phần liên quan.
Download Source Code
VIETUNITY AI C02.rar
Trong game của chúng ta, player có thể điều khiển được một chiếc xe tăng. Các xe tăng địch sẽ di chuyển xung quanh trong scene bằng bốn điểm waypoint. Khi xe tăng của player bước vào tầm nhìn của địch, bọn chúng sẽ truy đuổi theo; và khi xe tăng địch đã đến đủ gần để tấn công, bọn chúng sẽ bắt đầu bắn vào xe tăng của player. Điều này có đủ đơn giản chứ? Chúng ta sẽ tích hợp FSM vào để điều khiển các xe tăng địch AI của chúng ta. Đầu tiên, chúng ta sẽ chỉ dùng các trạng thái chuyển đổi đơn giản để đưa vào các trạng thái AI của xe tăng, và rồi khi chúng ta dùng một framework FSM, nền tảng tương thích trong C# FSM framework, và có thể được tìm thấy ở trang web sau đây :
http://wiki.unity3d.com/index.php?title=Finite_State_Machine
Xe tăng của Player
Trước khi viết script cho xe tăng player, hãy xem cách chúng ta cài đặt đối tượng Player Tank. Đối tượng Tank dựa trên một Mesh đơn giản với một thành phần Rigidbody, và một thành phần Box Collider. Đối tượng Tank không chỉ đơn giản là một Mesh, mà là hai Mesh tách biệt, Tank và Turret. Chúng ta thiết lập Turret là đối tượng con của Tank. Nó cho phép đối tượng Turret xoay chiều độc lập khi dùng chuột di chuyển. Và cùng lúc, khi mà nó là con của đối tượng Tank, nó sẽ đi theo bất kỳ đâu Tank đi. Vì vậy tạo ra một empty object để làm việc chuyển đổi SpawnPoint của chúng ta. Nó sẽ được dùng như một vị trí điểm khởi tạo lúc bắn một viên đạn. Cũng như chúng ta cần ấn định liên kết của Player vào đối tượng Tank của chúng ta. Đó là cách thực thể Tank của chúng ta được thiết lập. Nào chúng ta hãy nhìn vào các lớp điều khiển.
Thực thể Tank |
Lớp này mang ý nghĩa chính bởi player điều khiển đối tượng Tank sẽ dùng đến nó. Chúng ta sẽ dùng các phím W, A, S và D để di chuyển và lái xe tăng, và chuột trái dùng để nhắm và bắn dành cho đối tượng Turret.
Khởi tạo
Đặc tính của lớp TankController như sau. Đầu tiên chúng ta sẽ thiết lập hàm Start và Update.
Code trong file PlayerTankController.cs như sau :
using UnityEngine;
using System.Collections;
public class PlayerTankController : MonoBehaviour
{
public GameObject Bullet;
private Transform Turret;
private Transform bulletSpawnPoint;
private float curSpeed, targetSpeed, rotSpeed;
private float turretRotSpeed = 10.0f;
private float maxForwardSpeed = 300.0f;
private float maxBackwardSpeed = -300.0f;
//Bullet shooting rate
protected float shootRate = 0.5f;
protected float elapsedTime;
void Start()
{
//Tank Settings
rotSpeed = 150.0f;
//Get the turret of the tank
Turret = gameObject.transform.GetChild(0).transform;
bulletSpawnPoint = Turret.GetChild(0).transform;
}
void Update()
{
UpdateWeapon();
UpdateControl();
}
Đối tượng con đầu tiên trong thực thể Tank của chúng ta chính là đối tượng Turret, và đối tượng con đầu tiên của đối tượng Turret chính là điểm khởi tạo đạn SpawnPoint. Hàm Start tìm các đối tượng này, và rồi ấn định chúng cho các biến. Chúng ta sẽ ấn định biến Bullet sau, sau khi chúng ta tạo ra đối tượng Bullet. Cũng như chúng ta thêm vào trong hàm Update những hàm như UpdateControl và UpdateWeapon, chúng ta sẽ tạo chúng sớm thôi.
Bắn đạn
SpawnPoint |
void UpdateWeapon()
{
if (Input.GetMouseButtonDown(0))
{
elapsedTime += Time.deltaTime;
if (elapsedTime >= shootRate)
{
//Reset the time
elapsedTime = 0.0f;
//Instantiate the bullet
Instantiate(Bullet, bulletSpawnPoint.position, bulletSpawnPoint.rotation);
}
}
}
Điều khiển xe tăng
Turret |
void UpdateControl()
{
//AIMING WITH THE MOUSE
//Generate a plane that intersects the transform's
//position with an upwards normal.
Plane playerPlane = new Plane(Vector3.up,transform.position + new Vector3(0, 0, 0));
// Generate a ray from the cursor position
Ray RayCast = Camera.main.ScreenPointToRay(Input.mousePosition);
//Determine the point where the cursor ray intersects
//the plane.
float HitDist = 0;
// If the ray is parallel to the plane, Raycast will
//return false.
if (playerPlane.Raycast(RayCast, out HitDist))
{
//Get the point along the ray that hits the
//calculated distance.
Vector3 RayHitPoint = RayCast.GetPoint(HitDist);
Quaternion targetRotation = Quaternion.LookRotation(RayHitPoint - transform.position);
Turret.transform.rotation = Quaternion.Slerp(Turret.transform.rotation, targetRotation, Time.deltaTime * turretRotSpeed);
}
Tia sáng để nhắm bằng chuột |
Đây là cách nó hoạt động :
1. Thiết lập một mặt phẳng giao với xe tăng người chơi bằng một pháp tuyến hướng lên.
2. Bắn ra một tia từ khoảng không màn hình với vị trí chuột (ở hình minh họa trước, cho thấy chúng ta đang nhìn xuống xe tăng).
3. Tìm điểm tia sáng giao với mặt phẳng.
4. Cuối cùng, tìm góc xoay từ vị trí hiện hành đến điểm giao nhau.
Rồi chúng ta kiểm tra việc nhập phím, và rồi di chuyển/xoay xe tăng theo đó.
if (Input.GetKey(KeyCode.W))
{
targetSpeed = maxForwardSpeed;
}
else if (Input.GetKey(KeyCode.S))
{
targetSpeed = maxBackwardSpeed;
}
else
{
targetSpeed = 0;
}
if (Input.GetKey(KeyCode.A))
{
transform.Rotate(0, -rotSpeed * Time.deltaTime, 0.0f);
}
else if (Input.GetKey(KeyCode.D))
{
transform.Rotate(0, rotSpeed * Time.deltaTime, 0.0f);
}
//Determine current speed
curSpeed = Mathf.Lerp(curSpeed, targetSpeed, 7.0f * Time.deltaTime);
transform.Translate(Vector3.forward * Time.deltaTime * curSpeed);
}
}
Lớp Bullet
Prefab Bullet |
Code trong file Bullet.cs như sau :
using UnityEngine;
using System.Collections;
public class Bullet : MonoBehaviour
{
//Explosion Effect
public GameObject Explosion;
public float Speed = 600.0f;
public float LifeTime = 3.0f;
public int damage = 50;
void Start()
{
Destroy(gameObject, LifeTime);
}
void Update()
{
transform.position += transform.forward * Speed * Time.deltaTime;
}
void OnCollisionEnter(Collision collision)
{
ContactPoint contact = collision.contacts[0];
Instantiate(Explosion, contact.point, Quaternion.identity);
Destroy(gameObject);
}
}
Chúng ta có ba đặc tính: damage, Speed và Lifetime cho Bullet, vì thế Bullet sẽ tự động bị huỷ sau khi hết lifetime của nó.
Bạn có thể thấy đặc tính Explosition của Bullet được liên kết với prefab ParticleExplosion, chúng ta sẽ không nói chi tiết về nó. Có một prefab được gọi là ParticleExplosion bên dưới thư mục ParticleEffects. Chúng ta chỉ cần kéo thả prefab vào trong khu vực này. Hiệu ứng riêng biệt này được dùng khi Bullet đâm vào cái gì đó như miêu tả trong phương pháp OnCollisionEnter. Prefab ParticleExplosion dùng một script gọi là AutoDestruct để huỷ đối tượng Explosion một cách tự động sau một khoảng thời gian nhất định.
Không có nhận xét nào:
Đăng nhận xét