Hi, I've been trying to code a video game called Galaga using C# and the Raylib_cs library, but I feel frustrated right now because I got a System.IndexOutOfRangeException bug that says "Index was outside the bounds of the array". Also, I noticed that this error occurs everytime 1, 2 or all enemies try to shoot and destroy the player because they aren't destroying it since the bullet is going up instead of downwards it and there might be something wrong with the collisions because the enemies' bullet is destroying everything that collides with it, including these enemies (aliens) themselves, and it is not supposed to happen and the idea is that every once in a while, an enemy has to shoot a few bullets randomly to only destroy the player. and once it gets destroyed, it explodes and you lose the game. Can you help me to solve this problem, please? Also, here's the code, so you can help me to find a solution, and the zipped .rar file of the game that contains everything including the code below
.
using System; using System.Numerics; using Raylib_cs;
class Enemy { public Vector2 Position; public bool IsActive; public Texture2D Texture;
public Enemy(float x, float y, Texture2D texture)
{
Position = new Vector2(x, y);
IsActive = true;
Texture = texture;
}
}
class Galaga { static Vector2 playerPosition = new Vector2(200, 600); static float playerSpeed = 400; static Enemy[] enemyGroup;
static float enemySpeed = 160;
static int direction = 1;
static bool bulletActive = false;
static float bulletSpeed = 750;
static Vector2 bulletPosition = new Vector2(-100, -100);
static double totalTime;
private static Enemy[] InitializeEnemyGroup(Texture2D alien1Texture, Texture2D alien2Texture, Texture2D alien3Texture)
{
Enemy[] enemies = new Enemy[15];
for (int i = 0; i < enemies.Length; i++)
{
float x = 100 + (i % 5) * 120;
float y = 100 + (i / 5) * 120;
if (i % 3 == 0)
{
enemies[i] = new Enemy(x, y, alien1Texture);
}
else if (i % 3 == 1)
{
enemies[i] = new Enemy(x, y, alien2Texture);
}
else
{
enemies[i] = new Enemy(x, y, alien3Texture);
}
}
return enemies;
}
static int playerLives = 3;
static bool playerExploded = false;
public static void Main()
{
const int screenWidth = 1280;
const int screenHeight = 720;
Raylib.InitWindow(screenWidth, screenHeight, "Galaga");
// Load enemy textures
Texture2D playerTexture = LoadTexture("player.png", 2);
Texture2D alien1Texture = LoadTexture("alien1.png", 2);
Texture2D alien2Texture = LoadTexture("alien2.png", 2);
Texture2D alien3Texture = LoadTexture("alien3.png", 2);
// Initialize enemy group with different enemy types
enemyGroup = InitializeEnemyGroup(alien1Texture, alien2Texture, alien3Texture);
Texture2D explosionTexture = LoadTexture("explosion.png", 2);
while (!Raylib.WindowShouldClose())
{
float delta = Raylib.GetFrameTime();
// Update player position
if (!playerExploded)
{
if (Raylib.IsKeyDown(KeyboardKey.KEY_LEFT) && playerPosition.X > 0)
{
playerPosition.X -= playerSpeed * delta;
}
if (Raylib.IsKeyDown(KeyboardKey.KEY_RIGHT) && playerPosition.X < (screenWidth - 96)) // Assuming the player texture width is 96
{
playerPosition.X += playerSpeed * delta;
}
// Update bullet position
UpdateBullet();
// Update enemy group
UpdateEnemyGroup(delta, screenWidth);
// Update player explosion state
if (playerExploded && Raylib.GetTime() > totalTime + 2.0) // 2 seconds for explosion animation
{
playerExploded = false;
}
// Check for collisions
CheckCollisions(screenWidth);
// Check for enemy shooting
if (Raylib.GetRandomValue(0, 100) < 1) // Adjust the probability as needed
{
// Find an active enemy to shoot
int activeEnemyCount = enemyGroup.Count(enemy => enemy.IsActive);
if (activeEnemyCount > 0)
{
int randomEnemyIndex;
do
{
randomEnemyIndex = Raylib.GetRandomValue(0, enemyGroup.Length);
} while (!enemyGroup[randomEnemyIndex].IsActive); // This is were the bug /System.IndexOutOfRangeException occurs
ShootEnemy(enemyGroup[randomEnemyIndex]);
}
}
}
// Draw everything
Raylib.BeginDrawing();
Raylib.ClearBackground(Color.DARKBLUE);
Raylib.DrawText("Press ESC to exit", 10, 10, 20, Color.WHITE);
// Draw player or explosion
if (!playerExploded)
{
Raylib.DrawTexture(playerTexture, (int)playerPosition.X, (int)playerPosition.Y, Color.WHITE);
}
else
{
Raylib.DrawTexture(explosionTexture, (int)playerPosition.X, (int)playerPosition.Y, Color.WHITE);
}
// Draw enemies
DrawEnemies(enemyGroup);
// Draw bullet
if (bulletActive)
{
Raylib.DrawTexture(LoadTexture("bullet.png", 2), (int)bulletPosition.X, (int)bulletPosition.Y, Color.WHITE);
}
Raylib.EndDrawing();
}
}
private static void UpdateBullet()
{
if (!bulletActive && Raylib.IsKeyDown(KeyboardKey.KEY_SPACE))
{
bulletActive = true;
bulletPosition = new Vector2(playerPosition.X + 48, playerPosition.Y); // Assuming the player texture width is 96
}
if (bulletActive)
{
bulletPosition.Y -= bulletSpeed * Raylib.GetFrameTime();
if (bulletPosition.Y < 0)
{
bulletActive = false;
}
}
}
private static void ShootEnemy(Enemy enemy)
{
bulletActive = true;
bulletPosition = new Vector2(enemy.Position.X + enemy.Texture.Width / 2, enemy.Position.Y + enemy.Texture.Height);
}
private static void UpdateEnemyGroup(float delta, int screenWidth)
{
for (int i = 0; i < enemyGroup.Length; i++)
{
if (enemyGroup[i].IsActive)
{
enemyGroup[i].Position.X += enemySpeed * direction * delta;
// Check if an enemy has hit the screen borders
if (enemyGroup[i].Position.X < 0 || enemyGroup[i].Position.X > (screenWidth - 96)) // Assuming the alien texture width is 96
{
// If any enemy hits the screen border, change direction for all enemies
direction *= -1;
}
}
}
}
private static void CheckCollisions(int screenWidth)
{
if (bulletActive)
{
Rectangle bulletBounds = new Rectangle(bulletPosition.X, bulletPosition.Y, LoadTexture("bullet.png", 2).Width, LoadTexture("bullet.png", 2).Height);
for (int i = 0; i < enemyGroup.Length; i++)
{
if (enemyGroup[i].IsActive)
{
Rectangle enemyBounds = new Rectangle(enemyGroup[i].Position.X, enemyGroup[i].Position.Y, enemyGroup[i].Texture.Width, enemyGroup[i].Texture.Height);
if (Raylib.CheckCollisionRecs(bulletBounds, enemyBounds))
{
// Collision detected, handle it as needed
bulletActive = false;
enemyGroup[i].IsActive = false; // Disable the enemy
break; // Exit the loop once a collision is detected
}
}
}
}
}
private static void DrawEnemies(Enemy[] enemies)
{
for (int i = 0; i < enemies.Length; i++)
{
if (enemies[i].IsActive)
{
Raylib.DrawTexture(enemies[i].Texture, (int)enemies[i].Position.X, (int)enemies[i].Position.Y, Color.WHITE);
}
}
}
private static Texture2D LoadTexture(string path, int resize = 1)
{
Image image = Raylib.LoadImage(path);
Texture2D texture = Raylib.LoadTextureFromImage(image);
Raylib.UnloadImage(image);
texture.Width = texture.Width / resize;
texture.Height = texture.Height / resize;
return texture;
}
}
Please put ``` (three backticks) on separate line before and after code fragment you put in the post.
Where exactly exception is thrown? Which line? What is on the callstack? What are the values of variables (the array and the index)?
When you do
randomEnemyIndex = Raylib.GetRandomValue(0, enemyGroup.Length);
You need to use enemyGroup.Length - 1
.
From the raylib cheatsheet:
int GetRandomValue(int min, int max); // Get a random value between min and max (both included)