//add an ore drop using a gameobject's positional/velocity properties public static void AddOreDrop(GameObject origin) { Particle temp = new Particle( //generate the ore drop ContentHandler.Textures[ORE_KEY], origin.WorldCenter, origin.Velocity + Vector2.Multiply(AsteroidManager.GetVelocity(origin.Rotation + MathHelper.ToRadians(Util.rnd.Next(-90, 90))), 0.5f), Color.White, ORE_DROP_FTL, true, origin.Rotation, (float)Util.rnd.NextDouble(-0.1f, 0.1f), 1f, 1f, SpriteEffects.None, ContentHandler.Textures[ORE_KEY].GetMeanRadius(8), 0, 0, 8, 1, 8, 0, false, ORE_FRAME_DELAY); temp.Animating = true; OreDrops.Add(temp); }
//splits a destroyed large asteroid into a small one static void splitAsteroid(GameObject asteroidToSplit) { //split asteroid into small, inherting most of the characteristics GameObject split = new GameObject( ContentHandler.Textures[SMALL_ASTEROID], asteroidToSplit.WorldCenter, GetVelocity(asteroidToSplit.RotationDegrees + Util.rnd.Next(90, 270)), //get a random new velocity asteroidToSplit.TintColor, false, //nothing to animate asteroidToSplit.Rotation, asteroidToSplit.RotationalVelocity, asteroidToSplit.Scale, asteroidToSplit.Depth, false, ContentHandler.Textures[SMALL_ASTEROID].GetMeanRadius()); //get rounded radius Asteroids.Add(split); }
public static void DestroyAsteroid(GameObject asteroid, bool effect = true) { int x = Util.rnd.Next(50); //temp var //around 50% chance of splitting if asteroid is a large non-ore asteroid if (x > 25 && asteroid.Texture == ContentHandler.Textures[LARGE_ASTEROID]) splitAsteroid(asteroid); if (asteroid.Texture == ContentHandler.Textures[ORE_ASTEROID]) { for (int i = 0; i < Util.rnd.Next(ORE_MIN_DROP, ORE_MAX_DROP); i++) OreManager.AddOreDrop(asteroid); //if it is an ore asteroid, add drop(s) on destroy } if(effect) //add a particle effect if flag is true addExplosion(asteroid.WorldCenter); Asteroids.Remove(asteroid); //remove the asteroid from the list }
//add a specified type asteroid public static void AddAsteroid(AsteroidType type, bool offScreen = false) { GameObject tempAsteroid; //temporary asteroid bool isOverlap = false; //overlap flag int counter = 0; //generation counter Texture2D text; //temporary texture switch (type) //assign appropriate texture to asteroid type { case AsteroidType.Small: text = ContentHandler.Textures[SMALL_ASTEROID]; break; case AsteroidType.Large: text = ContentHandler.Textures[LARGE_ASTEROID]; break; case AsteroidType.Ore: text = ContentHandler.Textures[ORE_ASTEROID]; break; default: throw new InvalidOperationException(); } do //Do-While to ensure that the asteroid gets generated at least once { float rot = MathHelper.ToRadians((float)Util.rnd.NextDouble(0f, 359f)); //random rotation //random rotational velocity; within constants float rotVel = MathHelper.ToRadians((float)Util.rnd.NextDouble(MINROTATIONALVELOCITY, MAXROTATIONALVELOCITY)); float colRadius = text.GetMeanRadius(); Vector2 vel; //temporary velocity Vector2 worldPos; //temporary worldposition if (offScreen) //if asteroid needs to be generated offscreen { SpawnSide side = Util.RandomEnumValue<SpawnSide>(); //pick a random world border to spawn it from switch (side) { case SpawnSide.Up: vel = GetVelocity(MathHelper.ToRadians((float)Util.rnd.Next(140, 230))); //get a velocity pointing between 140/230 degrees worldPos = new Vector2( //and add a velocity which will knock it into the world borders next tick Util.rnd.Next(Camera.WorldRectangle.X, Camera.WorldRectangle.Width), Camera.WorldRectangle.Y - text.Height); break; case SpawnSide.Left: vel = GetVelocity(MathHelper.ToRadians((float)Util.rnd.Next(50, 130))); //between 50/130 degrees worldPos = new Vector2( Camera.WorldRectangle.X - text.Width, Util.rnd.Next(Camera.WorldRectangle.Y, Camera.WorldRectangle.Height)); break; case SpawnSide.Right: vel = GetVelocity(MathHelper.ToRadians((float)Util.rnd.Next(230, 310))); //between 230/310 degrees worldPos = new Vector2( Camera.WorldRectangle.Width + text.Width, Util.rnd.Next(Camera.WorldRectangle.Y, Camera.WorldRectangle.Height)); break; case SpawnSide.Down: vel = GetVelocity( MathHelper.ToRadians(Util.rnd.Next(320, 410) % 360)); //between 320/(360 + 50) degrees worldPos = new Vector2( Util.rnd.Next(Camera.WorldRectangle.X, Camera.WorldRectangle.Width), Camera.WorldRectangle.Height + text.Height); break; default: throw new InvalidOperationException(); } } else //if the asteroid does not need to be generated offscreen... { vel = GetVelocity(rot); //get a random velocity according to the rotation worldPos = new Vector2( //and simply get a random position in the world to place it... Util.rnd.Next(Camera.WorldRectangle.X, Camera.WorldRectangle.Width), Util.rnd.Next(Camera.WorldRectangle.Y, Camera.WorldRectangle.Height)); } tempAsteroid = new GameObject( //init a temporary asteroid to check for overlaps text, worldPos, vel, Color.White, false, rot, rotVel, 1f, ASTEROID_DRAW_DEPTH, false, text.GetMeanRadius()); foreach (GameObject asteroid in Asteroids) { if (tempAsteroid.BoundingBox.Intersects(asteroid.BoundingBox) || tempAsteroid.BoundingCircle.Intersects(Player.SpawnCircle)) { isOverlap = true; //flag if overlapping break; //and break; no need to check all other asteroids } } counter++; //increase counter } while (isOverlap && counter < MAX_TRIES); //if overlapping, loop, if maxtries exceeded, quit if (counter >= MAX_TRIES) { return; } else { Asteroids.Add(tempAsteroid); //add the temp asteroid if not at maxtries } }
//simple bounding circle collision detection check public bool IsCircleColliding(GameObject obj) { if (BoundingCircle.Intersects(obj.BoundingCircle)) return true; else return false; }
//tests for both bb and bc collisions with another game object public bool IsCircleAndBoxColliding(GameObject obj) { if (IsBoxColliding(obj) && IsCircleColliding(obj)) return true; return false; }
//overload of previous which takes a GameObject instead of a rectangle public bool IsBoxColliding(GameObject obj) { if (BoundingBox.Intersects(obj.BoundingBox)) return true; else return false; }
//overload with x/rotation offset public static Vector2 GetOffset(GameObject root, float radius, float rotation) { Vector2 temp = (root.Rotation + MathHelper.ToRadians(rotation)).RotationToVector(); temp *= radius; return root.WorldCenter + temp; }
//find the specified offset of a rotated root object public static Vector2 GetOffset(GameObject root, float radius) { Vector2 temp = root.rotationToVector(); temp.X *= radius; temp.Y *= radius; return root.WorldCenter + temp; }
//bounce two objects and return a pair public static GameObjectPair Bounce(GameObject obj1, GameObject obj2) { if (obj1.Equals(obj2)) //can't bounce the same object! throw new InvalidOperationException("Identical objects"); Vector2 centerOfMass = (obj1.Velocity + obj2.Velocity) / 2; //calculate the center of mass Vector2 normal1 = GetNormal(new GameObjectPair(obj1, obj2)); Vector2 normal2 = GetNormal(new GameObjectPair(obj2, obj1)); //Bounce Obj1 obj1.Velocity -= centerOfMass; obj1.Velocity = Vector2.Reflect(obj1.Velocity, normal1); obj1.Velocity += centerOfMass; //Bounce Obj2 obj2.Velocity -= centerOfMass; obj2.Velocity = Vector2.Reflect(obj2.Velocity, normal2); obj2.Velocity += centerOfMass; return new GameObjectPair(obj1, obj2); }
public GameObjectPair(GameObject obj1, GameObject obj2) { Object1 = obj1; Object2 = obj2; }
public static bool IsHit(GameObject obj, out Projectile shotHit, FoF_Ident alignment = FoF_Ident.Neutral) { foreach (Projectile shot in Projectiles) //loop through each shot to check if hit { if (shot.Identification != alignment && shot.IsDummyProjectile == false) //check if friendly & not a dummy { if (obj.IsCircleColliding(shot)) //check if colliding { HitEffects.Add(new ParticleEmitter( //add a hit effect EFFECT_MAX_PARTICLES, obj.WorldCenter.Center(shot.WorldCenter), ContentHandler.Textures["particle"].ToTextureList(), EFFECT_COLORS.ToList<Color>(), EFFECT_FRAMES_TO_LIVE, true, true, EFFECT_TIME_TO_EMIT, EFFECT_MAX_PARTICLES / DETONATE_TIME_TO_EMIT, EFFECT_EJECTION_SPEED, EFFECT_RANDOMIZATION, shot.RotationDegrees + 180, EFFECT_SPRAY_WIDTH)); shotHit = shot; //set the out param shot.Active = false; if (shot.DetonateEffect) addDetonateEffect(shot.WorldCenter); return true; //return true } } } shotHit = null; //set the shot to null return false; //and return false }
public static void Initialize() { #region Equipment Definitions Slot1 = LASER_KEY; //set initial equipment Slot2 = TORPEDO_KEY; EquipmentDictionary = new Dictionary<string, EquipmentData>(); //initialize the dictionary //add torpedoes EquipmentDictionary.Add(TORPEDO_KEY, new EquipmentData( ContentHandler.Textures[TORPEDO_KEY], 300, 0f, TORPEDO_KEY, COLLISION_SFX, 2000, 30, 20, 50, 1, 0, "Torpedo Launcher", true, true)); //add lasers EquipmentDictionary.Add(LASER_KEY, new EquipmentData( ContentHandler.Textures[LASER_KEY], 750, 150, LASER_KEY, COLLISION_SFX, 450, 10, 6, 5, 1, 0, "Pulse Laser")); //add shell EquipmentDictionary.Add(SHELL_KEY, new EquipmentData( ContentHandler.Textures[SHELL_KEY], 1000, 300, SHELL_KEY, COLLISION_SFX, 175, 10, 3, 50, 35, 30, "Scatter-Fire", false, true)); //add rapid-fire sliver EquipmentDictionary.Add(SLIVER_KEY, new EquipmentData( ContentHandler.Textures[SLIVER_KEY], 450, 50, SLIVER_KEY, IMPACT_SFX, 400, 1, 5, 1, 2, 45, "Shrapnel Projector")); //add missiles EquipmentDictionary.Add(MISSILE_KEY, new EquipmentData( ContentHandler.Textures[MISSILE_KEY], 1000, 0, MISSILE_KEY, COLLISION_SFX, 500, 20, 10, 30, 1, 40, "Rapid-Missile Launcher", true, true)); #endregion Health = STARTING_HEALTH; CurrentOre = STARTING_ORE; CollectableOre = LevelManager.Levels[0].CollectableOre; ActiveSlot = INITIAL_ACTIVE_SLOT; StabilizeRotation = true; #region Component Initialization //init the ship Ship = new GameObject( ContentHandler.Textures[SHIP_TEXTURE], new Vector2(Camera.WorldRectangle.Width / 2, Camera.WorldRectangle.Height), new Vector2(0, -50), Color.White, false, 0f, 0f, 1f, SHIP_DEPTH, false, ContentHandler.Textures[SHIELD_KEY].GetMeanRadius(), //use the shield texture as a collision boundary 0, 0, SpriteEffects.None, 8, 1, 8, 2, SHIP_FRAME_DELAY); //init the shield overlay Shield = new GameObject( ContentHandler.Textures[SHIELD_KEY], Ship.WorldCenter, Ship.Velocity, Color.Transparent); //init the left-side particle engine trail LeftEngineTrail = new ParticleEmitter( Int32.MaxValue, GameObject.GetOffset(Ship, THRUST_OFFSET, ROTATION_OFFSET), ContentHandler.Textures["particle"].ToTextureList(), TRAIL_COLORS.ToList<Color>(), TRAIL_FTL, false, true, -1, TRAIL_PPT, TRAIL_EJECTION_SPEED, TRAIL_RANDOM_MARGIN, 0f, TRAIL_SPRAYWIDTH); //same for right side RightEngineTrail = new ParticleEmitter( Int32.MaxValue, GameObject.GetOffset(Ship, THRUST_OFFSET, -ROTATION_OFFSET), ContentHandler.Textures["particle"].ToTextureList(), TRAIL_COLORS.ToList<Color>(), TRAIL_FTL, false, true, -1, TRAIL_PPT, TRAIL_EJECTION_SPEED, TRAIL_RANDOM_MARGIN, 0f, TRAIL_SPRAYWIDTH); //explosion particle textures explosionParticles.Add(ContentHandler.Textures["junk1"]); explosionParticles.Add(ContentHandler.Textures["junk2"]); explosionParticles.Add(ContentHandler.Textures["junk3"]); ExplosionEmitter = new ParticleEmitter( EXPLOSION_PARTICLES_TO_EMIT, Ship.WorldCenter, explosionParticles, EXPLOSION_COLORS.ToList<Color>(), EXPLOSION_FTL, false, true, EXPLOSION_TIME_TO_EMIT, EXPLOSION_PARTICLES_TO_EMIT / EXPLOSION_TIME_TO_EMIT, EXPLOSION_EJECTION_SPEED, EXPLOSION_RANDOMIZATION, 0f, 180f); #endregion StoredOre = 100; //TEMP SpawnCircle = new Circle(Ship.WorldCenter, MIN_SPAWN_DISTANCE); }
public NPC( string texturekey, string damagekey, string deathkey, AIState initialState, Vector2 initialPos, Vector2 initialVel, Vector2 initialTarget, Color tintColor, int startingHealth, EquipmentData equip, int colRadius, int activationRadius, float trailOffset, float weaponOffset, float maxSpeed, float trackSpeed, float maxAccelSpeed, float initialRot = 0f, float initialRotVel = 0f, int totalFrames = 0, int rows = 1, int columns = 1, int startingFrame = 0, float frameDelay = 0, FoF_Ident ident = FoF_Ident.Enemy, bool activated = false) { Ship = new GameObject( ContentHandler.Textures[texturekey], initialPos, initialVel, tintColor, false, initialRot, initialRotVel, 1f, NPC_DEPTH, false, colRadius, 0, 0, SpriteEffects.None, totalFrames, rows, columns, startingFrame, frameDelay); Shield = new GameObject( ContentHandler.Textures[texturekey + NPCManager.SHIELD_TEXTURE], Ship.WorldCenter, Ship.Velocity, Color.Transparent, false, Ship.Rotation, Ship.RotationalVelocity, Ship.Scale, Ship.Depth); CurrentState = initialState; LastState = initialState; DamageSoundKey = damagekey; DeathSoundKey = deathkey; Weapon = equip; if (equip != null) { firedelay = equip.RefireDelay; } ActivationRadius = activationRadius; Activated = activated; TrailOffset = trailOffset; WeaponOffset = weaponOffset; MaxSpeed = maxSpeed; TrackSpeed = trackSpeed; AccelerationSpeed = maxAccelSpeed; Target = Vector2.Normalize(initialTarget); Identification = ident; StartingHealth = startingHealth; Health = StartingHealth; trail = new ParticleEmitter( //initialize the engine trail particle emitter TRAIL_MAX_PARTICLES, GameObject.GetOffset(Ship, TrailOffset), ContentHandler.Textures[TRAIL_PARTICLE].ToTextureList(), TRAIL_COLORS.ToList<Color>(), TRAIL_FTL, false, true, -1, TRAIL_PPT, TRAIL_EJECTION_SPEED, TRAIL_RANDOM_MARGIN, Ship.RotationDegrees + 180, TRAIL_SPRAYWIDTH); //initialize the state logic switchState(initialState); //pick a slightly randomized evasion damage threshold dmgThreshold = Util.rnd.Next( EVADE_DMG_THRESHOLD_MIN, EVADE_DMG_THRESHOLD_MAX); reattackTime = Util.rnd.Next( REATTACK_TIME_MIN, REATTACK_TIME_MAX); evadeTime = Util.rnd.Next( EVADE_TIME_MIN, EVADE_TIME_MAX); shotsBeforeCooldown = Util.rnd.Next( COOLDOWN_MIN, COOLDOWN_MAX); shotsCounter = 0; }