Unity ile Yapay Zeka: Oyun Karakterlerine Akıllı Davranışlar Kazandırma

 

Unity ile Yapay Zeka

Herkese merhaba, bugün Unity üzerine birşeyler araştırmak istedim ve karşıma neredeyse her yerde yapay zeka çıktı. Çünkü oyun geliştirme dünyasında yapay zeka (AI), büyülü bir dünya gibi! AI, oyun karakterlerine gerçekçi davranışlar kazandırarak, oyun dünyasının daha dinamik ve akıllı hissettirilmesini sağlıyor. Bir düşünün, oynadığınız bir oyunda düşmanların stratejik hamleler yapması ya da NPC’lerin çevreye duyarlı davranışlar sergilemesi, oyunun atmosferini ne kadar güçlendirir, değil mi?

Bu yazıda Unity kullanarak oyun karakterlerine nasıl akıllı davranışlar kazandırabileceğinizden bahsedeceğiz. Yani, düşman karakterlerinizin birer tuğladan ibaret olmaktan çıkıp gerçek birer rakip gibi hissettirilmesini sağlamak!

1. Yapay Zeka ile Tanışalım

Öncelikle, yapay zeka nedir? Aslında oyun AI’sı dediğimiz şey, karakterlerin belirli kurallara ve algoritmalara göre hareket etmelerini sağlamak. Amaç, oyuncunun karşısında sadece scripted davranışlar sergileyen bir karakter yerine, daha dinamik ve duruma göre tepki veren bir rakip veya dost oluşturmak.

Unity’de yapay zeka geliştirmenin ilk adımı, yol bulma ve hareket sistemlerini öğrenmek. Burada karşımıza NavMesh çıkıyor.

2. NavMesh: Karakterlerimize Yollar Çizelim!

Unity’de karakterlerin çevrede nasıl hareket edeceğini belirlemenin en yaygın yollarından biri NavMesh (Navigasyon Ağı) kullanmaktır. NavMesh, karakterlerin hareket edebileceği yolları ve alanları tanımlar. Bunu oluşturduktan sonra, karakterinizin belirli bir noktaya nasıl ulaşacağı sorusunu çözmüş oluyorsunuz. Şimdi buna biraz daha detaylı bakalım:

NavMesh Nedir?

NavMesh, oyun dünyasındaki gezilebilir alanları tanımlayan sanal bir ağdır. Bu ağ, karakterlerin hareket edebileceği yolları ve engelleri belirler. Örneğin, karakterlerin yürüyebileceği zeminleri, duvarları ve diğer engelleri içerir. NavMesh, karakterlerin doğal ve mantıklı bir şekilde hareket etmelerini sağlayan bir harita gibidir.

NavMesh Nasıl Oluşturulur?

NavMesh oluşturmak için şu adımları izlemelisiniz:

  1. Unity Editor’da, Window menüsünden AI ve ardından Navigation seçeneğine tıklayarak Navigasyon penceresini açın.
  2. Oyununuzdaki zemin ve diğer yüzeyler üzerinde NavMesh’in hangi alanlarda oluşturulacağını belirlemek için bu alanları “Navigation Static” olarak işaretleyin. Bu, bu yüzeylerin NavMesh oluşturulurken dikkate alınmasını sağlar.
  3. Navigasyon penceresinde, Bake sekmesine gidin ve Bake butonuna tıklayarak NavMesh'i oluşturun. Unity, sahnedeki gezilebilir alanları analiz eder ve bunları NavMesh'e dönüştürür.

NavMesh Agent Bileşeni

Karakterlerinizin NavMesh üzerinde hareket etmesini sağlamak için her bir karaktere NavMesh Agent bileşenini eklemeniz gerekir. Bu bileşen, karakterin NavMesh üzerindeki hareketini kontrol eder.

  1. NavMesh Agent bileşenini karakterinize ekleyin ve bileşenin özelliklerini (hız, dönüş hızı, ivme, vs.) ayarlayın. Bu ayarlar, karakterinizin NavMesh üzerinde nasıl hareket edeceğini belirler.

Hareket Etme ve Hedef Belirleme

Karakterinizin belirli bir noktaya ulaşmasını sağlamak için, NavMesh Agent bileşenini kullanarak hedef noktalar belirleyebilirsiniz:

  • Kod ile Hedef Belirleme: NavMesh Agent bileşenini kullanarak karakterin hedef bir noktaya gitmesini sağlayabilirsiniz. Örneğin, bir düşman karakterinin oyuncuyu takip etmesini sağlamak için hedef olarak oyuncunun pozisyonunu ayarlayabilirsiniz.
