I really don't know what is considered better or even good for the most part. My code varies and has evolved over the years as a developer and sometimes I think it looks cleaner, but it is never easy to edit or add something. I fight with myself when writing things like particle engines because I know the purpose of a particle engine is to be quick and efficient, but how much overhead is there really just by giving a reference of an emitter to a particle that is contained within it? Why should I write behaviors for particles as functions that return a value vs just writing a function that returns nothing but handles all of the behavior? I feel like with the latter I end up with code that is easier to modify, but it looks terrible. With the previous I end up with very clean code but is god awful to edit as I have one iteration loop that basically controls everything based on the function it is given.
Here is some more recent code I have written that I think would be considered "good" but I am really not sure. The gist of this code is that it will spawn an enemy in a pattern that right now is determined by the writer. I will eventually write functions that determine which shape should be spawned when and where, but right now it just will spawn a shape from the SpawnPolyGroup function with 5 enemies per line and 6 lines in the shape. So it makes a hexagon with 5 enemies per line. My question is, is it better to have the SpawnGroup function control the for loop and return values from each SpawnPatterns (being Vector2 as locations), or would it be better to have each function in the SpawnPatterns class have it's own iterative loop? Also, any other tips on my code for cleanliness and professionalism would be great. I am self taught and never had a tutor, but have read a lot about people being self taught writing code that is unprofessional, but I have never reached out for someone to look at my code aside from a few people so I am hoping that I can learn something to be more professional in the future in hopes to find a paying job as a programmer.
public static class Spawner
{
public static bool isSpawning = false;
public static float spawnTimer = 0;
public static bool groupSpawning = false;
public static Dictionary<Enemy, float> delayedSpawnDict = new Dictionary<Enemy, float>();
public static float timeDelta = 0;
//Arguments for currentPattern should be (int maxEnemies, int currentIteration, int radius, Vector2 PatternLocation)
public static Func<int, int, Vector2, Vector2, Vector2> currentPattern = SpawnPatterns.Line;
public static void Update(GameTime gameTime)
{
if (!isSpawning)
{ return; }
if (timeDelta > 0)
{
timeDelta -= gameTime.ElapsedGameTime.Milliseconds;
}
if (timeDelta <= 0 && delayedSpawnDict.Count() > 0)
{
KeyValuePair<Enemy, float> pair = delayedSpawnDict.ElementAt(0);
Enemies.enemies.Add(pair.Key);
pair.Key.Spawn();
timeDelta = pair.Value;
delayedSpawnDict.Remove(pair.Key);
}
//If enemies alive is greater than max enemies then do not spawn
if (Enemies.enemies.Count + delayedSpawnDict.Count() >= 1)
{ return; }
//Spawn Individual
if (spawnTimer >= 500)
{
SpawnPolyGroup(gameTime, new Vector2(800, 0), 5, 6);
spawnTimer = 0;
}
spawnTimer += gameTime.ElapsedGameTime.Milliseconds;
}
public static void SpawnGroup(GameTime gameTime, Vector2 location, Vector2 mod1, int amount = 5, float delay = 100)
{
for (int i = 0; i < amount; i++)
{
Vector2 enemyLocation = currentPattern(amount, i, mod1, location);
if (enemyLocation == default(Vector2))
{
return;
}
Enemy enemy = new Enemy(15, Assets.hollowCircle, enemyLocation, EnemyUtilities.Follow, 500);
if (delay > 0)
{
delayedSpawnDict.Add(enemy, delay);
}
else
{
Enemies.enemies.Add(enemy);
}
}
}
public static void SpawnPolyGroup(GameTime gameTime, Vector2 location, int amount = 5, int sides = 5)
{
float radians = AOneMath.AngleToRadian(360 / sides);
float rotation = AOneMath.AngleToRadian(90 * (sides % 2));
for (int i = 0; i < sides; i ++)
{
int distanceFromCenter = 200;
float x1 = location.X + (float)Math.Cos(radians * i + rotation) * distanceFromCenter;
float y1 = location.Y + (float)Math.Sin(radians * i + rotation) * distanceFromCenter;
Vector2 p1 = new Vector2(x1, y1);
float x2 = location.X + (float)Math.Cos(radians * (i + 1) + rotation) * distanceFromCenter;
float y2 = location.Y + (float)Math.Sin(radians * (i + 1) + rotation) * distanceFromCenter;
Vector2 p2 = new Vector2(x2, y2);
SpawnGroup(gameTime, p2, p1, amount);
}
}
}
public static class SpawnPatterns
{
/// <param name="radius">Radius, Best to have X and Y the same</param>
/// <param name="patternLocation">Center location of circle</param>
/// <returns>Enemy location based on current iteration of max from radius to the patternLocation as the center</returns>
public static Vector2 Circle(int max, int current, Vector2 radius, Vector2 patternLocation)
{
float radians = AOneMath.AngleToRadian(360/max);
float x = (float)Math.Cos(radians * current);
float y = (float)Math.Sin(radians * current);
return new Vector2(patternLocation.X + (x * radius.X), patternLocation.Y + (y * radius.Y));
}
/// <param name="pointB">The end point where the last enemy should be in the line</param>
/// <param name="pointA">The start point where the first enemy should be in the line</param>
/// <returns>Enemy location based on current iteration of max from pointA to pointB</returns>
public static Vector2 Line(int max, int current, Vector2 pointA, Vector2 pointB)
{
float x = MathHelper.Lerp(pointA.X, pointB.X, (float)current / (float)max);
float y = MathHelper.Lerp(pointA.Y, pointB.Y, (float)current / (float)max);
return new Vector2(x, y);
}
/// <param name="p1">Top left point of area to spawn randomly</param>
/// <param name="p2">Bottom right point of area to spawn randomly</param>
public static Vector2 Random(int max, int current, Vector2 p1, Vector2 p2)
{
float x = AOneMath.random.Next((int)p1.X, (int)p2.X);
float y = AOneMath.random.Next((int)p1.Y, (int)p2.Y);
return new Vector2(x, y);
}
}
↧