Android Studio Oyun Yapımı (Flappy Bird Clone)

Bir zamanlar çok moda olan ve milyonlar tarafından indirilip oynanan yazılımı basit ama çok yankı getiren Flappy Bird oyununun değişik bir versiyonunu Android Studio ve Libgdx kullanarak nasıl yapabileceğimize bakacağız.
Uygulamaya geçmeden önce yapılması gereken ayarları yapalım. Öncelikle bu linke tıklayarak libgdx.jar dosyasını aşağıdaki oklarla gösterilen yerden indirelim.
İndirilen jar dosyamızı açalım aşağıdaki ayarlamalar yapalım.
1-Name: İstediğiniz ismi verebilirsiniz oluşturulacak projenin ismi.
2-Package: Android Studio’da bir proje oluştururken sorulan package name ile aynı istediğinizi verebilirsiniz.
3-Game Class: Android Studio’da proje oluştururken MainActivitiy.java olarak gelen standart isim değiştirip istedeğinizi yazabilirsiniz.
4-Destination: Projenin oluşturulacağı konum istediğiniz yeri verebilirsiniz.
5-Android SDK: Android Studio hangi Sdk yolunu kullanıyorsa onu yazmanız gerekiyor. Sdk yolunu öğrenmek için bir tane Android Studio projesi oluşturun veya var olan bir tanesini açıp Tools >> Android >> SDK Manager diyerek yolunu öğrenebilirsiniz.
Geriye kalan ayarları aşağıdaki resime göre ayarlayalım.
Resimdeki ayarlarıda yaptıktan sonra Generate diyerek projemizin oluşturulmasını bekleyelim daha sonra Android Studio’yu açarak Open Project diyerek oluşturulan proje dosyasını açalım.
Artık Android Studio’yu oyun yazmaya hazır hale getirdik. Anlatıma geçmeden önce uygulamada kullanılacak resimleri buraya tıklayarak indirelim. İndirdiğimiz üç resmi assets klasörünün altına atalım.
Artık uygulamaya geçebiliriz. Projemizde MyGdxGame.java dosyamızı açalım eğer başlangıçta adını değiştirdiyseniz “değiştirdiğinizisim.java” dosyamızı açalım ve aşağıdaki gibi düzenleyelim.
MyGdxGame.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
package com.mygdx.game; import com.badlogic.gdx.ApplicationAdapter; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL20; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.BitmapFont; import com.badlogic.gdx.graphics.g2d.SpriteBatch; import com.badlogic.gdx.graphics.glutils.ShapeRenderer; import com.badlogic.gdx.math.Circle; import com.badlogic.gdx.math.Intersector; import java.util.Random; public class MyGdxGame extends ApplicationAdapter { SpriteBatch batch; Texture background; Texture bird; Texture bullet1; Texture bullet2; Texture bullet3; float width; float height; float birdX = 0; float birdY = 0; int gameState = 0; float birdVelocity = 0; float enemyVelocitiy =8; float gravity = 0.5f; int numberOfEnemies = 4; float [] enemyX; float distance = 0; float [] enemyOffSet1; float [] enemyOffSet2; float [] enemyOffSet3; Random random; Circle birdCircle; Circle[] enemyCircle1; Circle[] enemyCircle2; Circle[] enemyCircle3; int score =0; int scoredEnemy= 0; BitmapFont font; //ShapeRenderer shapeRenderer; // Program ilk çağrıldığında çalışacak yer. @Override public void create () { batch = new SpriteBatch(); //Arka planlarımızı ayarlıyoruz. background = new Texture("background.png"); bird = new Texture("bird.png"); bullet1 = new Texture("bullet.png"); bullet2 = new Texture("bullet.png"); bullet3 = new Texture("bullet.png"); // Score ve Game Over yazdırabilmek için font oluşturuyoruz. font= new BitmapFont(); // Beyaz rengini seçiyoruz. font.setColor(Color.WHITE); // Yazı büyüklüğünü ayarlıyoruz. font.getData().setScale(4); // Sürekli bir şekilde oyunun en ve boy oranına ihtiyacımız olduğu için bir değişkene atıyoruz. width = Gdx.graphics.getWidth(); height = Gdx.graphics.getHeight(); // Kuşun hangi konumda durması gerektiğini ayarlıyoruz. birdX = width/3; birdY = height/3; // Kurşunlar arasındaki mesafeyi bir değişkene atıyoruz. distance = width/2; // Kurşunların x ekseninde rastgele gelmesi için dizi oluşturuyoruz. enemyX = new float[numberOfEnemies]; // Kurşunların random(rastgele) bir şekilde gelmesi için nesnemizi türetiyoruz. random = new Random(); // Kurşunların y düzleminde rastgele gelmesi için her kurşun için ayrı ayrı dizi oluşturuyoruz. enemyOffSet1 = new float[numberOfEnemies]; enemyOffSet2 = new float[numberOfEnemies]; enemyOffSet3 = new float[numberOfEnemies]; // Çarpışmaları anlayabilmek için kuşun etrafında görünmez bir daire çiziyoruz. birdCircle = new Circle(); // Kurşunların y düzleminde rastgele gelmesi için her kurşun için ayrı ayrı dizi oluşturduğumuz için // çemberler içinde ayrı ayrı dizi oluşturuyoruz. enemyCircle1 = new Circle[numberOfEnemies]; enemyCircle2 = new Circle[numberOfEnemies]; enemyCircle3 = new Circle[numberOfEnemies]; //shapeRenderer = new ShapeRenderer(); for (int i =0; i<numberOfEnemies; i++) { // Kurşunların x ekseninde belli aralıklarla gelmesini ayarlıyoruz. enemyX[i] = width +i * distance; // Kurşunların y ekseninde rastgele gelmesini ayarlıyoruz. // random.nextInt(100) = 0 ile 100 arasında rastgele değer üretir. enemyOffSet1[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet2[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet3[i] = random.nextInt(Gdx.graphics.getHeight()); // Görünmez dairelerimizi ayarlıyoruz. enemyCircle1[i] = new Circle(); enemyCircle2[i] = new Circle(); enemyCircle3[i] = new Circle(); } } // Program başladığında sürekli çağrılacak yer. @Override public void render () { batch.begin(); // Oyun başladığında arkaplanımızı çizdiriyoruz. batch.draw(background,0,0,width,height); if (gameState==1) { // Kurşunlar x ekseninde kuşu geçtiği zaman.. if (enemyX[scoredEnemy]<birdX) { score++; // scoredEnemy 0 ile 2 arasında tutuyoruz. if(scoredEnemy<numberOfEnemies-1) { scoredEnemy++; } else { scoredEnemy =0; } } //Eğer ekrana tıklanırsa.. if (Gdx.input.justTouched()) { // Kuşun hızını -9 olarak ayarlıyoruz. birdVelocity = -9; } for (int i = 0; i<numberOfEnemies; i++) { // Kurşunlar ekranın sonuna geldiği zaman tekrarda başlatıyoruz. if (enemyX [i]< width /20) { // Kurşunların x eksenindeki uzaklığını ayarlıyoruz. enemyX[i] =width +numberOfEnemies * distance; // Kurşunların y ekseninden uzaklıklarını tekrardan ayarlıyoruz. enemyOffSet1[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet2[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet3[i] = random.nextInt(Gdx.graphics.getHeight()); } else { // Eğer ekranın sonuna gelinmediyse kurşunların sürekli hareket etmesi için // Kurşunun hızını x ekseninden çıkartıyoruz. enemyX[i] = enemyX[i] - enemyVelocitiy; } // Kurşunları çizdiriyoruz. batch.draw(bullet1,enemyX[i],enemyOffSet1[i],width/15,height/12); batch.draw(bullet2,enemyX[i],enemyOffSet2[i],width/15,height/12); batch.draw(bullet3,enemyX[i],enemyOffSet3[i],width/15,height/12); // Görünmez dairelerimizi çizdiriyoruz. enemyCircle1[i] = new Circle(enemyX[i]+width/30,enemyOffSet1[i]+height/20,width/25); enemyCircle2[i] = new Circle(enemyX[i]+width/30,enemyOffSet2[i]+height/20,width/25); enemyCircle3[i] = new Circle(enemyX[i]+width/30,enemyOffSet3[i]+height/20,width/25); } if (birdY >0) { // Kuş y ekseninde 0 dan yukarıysa yani yere düşmediyse // Kuşun hızından yerçekimini çıkartıyoruz. birdVelocity = birdVelocity + gravity; // Kuşun y ekseninden kuşun hızını çıkartıyoruz. birdY = birdY - birdVelocity; } else { // Kuş yere düşerse.. gameState =2; } } else if (gameState == 0) { if (Gdx.input.justTouched()) { gameState = 1; } } else if (gameState == 2) { // Oyun biterse yani kuş yere düşerse veya kurşuna çarparsa.. // Game Over ve Tap to Play Again! ekrana yazdırıyoruz. font.draw(batch,"Game Over!",height/2,width/3); font.draw(batch,"Tap to Play Again!",height/3,width/4); // Oyun bittikten sonra ekrana tıklanırsa.. if(Gdx.input.justTouched()) { // Scoru ve kuşun hızını sıfırlıyoruz. score =0; birdVelocity =0; gameState =1; // Kuşu başlangıçtaki haline getiriyoruz birdY= height/2; // Kurşunları başlangıçtaki haline getiriyoruz. for (int i =0; i<numberOfEnemies; i++) { enemyX[i] = width +i * distance; enemyOffSet1[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet2[i] = random.nextInt(Gdx.graphics.getHeight()); enemyOffSet3[i] = random.nextInt(Gdx.graphics.getHeight()); enemyCircle1[i] = new Circle(); enemyCircle2[i] = new Circle(); enemyCircle3[i] = new Circle(); } } scoredEnemy =0; } // Kuşu çizdiriyoruz. // draw(kuşun arkapalanı, kuşun x ekseni, kuşun y ekseni, kuşun eni,kuşun boyu) batch.draw(bird,birdX,birdY,width/15,height/12); // Skor tabelasını ekrana yazdırıyoruz. font.draw(batch,String.valueOf(score),width/2,height/2+height/3); batch.end(); // Kuşun görünmez çemberini çizdiriyoruz. birdCircle.set(birdX+width/30,birdY+height/24,width/30); //shapeRenderer.begin(ShapeRenderer.ShapeType.Filled); //shapeRenderer.setColor(Color.BLACK); //shapeRenderer.circle(birdCircle.x,birdCircle.y,birdCircle.radius); for (int i=0; i < numberOfEnemies; i++) { //shapeRenderer.circle(enemyX[i]+width/30,enemyOffSet1[i]+height/20,width/20); //shapeRenderer.circle(enemyX[i]+width/30,enemyOffSet2[i]+height/20,width/20); //shapeRenderer.circle(enemyX[i]+width/30,enemyOffSet3[i]+height/20,width/20); // Eğer kurşun ile kuş çarpışırsa... if(Intersector.overlaps(birdCircle,enemyCircle1[i])||Intersector.overlaps(birdCircle,enemyCircle2[i])||Intersector.overlaps(birdCircle,enemyCircle3[i])) { gameState = 2; } } //shapeRenderer.end(); } @Override public void dispose () { } } |
Gerekli açıklamaları kod satırları arasında yaptım bu haliyle uygulamayı çalıştırırsanız düzgün bir şekilde çalışacaktır. Ancak kod satırları arasında shapeRenderer nesnesi ile yaptığımız değişiklikleri açıklama satırı haline getirdim. shapeRenderer ne işe yarar dersek kuşun ve kurşunların üstüne çizdiğimiz görünmez dairelerin görünür olmasını sağlar. Yani açıklama satırı şeklinde bulunan shapeRenderer ile ilgili bulunan kodları aktif hale getirirseniz oyun aşağıdaki gibi gözükecektir.
Kuşun ve kurşunların görünmeyen dairelerinin nasıl gözüktüğünü ne kadar büyük olduğunu shapeRenderer kullanarak öğrenebiliriz ve buna göre gerekli çarpışma ayarlarımızı yapabiliriz.
Böylelikle Android Studio kullanarak nasıl oyun yapabileceğimizi öğrenmiş olduk. Artık sizde bu öğrendiklerinizi geliştirerek çok güzel oyunlar yazabilirsiniz.
Projenin kodlarını buraya tıklayarak indirebilirsiniz.
3 cevap
Merhaba Esat hocam
birdcircle ve düşman circle larım birbirine yaklaştığı anda oyun sonlanıyor. Karakterim siyah noktaya çarpmadan düşman pngsine çarpar çarpmaz oyun bitiyor. Neden kaynaklanıyor olabilir.
Merhaba Kadir
277. kod satırında birdCircle ve enemyCircle birbirine değince overlaps fonksiyonu ile bunu anlıyoruz ve oyun sona eriyor. Yani kuş kurşunlar tarafından öldürülüyor amaçta bu zaten 🙂
Merhaba hocam bu tarz oyunların devamını bekliyorum bundan sonra sitenizin takipçisi olacağım ayrıca anlatımlara video da gelirse tadından yenmez böyle basit ama kolay oyunları yapmanızı bekliyor ve yaptığınız bu katkılardan dolayı teşekkür ediyorum
Bana mail yolu ile ulaşırsanız sevinirim