using UnityEngine;
using UnityEngine.AI;

public class EnemyAI : MonoBehaviour
{
public Transform player; // Oyuncu nesnesi
private NavMeshAgent agent;

void Start()
{
agent = GetComponent<NavMeshAgent>();
}

void Update()
{
if (player != null)
{
agent.SetDestination(player.position); // Düşmanı oyuncunun konumuna yönlendir
}
}
}
  • Hedeflere Ulaşma: Karakteriniz NavMesh üzerinde hareket ederken, NavMesh Agent bileşeni karakterin yolunu otomatik olarak hesaplar ve hedefe en kısa yoldan ulaşmasını sağlar.

Engeller ve Dinamik Değişiklikler

Bazı durumlarda, sahnede dinamik değişiklikler olabilir (örneğin, hareket eden engeller). Bu gibi durumlarda, NavMesh’in bu değişikliklere tepki vermesi gerekir. Bunu sağlamak için NavMesh Obstacle bileşenini kullanabilirsiniz. Bu bileşen, sahnedeki engellerin NavMesh'i nasıl etkilediğini belirtir. Engellerin NavMesh üzerinde etkili olmasını sağlar ve gerektiğinde karakterlerin bu engelleri aşmalarını veya çevresinden dolaşmalarını sağlar.

3. Karar Verme Zamanı: Davranış Ağaçları

Karakterlerinizin hareket edebilmesini sağladınız, harika! Peki, şimdi sıra onların karar vermesinde. Oyun karakterlerinizin belirli durumlar karşısında nasıl tepki vereceğini belirlemek için davranış ağaçları (behavior trees) veya finite state machine (FSM) kullanabilirsiniz.

Davranış ağaçları, karar verme süreçlerini modellemenin etkili yollarından biridir. Örneğin, bir düşman karakteriniz oyuncuyu gördüğünde saldırmaya mı karar verecek yoksa kaçacak mı? Bu gibi kararları dallara ayrılmış ağaçlar şeklinde modelleyebilirsiniz. Ayrıca Unity Asset Store’da, bu işlevselliği kolaylaştıran harika eklentiler de bulabilirsiniz.

FSM ise bir karakterin durumlarını temsil eden bir yapı sunar. Karakterinizin durumu “devriye geziyor” iken, bir tehlike fark ederse durumu “saldırıyor” olarak değişebilir. Bu yapı, karakterin daha organize ve yönetilebilir bir davranış sergilemesine olanak tanır.

4. Dost mu, Düşman mı? Karakterlerimizi Kategorize Edelim

Her oyunda farklı AI türleri vardır: Düşmanlar, dostlar ve bağımsız NPC’ler. Her biri için farklı davranışlar geliştirmeniz gerekecek. Örneğin, düşman AI’nız oyuncuya saldırırken, dost AI karakteriniz belki de ona yardım etmeye çalışacak. Her bir AI türü için farklı stratejiler geliştirmek işinizi kolaylaştırır ve karakterlerinizi daha ilginç hale getirir.

5. Makine Öğrenimi ile Daha Akıllı AI: Unity ML-Agents

Eğer yapay zekaya daha da derinlemesine girmek istiyorsanız, Unity ML-Agents ile makine öğrenimi (ML) kullanarak karakterlerinizi eğitebilirsiniz. Unity, ML-Agents ile oyunlarınızda AI eğitimini kolaylaştıran araçlar sunuyor. ML-Agents sayesinde karakterleriniz, oyun içinde öğrenme yeteneğine sahip olabilir. Bu, karakterlerinizin davranışlarını önceden kodlamaktan ziyade, onların belirli durumlarda kendi başlarına karar verebilmesini sağlar.

Örneğin, düşmanlarınız zamanla oyuncunun stratejilerini öğrenip daha karmaşık saldırı stratejileri geliştirebilir. Bu, oyun deneyimini çok daha dinamik ve zorlayıcı hale getirebilir.

6. Gerçek Dünyadan İlham Verenler!

Unity kullanarak AI geliştiren birçok oyun mevcut. Örneğin, Alien: Isolation, yapay zekayı etkileyici bir şekilde kullanarak oyuncuya sürekli bir tehlike hissi yaşatmayı başardı. Düşmanlarınızın oyun alanında stratejik hareket etmeleri ve oyuncuya meydan okumaları, oyununuzu bir üst seviyeye taşıyacaktır.

