Building My First Unity Game: An Underwater Exploration Prototype
This project was my first Unity game project, and I used it as a way to learn how a larger game idea can be broken down into smaller technical systems. The concept was a survival and exploration game where the player controls a small fish in an endless underwater world.
The player starts as a weak fish, explores different underwater environments, avoids dangerous sea creatures, and improves abilities like size, speed, and stealth by surviving and feeding. The goal was simple: keep exploring without dying and eventually max out the fish’s attributes.
Starting With the Core Idea
I wanted the game to feel different each time it was played, so I decided early that the map should not be built manually. Instead, the underwater world would be generated while the player explored it.
That decision shaped the whole project. The game was no longer just about controlling a fish; it also became a procedural generation project. I needed to learn how to create 3D terrain through code, how to divide the world into manageable pieces, and how to make the map continue around the player.
Choosing Unity
For the game engine, I compared Unity and Unreal Engine. I chose Unity because it was easier for me to learn at the time, I had more experience with C#, and it fit the scope of the project better.
Since this was my first Unity game project, I also wanted an engine where I could quickly test ideas visually. Unity made it easier to experiment with generated meshes, materials, lighting, and gameplay behavior without spending too much time fighting the tool itself.
Procedural Terrain Generation
The biggest technical focus of the project was the underwater terrain system.
I used Marching Cubes and Perlin Noise together to create cave-like 3D environments. Perlin Noise generated density values that shaped the terrain, while Marching Cubes converted those values into actual mesh geometry.
The basic idea was:
- Split the infinite world into chunks.
- Divide each chunk into small cube units.
- Sample a density function at the corners of each cube.
- Decide which parts are inside or outside the terrain.
- Generate polygons from those cube configurations.
- Combine the generated polygons into a mesh for that chunk.
This allowed the game to create organic cave shapes instead of flat terrain or manually placed objects.
Chunks and Infinite Exploration
To support an endless world, I structured the map around chunks. Each chunk represented a 32x32x32 section of the world. As the player moved, the system could generate terrain around the player instead of loading one fixed map.
This was one of the first times I had to think about a game world as a streaming system. The player’s position controlled what needed to exist, and the map generation system had to respond to that movement.
The project design separated the terrain generation process into different parts. The chunk manager handled the player’s position and requested nearby terrain. The biome manager provided biome information, and the map generator created the vertices and triangle data needed for the final mesh.
Shaping the Underwater World
The terrain appearance depended heavily on the density function. By changing the Perlin Noise parameters, I could create different cave shapes and biome structures.
I experimented with settings such as:
- Surface level
- Noise scale
- Octaves
- Persistence
- Lacunarity
- Value multiplier
These parameters made the project feel very experimental. Small changes could create completely different terrain shapes, which helped me understand how procedural generation is often about controlling randomness rather than removing it.
Optimization Considerations
Procedural terrain generation can quickly become expensive, especially when generating 3D meshes in real time. Because of that, I also planned optimization methods for the system.
One important idea was level of detail. Terrain close to the player should be generated with more detail, while distant terrain could use simpler meshes. This would reduce unnecessary geometry while keeping the nearby environment visually rich.
I also considered generating chunks on separate threads and, if needed, moving heavier terrain calculations to compute shaders. Even though the project was an early prototype, thinking about these options helped me understand the performance side of real-time world generation.
Creature Behavior
Alongside the terrain system, I also implemented flocking movement for groups of sea creatures. This helped the underwater world feel more alive instead of being only a static cave environment.
Flocking was a useful addition because it connected gameplay with simulation. It made me think about how simple local rules such as separation, alignment and cohesion can create natural looking group movement, especially in a game world where the environment is meant to feel organic.
What I Learned
This project taught me a lot because it was not just one system. It included gameplay, procedural mesh generation, terrain streaming, biome logic, optimization planning, and creature movement.
The most important lesson was learning how to approach a large idea step by step. At the start, “an endless underwater exploration game” felt too broad. But by separating it into smaller systems like chunk generation, density functions, mesh creation, and player-centered loading, it became possible to build a working prototype.
It also gave me my first real experience with Unity as a game engine. I learned how to create and manipulate meshes, test gameplay visually, organize systems around the player, and think about performance from the beginning.
Final Thoughts
Looking back, this project was an important starting point for me. It combined many topics I was interested in: games, procedural generation, simulation, and real-time interaction.
The final result was not a polished commercial game, but it helped me understand the kind of technical game development work I enjoy. It pushed me toward projects where code creates visual systems, worlds, and behaviors instead of only solving isolated problems.
Geliştirdiğim İlk Unity Oyunu: Sualtı Keşif Prototipi
Bu proje, Unity ile geliştirdiğim ilk oyun projesiydi. Daha büyük bir oyun fikrinin küçük teknik sistemlere nasıl ayrılabileceğini öğrenmek için kullandığım bir çalışma oldu. Projenin temel fikri, oyuncunun küçük bir balığı kontrol ettiği, sonsuz bir su altı dünyasında geçen hayatta kalma ve keşif oyunuydu.
Oyuncu zayıf bir balık olarak başlayıp, farklı su altı ortamlarını keşfediyor, tehlikeli deniz canlılarından kaçıyor ve hayatta kalıp beslenerek büyüklük, hız ve gizlilik gibi özelliklerini geliştiriyordu. Oyunun amacı, ölmeden keşfetmeye devam etmek ve sonunda balığın tüm özelliklerini en yüksek seviyeye ulaştırmaktı.
Temel Fikir
Oyunun her oynanışta farklı hissettirmesini istiyordum. Bu nedenle haritanın elle oluşturulmaması gerektiğine erken bir aşamada karar verdim. Bunun yerine su altı dünyası, oyuncu keşfettikçe prosedürel olarak üretilecekti.
Bu karar projenin tamamını şekillendirdi. Oyun, balık kontrolleri ve oynanış sistemlerinin yanı sıra, aynı zamanda bir prosedürel üretim projesine dönüşmüştü. Kod aracılığıyla üç boyutlu arazi oluşturmayı, dünyayı yönetilebilir parçalara bölmeyi ve haritanın oyuncunun çevresinde üretilmeye devam etmesini sağlamayı öğrenmem gerekiyordu.
Seçtiğim Oyun Motoru
Oyun motoru seçerken Unity ve Unreal Engine’i karşılaştırdım. O dönemde öğrenmesi benim için daha kolay olduğu, C# konusunda daha fazla deneyimim bulunduğu ve projenin kapsamına daha uygun olduğu için Unity’yi seçtim.
Bu aynı zamanda ilk oyun projem olduğu için fikirleri görsel olarak hızlıca test edebileceğim bir motor kullanmak istiyordum. Unity, oluşturulan mesh’ler, materyaller, ışıklandırma ve oynanış davranışları üzerinde, motorun kendisiyle gereğinden fazla uğraşmadan denemeler yapmamı kolaylaştırdı.
Prosedürel Arazi Üretimi
Projenin en büyük teknik odağı su altı arazi sistemiydi.
Mağaraya benzeyen üç boyutlu ortamlar oluşturmak için Marching Cubes ve Perlin Noise tekniklerini birlikte kullandım. Perlin Noise, arazinin biçimini belirleyen yoğunluk değerlerini üretirken Marching Cubes bu değerlerin gerçek mesh geometrisine dönüştürülme aşamasında kullanılıyordu.
Sistemin temel çalışma mantığı şu şekildeydi:
- Sonsuz dünyayı chunk adı verilen parçalara ayırmak.
- Her chunk’ı küçük küp birimlerine bölmek.
- Her küpün köşelerindeki yoğunluk değerlerini örneklemek.
- Hangi bölgelerin arazinin içinde veya dışında kaldığını bu yoğunluklara göre belirlemek.
- Küplerin yoğunluğa göre oluşan konfigürasyonlarına bakarak poligonlar üretmek.
- Üretilen poligonları birleştirerek chunk’ın mesh’ini oluşturmak.
Bu yöntem sayesinde organik mağara yapıları oluşturulabiliyordu.
Chunk Sistemi ve Sonsuz Keşif
Sonsuz bir dünyayı desteklemek için haritayı chunk tabanlı bir yapıyla oluşturdum. Her chunk, dünyanın 32x32x32 boyutlarındaki bir bölümünü temsil ediyordu. Oyuncu hareket ettikçe sistem, tek ve sabit bir haritayı yüklemek yerine oyuncunun çevresinde yeni araziler oluşturabiliyordu.
Bu proje, bir oyun dünyasını ilk kez sürekli yüklenen bir sistem olarak düşünmemi gerektirdi. Hangi parçaların var olması gerektiğini oyuncunun konumu belirliyor, harita üretim sistemi de oyuncunun hareketine göre tepki veriyordu.
Arazi üretim sürecini farklı sorumluluklara sahip bölümlere ayırdım. Chunk yöneticisi oyuncunun konumunu takip ediyor ve yakındaki arazilerin oluşturulmasını talep ediyordu. Biyom yöneticisi gerekli biyom bilgilerini sağlıyor, harita üreticisi ise nihai mesh için gereken köşe ve üçgen verilerini oluşturuyordu.
Sualtı Dünyasını Şekillendirmek
Arazinin görünümü büyük ölçüde yoğunluk fonksiyonuna bağlıydı. Perlin Noise parametrelerini değiştirerek farklı mağara biçimleri ve biyom yapıları oluşturabiliyordum.
Üzerinde denemeler yaptığım parametrelerden bazıları şunlardı:
- Yüzey seviyesi
- Gürültü ölçeği
- Oktav sayısı
- Genlik katsayısı
- Frekans katsayısı
- Değer çarpanı
Bu parametrelerle oynadıkça, küçük değişikliklerin tamamen farklı arazi biçimleri oluşturabildiğini fark ettim. Bu süreç, prosedürel üretimin çoğu zaman rastgeleliği ortadan kaldırmak yerine onu kontrol etmekle ilgili olduğunu anlamamı sağladı.
Optimizasyon
Prosedürel arazi üretimi, özellikle üç boyutlu mesh’ler gerçek zamanlı olarak oluşturulduğunda hızlı bir şekilde maliyetli hâle gelecekti. Bu nedenle sistem için farklı optimizasyon yöntemleri planladım.
Önemli fikirlerden biri detay seviyesi, yani level of detail sistemiydi. Oyuncuya yakın araziler daha ayrıntılı oluşturulurken uzaktaki bölgelerde daha basit mesh’ler kullanılabilirdi. Böylece yakın çevrenin görsel zenginliği korunurken uzaktaki gereksiz geometrinin azaltılması mümkün olabiliyordu.
Chunk’ların ayrı threadlerde oluşturulmasını ve gerekirse daha ağır arazi hesaplamalarının compute shader’lara taşınmasını da değerlendirdim. Proje erken aşamadaki bir prototip olduğu için bu tekniği henüz kullanmasam da, farklı seçeneklerin üzerine düşünmek, gerçek zamanlı prosedürel dünya üretiminin performans tarafını daha iyi anlamama yardımcı oldu.
Canlı Davranışları
Arazi sisteminin yanında, deniz canlılarının gruplar hâlinde hareket etmesini sağlayan bir sürü davranışı sistemi de geliştirdim. Bu sistem, su altı dünyasının statik bir mağara ortamı olmaktan çıkıp daha canlı hissettirmesine yardımcı oldu.
Sürü davranışı, oynanış ile simülasyonu bir araya getirerek projeye değerli bir katkı sağladı. Ayrılık, hizalanma ve birleşme şeklindeki üç basit yerel kuralın nasıl doğal gözüken grup hareketleri oluşturabildiğini görmemi sağladı. Balık sürüleri oluşturmak özellikle organik hissettirmesi amaçlanan bu oyun dünyasında önemliydi.
Öğrendiklerim
Bu proje benim için oldukça faydalı oldu çünkü birçok sistemden oluşuyordu. Oynanış, prosedürel mesh üretimi, arazi yükleme, biyom mantığı, optimizasyon ve canlı hareketleri gibi farklı konuları bir araya getiriyordu.
En önemli kazanımım, büyük bir fikre adım adım nasıl yaklaşılacağını öğrenmek oldu. Başlangıçta “sonsuz bir su altı keşif oyunu” fazlasıyla geniş bir fikir gibi görünüyordu. Ancak bu fikri chunk üretimi, yoğunluk fonksiyonları, mesh oluşturma ve oyuncu merkezli yükleme gibi daha küçük sistemlere ayırdığımda çalışan bir prototip geliştirmek mümkün hâle geldi.
Bu çalışma aynı zamanda Unity ile gerçek anlamda ilk deneyimimi kazanmamı sağladı. Mesh oluşturmayı ve değiştirmeyi, oynanışı görsel olarak test etmeyi, sistemleri oyuncunun çevresinde organize etmeyi ve performansı geliştirme sürecinin başından itibaren düşünmeyi öğrendim.
Son Düşünceler
Geriye dönüp baktığımda bu proje benim için önemli bir başlangıç noktasıydı. Oyunlar, prosedürel üretim, simülasyon ve gerçek zamanlı etkileşim gibi ilgilendiğim birçok alanı bir araya getiriyordu.
Ortaya çıkan sonuç tamamlanmış ve ticari düzeyde bir oyun değildi. Ancak teknik oyun geliştirme alanında ne tür çalışmalardan keyif aldığımı anlamama yardımcı oldu. Yalnızca bağımsız problemleri çözmek yerine kod aracılığıyla görsel sistemler, dünyalar ve davranışlar üreten projelere yönelmemi sağladı.