Sonuç olarak, Unity ile yapay zeka geliştirmek, son dönem gelişmeleri de düşünürsek oyuncularınıza daha gerçekçi ve zengin bir deneyim sunmanın anahtarı gibi duruyor. Basit NavMesh uygulamalarından karmaşık AI davranış ağaçlarına ve hatta makine öğrenimine kadar uzanan geniş bir yelpazede AI geliştirme yöntemleri mevcut ve burası gerçekten derya deniz bir konu. Siz de eğer oyunlarınızda karakterlerin daha “akıllı” olmasını istiyorsanız, yapay zeka geliştirmenin püf noktalarını öğrenmeye başlamalısınız.

Herkese iyi kodlamalar.

Selin.

Flutter and Performance Optimisation

 

Flutter - Performance Optimisation

Hello everyone. In this blog post, I would like to talk about some basic techniques and tips that we can use to make our Flutter apps faster and smoother. I am about to publish my second app on GooglePlay and in this process, I realised that I have to think about performance more than I think about visuals, design, UI elements. Because no matter how stylish your app looks, it is not possible for the user experience to be positive if there are performance problems. That’s why I researched this topic and listed below what I found.

1. Render Performance: Avoid Unnecessary Redraws
In a Flutter application, every change can cause the screen to redraw. This often creates a big problem in terms of performance. You can optimise your application by avoiding unnecessary redraws.

  • const Keyword: Widgets defined with const are immutable and are not redrawn unnecessarily. Using const, especially when creating static structures, can provide a great improvement in performance.
const Text(
'Hello World!',
style: TextStyle(fontSize: 24),
);

The widget defined in this way will not be redrawn unless it changes.

  • ‘shouldRebuild’ Control: Within some widgets, you can use the shouldRebuild function to make the widget redraw only when certain conditions are met.
@override
bool shouldRebuild(covariant CustomWidget oldWidget) {
return oldWidget.value != value;
}

2. List Performance: Optimising Large Lists
Working with large datasets can cause performance issues, especially when displaying long lists. Flutter offers several optimisation tools for such situations.

  • ListView.builder: In a fixed length or large list, it is more performant to use ListView.builder, which loads only the items in the view, rather than loading all items at once.
ListView.builder(
itemCount: items.length,
itemBuilder: (context, index) {
return ListTile(
title: Text(items[index]),
);
},
);
  • ReorderableListView: When creating sortable lists, this widget can be used to maintain performance. Likewise, it renders only the widgets that are needed and improves performance.

3. Asynchronous Coding: Manage Transactions without Locking the UI
Time-consuming operations, such as network requests or long-running processes, can freeze the UI. Flutter has several tools for managing asynchronous operations.

  • FutureBuilder: FutureBuilder allows you to show a pending state in the UI while waiting for an asynchronous operation to complete. In this way, your application provides a seamless experience to users.
FutureBuilder(
future: fetchData(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator();
} else if (snapshot.hasError) {
return Text('Error: ${snapshot.error}');
} else {
return Text('Data: ${snapshot.data}');
}
},
);
  • async and await: These keywords allow operations to be performed asynchronously. await waits for the operation to finish, while async indicates the completion of the operation. It is important to use these constructs correctly to prevent the UI from freezing.
Future<void> fetchData() async {
final response = await http.get('https://api.example.com/data');
// Operations need to be carried out here
}

4. Get rid of unnecessary packages: Lighten Your Code Base
Adding packages to your Flutter application can speed up the development process. However, unnecessary or excess packages can bloat your application and negatively impact performance.

  • Dependency Management: Regularly review the dependencies in your pubspec.yaml file. Remove unused packages and measure their impact on performance.
dependencies:
flutter:
sdk: flutter
# Remove unused packages
  • Minimal Package Usage: If possible, only add packages that are really necessary. Prefer lighter packages and consider alternatives.

5. Flutter DevTools: Performance Analysis and Debugging
Flutter offers Flutter DevTools, a powerful tool for monitoring and solving performance issues. With this tool you can analyse your application’s CPU and memory usage, detect UI lags and make performance improvements.

  • CPU Profile: Monitoring the CPU usage of your application allows you to understand which processes consume excess resources.
  • Timeline: You can use the timeline tool to see where the UI is lagging. This tool shows which processes take the most time.
  • Memory Profile: You can detect memory leaks and make optimisation. You can identify processes that consume too much memory and make improvements in memory usage.

Conclusion: Performance Optimisation is a Process
Performance optimisation, unfortunately, is not a one-time operation. As you develop the application and add new features, performance issues can arise again and again, and I’ve seen it happen many times. A simple change to a button’s performance analysis is therefore necessary to make improvements on a regular basis.

I hope that the techniques I have discussed here will help you make your Flutter application more performant, but of course every application is different and we should not forget to optimise it according to its specific requirements.

Happy coding to everyone!

Selin.