public override void DrawRender(RenderContext renderContext, double scale, OrderedPair <double> playerPosition, OrderedPair <double> screenCenter, Graphics graphics) { // OrderedPair<double> offsetPosition = new OrderedPair<double>(source.Position.X + xOffset * scale, source.Position.Y + yOffset * scale); GameObject source = renderContext.Source; double xOffset = source.Position.X - playerPosition.X; double yOffset = source.Position.Y - playerPosition.Y; // Draw source object with accessories on top. if (source.RenderMode == GameObject.RenderContextMode.AccessoryFirst) { graphics.DrawImage(source.GetImage(), source.GetRectangleFWithOffset(screenCenter, xOffset, yOffset, scale)); foreach (GameObject acc in renderContext.Accessories) { if (acc != null) { graphics.DrawImage(acc.GetImage(), acc.GetRectangleFWithOffset(screenCenter, acc.Position.X + xOffset, acc.Position.Y + yOffset, scale)); } } } else // Draw accessories with source object on top. { foreach (GameObject acc in renderContext.Accessories) { if (acc != null) { graphics.DrawImage(acc.GetImage(), acc.GetRectangleFWithOffset(screenCenter, acc.Position.X + xOffset, acc.Position.Y + yOffset, scale)); } } graphics.DrawImage(source.GetImage(), source.GetRectangleFWithOffset(screenCenter, xOffset, yOffset, scale)); } }
public void RenderPlants(Graphics graphics, double scale, OrderedPair <double> origin, OrderedPair <double> center) { foreach (Plant p in Plants) { plantRenderer.DrawRender(p.RenderContext, scale, origin, center, graphics); } }
public void SpawnRandomAnimal() { Animal a; OrderedPair <int> spawnLocation = Utilities.GetRandomPoint(); int x = spawnLocation.X; int y = spawnLocation.Y; AnimalType animalType = UtilityDecider <AnimalType> .WeightedRandomChoice(animalSpawnWeights); switch (animalType) { case AnimalType.Bear: a = Animal.CreateBear(x, y); break; case AnimalType.Wolf: a = Animal.CreateWolf(x, y); break; case AnimalType.Hog: a = Animal.CreateHog(x, y); break; default: a = Animal.CreateGoat(x, y); break; } Console.WriteLine("Spawning a {0}", animalType); EntitiesAdd(a); }
public static double SquaredDistance(OrderedPair <double> p1, OrderedPair <double> p2) { double xDist = p1.X - p2.X; double yDist = p1.Y - p2.Y; return(xDist * xDist + yDist * yDist); }
public override void Do(Entity entity) { double squaredDistance = Utilities.SquaredDistance(entity.Position, fleeObject.Position); if (squaredDistance < entity.VisionRange * entity.VisionRange) { double x = entity.Position.X + entity.Position.X - fleeObject.Position.X; double y = entity.Position.Y + entity.Position.Y - fleeObject.Position.Y; activeAction = new GotoAction(x, y, entity.Size); activeAction.Do(entity); } else { entity.ApplyNeedDeltas(UtilityDeltas); End(); } if (activeAction != null && activeAction.State == ActionState.Failure) // If the entity has hit a wall while running away, head to a random point. { OrderedPair <int> randomPoint = Utilities.GetDirectionalPoint(entity.CollisionDirection, entity.Position); activeAction = new GotoAction(randomPoint.X, randomPoint.Y, entity.Size); } }
public override void Do(Entity entity) { moveTime++; moveAction.Do(entity); // GotoAction checks collision with destination and hitting walls. bool result = moveAction.IsActive; if (moveTime == changeCount) // Change directions after a set time. { moveTime = 0; double d = Utilities.Rng.NextDouble(); if (d < changeProbability) { // Applies goto to set direction to (x, y). Goto applies Move(). False means the entity hit a wall and needs to head to another square. destination = Utilities.GetRandomPoint(); moveAction = new GotoAction(destination.X, destination.Y, entitySize); } else if (d > 0.75) { entity.Stop(); } } // The entity has hit a wall or reached the destination. else if (!result && entity.CollisionDirection != Direction.None) { destination = Utilities.GetDirectionalPoint(entity.CollisionDirection, entity.Position); moveAction = new GotoAction(destination.X, destination.Y, entitySize); } //entity.ApplyNeedDeltas(UtilityDeltas); // Advertise needs deltas to entities but don't actually give them the reward. This is for a default action. }
public void RenderEntities(Graphics graphics, double scale, OrderedPair <double> center) { double xOffset = House.Position.X - Player.Position.X; double yOffset = House.Position.Y - Player.Position.Y; graphics.DrawImage(House.GetImage(), House.GetRectangleFWithOffset(center, xOffset, yOffset, scale)); if (Player.BasePerson != null && Player.BasePerson.Health >= 0) { entityRenderer.DrawRender(Player.BasePerson.RenderContext, scale, Player.Position, center, graphics); Rectangle playerDisplayRectangle = new Rectangle(Utilities.ViewWidth / 2 - Player.BasePerson.CollisionDistance, Utilities.ViewHeight / 2 - Player.BasePerson.CollisionDistance, (int)(Player.BasePerson.Size * scale), (int)(Player.BasePerson.Size * scale)); graphics.DrawRectangle(new Pen(new SolidBrush(Color.Gold), (float)(1.5 * scale)), playerDisplayRectangle); } foreach (Entity en in Entities) { if (en != null) { entityRenderer.DrawRender(en.RenderContext, scale, Player.Position, center, graphics); // Draw a circle representing the entities vision range. Not 100% accurate because object mesh squashes the game space into 0 width cells. //graphics.DrawEllipse(new Pen(new SolidBrush(Color.Black)), en.GetSearchRadius(en.VisionRange)); } } }
// TODO: Use the ObjectMesh to optimize rendering. If the world is big, only need to draw what is inside of the view area. public void Render(Graphics graphics) { // Position of the center of the screen. OrderedPair <double> screenCenter = new OrderedPair <double>(Utilities.ViewWidth / 2, Utilities.ViewHeight / 2); // Position of the center of the world. OrderedPair <double> worldCenter = new OrderedPair <double>(Utilities.WorldWidth / 2, Utilities.WorldHeight / 2); double xOffset, yOffset; PlantController.RenderPlants(graphics, Scale, EntityController.Player.Position, screenCenter); // Render Items and Effects. foreach (GameObject gameObject in Items.Concat(Miscellaneous).Concat(Effects)) { PictureRenderer.DrawRender(gameObject.RenderContext, Scale, EntityController.Player.Position, screenCenter, graphics); } EntityController.RenderEntities(graphics, Scale, screenCenter); // Draw a rectangle to represent the edge of the map. xOffset = worldCenter.X - EntityController.Player.Position.X; yOffset = worldCenter.Y - EntityController.Player.Position.Y; Rectangle wallRectangle = new Rectangle((int)(screenCenter.X + (xOffset - Utilities.WorldWidth / 2) * Scale), (int)(screenCenter.Y + (yOffset - Utilities.WorldHeight / 2) * Scale), (int)(Scale * Utilities.WorldWidth), (int)(Scale * Utilities.WorldHeight)); graphics.DrawRectangle(new Pen(Color.Red), wallRectangle); // Display a circle around the currently selected data object. if (CurrentDataObject != null && DataObjectSelected) { GameObject currentObject; if (CurrentDataObject is EntityController) // House does not need to be highlighted. { return; } if (CurrentDataObject is Player player) { currentObject = player.BasePerson; } else { currentObject = (GameObject)CurrentDataObject; } xOffset = currentObject.Position.X - EntityController.Player.Position.X; yOffset = currentObject.Position.Y - EntityController.Player.Position.Y; graphics.DrawEllipse(new Pen(Color.Red), (int)(screenCenter.X + (xOffset - 7) * Scale), (int)(screenCenter.Y + (yOffset - 7) * Scale), (int)(14 * Scale), (int)(14 * Scale)); } }
public GameObject(double x, double y, int size) { Position = new OrderedPair <double>(x, y); Size = size; CollisionDistance = Size / 2; RenderContext = new RenderContext(this); RenderMode = RenderContextMode.AccessoryFirst; ObjectID = nextObjectID; nextObjectID++; }
public Entity(double speed, int size, double x, double y, Color color, int ageSeconds) : base(x, y, size) { Speed = speed; BaseSpeed = speed; Damage = BaseDamage; IdleAction = new WanderAction(); Color = color; Velocity = new OrderedPair <double>(0, 0); AttackThisAction = new AttackAction(this); FollowThisAction = new FollowAction(this, FollowDistance); base.OnScheduleEvent(this, new ScheduleEventArgs(ageSeconds, new AgeAction())); }
public void CreateObjects(OrderedPair <int> center) { Plant potato = GeneralPlant.Potato(80, 80); List <Plant> yuccaPlants = new List <Plant>(); Plant pineTree1 = GeneralPlant.PineTree(230, 400); List <Plant> appleTrees = new List <Plant> { new AppleTree(center.X + 50, center.Y + 120), new AppleTree(center.X + 180, center.Y + 50) }; for (int i = 0; i < 10; i++) { var p = Utilities.GetRandomPoint(); appleTrees.Add(new AppleTree(p.X, p.Y)); } for (int i = 0; i < 10; i++) { var p = Utilities.GetRandomPoint(); yuccaPlants.Add(GeneralPlant.Yucca(p.X, p.Y)); } List <Plant> plants = new List <Plant>() { potato, pineTree1 } .Concat(appleTrees) .Concat(yuccaPlants) .ToList(); // Spawn shrubs in random locations. for (int i = 0; i < 20; i++) { OrderedPair <int> position = Utilities.GetRandomPoint(); plants.Add(GeneralPlant.Shrub(position.X, position.Y)); } Plants = new List <Plant>(); foreach (Plant plant in plants) { AddPlant(plant); } }
private void SpawnRandomPlant() { Plant p; OrderedPair <int> randomPoint = Utilities.GetRandomPoint(); // TODO: Create a range of random values for different plants to generate. Then use the frequency selection method from UtilityDecider class // to pick the plant to spawn. if (Utilities.Rng.Next(0, 2) == 0) { p = GeneralPlant.PineTree(randomPoint.X, randomPoint.Y); } else { p = GeneralPlant.Yucca(randomPoint.X, randomPoint.Y); } AddPlant(p); }
public event EventHandler CancelData; // Required for IGetData interface. Not used in EntityController. public EntityController(GameTime time, int width, int height) { GameTime = time; Inventory = new List <Item>(); Entities = new List <Entity>(); House = new House(width / 2, height / 2, houseSize); HousePosition = new OrderedPair <int>(width / 2, height / 2); Entity.SetHomePosition(width / 2, height / 2); HouseBox = new RectangleF(HousePosition.X - houseSize / 2, HousePosition.Y - houseSize / 2, houseSize, houseSize); HouseImage = new Bitmap(Utilities.ResourceDirectory + "house.png"); personBrain = new PersonBrain(20, 25, HousePosition, HouseBox); animalBrain = new AnimalBrain(); entityRenderer = new DefaultEntityRenderer(); }
// Add default EntityController controlled objects to the world after WorldController is listening for their creation. public void CreateObjects(OrderedPair <int> center) { Person playerPerson = new Person("Ryan", "Bressette", Sex.Male, center.X - 80, center.Y - 60); Player = new Player(playerPerson); Player.BasePerson.AddItem(new Item(0, 0, ItemType.Rock, 1)); //player.BasePerson.RenderContext.AddAccessory(new Halo(-100, -100)); Person hazel = new Person("Hazel", "Brunelle", Sex.Female, center.X - 100, center.Y - 20, true); OrderedPair <int> position = Utilities.GetRandomPoint(); Animal g = Animal.CreateGoat(position.X, position.Y); position = Utilities.GetRandomPoint(); Animal h = Animal.CreateHog(position.X, position.Y); position = Utilities.GetRandomPoint(); Animal w = Animal.CreateWolf(position.X, position.Y); List <Entity> entities = new List <Entity>() { hazel, g, h, w }; // Spawn random people. for (int i = 0; i < 4; i++) { position = Utilities.GetRandomPointCloseToPoint(HousePosition.X, HousePosition.Y, 100); Sex sex = Utilities.Rng.Next(0, 2) == 0 ? Sex.Male : Sex.Female; Person p = new Person(sex, position.X, position.Y, true); entities.Add(p); } // Add people to the world. EntitiesAdd(Player.BasePerson, false); Player.BasePerson.Age(); foreach (Entity e in entities) { e.Age(); EntitiesAdd(e); } }
public bool Move() { if (!CanMove) { return(false); } double nextXPosition = Position.X + Speed * Velocity.X; double nextYPosition = Position.Y + Speed * Velocity.Y; bool notCollided = true; // Project the next position to ensure it does not cross a boundary. if (nextXPosition < 0 + Boundary.Buffer) // About to cross left boundary: clear x velocity. { Velocity = new OrderedPair <double>(0, Velocity.Y); notCollided = false; CollisionDirection = Direction.Left; } else if (nextXPosition > Boundary.Width - Boundary.Buffer) // About to cross right boundary: clear x velocity. { Velocity = new OrderedPair <double>(0, Velocity.Y); notCollided = false; CollisionDirection = Direction.Right; } if (nextYPosition < 0 + Boundary.Buffer) // About to cross top boundary: clear y velocity. { Velocity = new OrderedPair <double>(Velocity.X, 0); notCollided = false; CollisionDirection = Direction.Up; } else if (nextYPosition > Boundary.Height - Boundary.Buffer) // About to cross bottom boundary: clear y velocity. { Velocity = new OrderedPair <double>(Velocity.X, 0); notCollided = false; CollisionDirection = Direction.Down; } if (notCollided) { Position = new OrderedPair <double>(nextXPosition, nextYPosition); // Next Position is within the boundary. } return(notCollided); }
public override void DrawRender(RenderContext renderContext, double scale, OrderedPair <double> playerPosition, OrderedPair <double> screenCenter, Graphics graphics) { Entity source = (Entity)renderContext.Source; double xOffset = source.Position.X - playerPosition.X; double yOffset = source.Position.Y - playerPosition.Y; graphics.FillRectangle(new SolidBrush(source.Color), source.GetRectangleFWithOffset(screenCenter, xOffset, yOffset, scale)); foreach (GameObject acc in renderContext.Accessories) { // Draw accessories relative to the center of each Entity. The center will not move under scaling. if (acc != null) { graphics.DrawImage(acc.GetImage(), acc.GetRectangleFWithOffset(screenCenter, acc.Position.X + xOffset, acc.Position.Y + yOffset, scale)); } } }
// Get Data from the object at the specified point. public WorldClickData GetObjectData(Point point, bool altData) { mousePoint = point; bool itemsAccessible = false; OrderedPair <int> screenCenter = new OrderedPair <int>(Utilities.ViewWidth / 2, Utilities.ViewHeight / 2); point = new Point((int)((point.X - screenCenter.X) / Scale + EntityController.Player.Position.X), (int)((point.Y - screenCenter.Y) / Scale + EntityController.Player.Position.Y)); // Check if the mouse was clicked on the house first. if (EntityController.ClickOnHouse(point.X, point.Y, out ObjectData houseData)) { canSwap = false; DataObjectSelected = true; CurrentDataObject = EntityController; itemsAccessible = true; } else { // Check if the mouse was clicked over a valid GameObject. See "GetObjectAtPoint" for options. GameObject targetObject = GetObjectAtPoint(point, g => g is IGetData); if (targetObject == null) { DataObjectSelected = false; return(null); } canSwap = PlayerIsDead && targetObject is Person; DataObjectSelected = true; // Player has player specific data and person specific data. Use mod key to access player data. if (altData && targetObject is Person person && person == EntityController.Player.BasePerson) { CurrentDataObject = EntityController.Player; itemsAccessible = true; }
public PersonBrain(int personLimit, int desiredFoodCount, OrderedPair <int> housePosition, RectangleF houseBox) { this.personLimit = personLimit; this.desiredFoodCount = desiredFoodCount; this.housePosition = housePosition; houseRectangle = houseBox; Tasks = new List <Task>(); utilityDecider = new UtilityDecider <Need>(); utilityDecider.AddResponseFunction(Need.Hunger, x => x); utilityDecider.AddResponseFunction(Need.Social, x => x); utilityDecider.AddResponseFunction(Need.Lust, x => x); utilityDecider.AddResponseFunction(Need.Tiredness, x => x); utilityDecider.AddResponseFunction(Need.Boredom, x => x); utilityDecider.AddResponseFunction(Need.JobFullfilment, x => x); dropUtility = new ActionUtility(new DropAction(houseRectangle), new Tuple <Need, double>[] { ActionUtility.NewPair(Need.JobFullfilment, DDeltaConfig.dropFoodDelta) }); }
public abstract void DrawRender(RenderContext renderContext, double scale, OrderedPair <double> playerPosition, OrderedPair <double> screenCenter, Graphics graphics);
public List <GameObject> GetObjectsInRange(OrderedPair <double> position, int searchRadius) => GetObjectsInRange(position.X, position.Y, searchRadius);
public Effect(int x, int y, EffectType type, int offset, bool isFinite) : base(x, y, GetSize(type)) { Type = type; Position = new OrderedPair <double>(x + offset - CollisionDistance, y - offset - CollisionDistance); IsFinite = isFinite; }
// Returns the rectangle bounding box for the GameObject shifted by the x and y offsets away from the source position. The offsets are scaled. public virtual RectangleF GetRectangleFWithOffset(OrderedPair <double> sourcePosition, double xOffset, double yOffset, double scale) { return(new RectangleF((float)(sourcePosition.X + (xOffset - CollisionDistance) * scale), (float)(sourcePosition.Y + (yOffset - CollisionDistance) * scale), (float)(scale * Size), (float)(scale * Size))); }
// Get a random point inside the width and height analytically using polar coordinates. // Generate a random angle based on the collision direction and then use trigonmetry to calculate the maximum distance within the screen. // Point is (distance * sin(angle), distance * cos(angle)) // Breaks when they get close to (0, 0) for some reason... public static OrderedPair <int> GetDirectionalPoint(Direction direction, OrderedPair <double> position) { if (direction == Direction.None) { Console.WriteLine("Direction was None inside Utilities.GetDirectionalPoint"); return(new OrderedPair <int>((int)position.X, (int)position.Y)); } double theta1; double theta2; double angle; double distance; if (direction == Direction.Left) { theta1 = Math.Atan((position.Y - ViewHeight) / ViewWidth); theta2 = Math.Atan(position.Y / ViewWidth); angle = Rng.Next(-89, 90) * Math.PI / 180.0; if (angle > theta2) { distance = Math.Abs(position.Y / Math.Sin(angle)); } else if (angle < theta1) { distance = Math.Abs((ViewHeight - position.Y) / Math.Sin(angle)); } else { distance = Math.Abs(ViewWidth / Math.Cos(angle)); } } else if (direction == Direction.Up) { theta1 = -Math.PI + Math.Atan(ViewHeight / position.X); theta2 = Math.Atan(-ViewHeight / (ViewWidth - position.X)); angle = Rng.Next(181, 360) * Math.PI / 180.0; angle -= (2.0 * Math.PI); if (angle > theta2) { distance = Math.Abs((ViewWidth - position.X) / Math.Cos(angle)); } else if (angle < theta1) { distance = Math.Abs(position.X / Math.Cos(angle)); } else { distance = Math.Abs(ViewHeight / Math.Sin(angle)); } } else if (direction == Direction.Right) { theta1 = Math.PI + Math.Atan(position.Y / -ViewWidth); theta2 = -Math.PI + Math.Atan((ViewHeight - position.Y) / ViewWidth); angle = Rng.Next(91, 270) * Math.PI / 180.0; if (angle > theta2 + 2.0 * Math.PI) // Adjust theta2 to positive again. { distance = Math.Abs((ViewHeight - position.Y) / Math.Sin(angle)); } else if (angle < theta1) { distance = Math.Abs(position.Y / Math.Sin(angle)); } else { distance = Math.Abs(ViewWidth / Math.Cos(angle)); } } else // Direction.Down. { theta1 = Math.Atan(ViewHeight / (ViewWidth - position.X)); theta2 = Math.PI - Math.Atan(ViewHeight / position.X); angle = Rng.Next(1, 180) * Math.PI / 180.0; if (angle > theta2) { distance = Math.Abs(position.X / Math.Cos(angle)); } else if (angle < theta1) { distance = Math.Abs((ViewWidth - position.X) / Math.Cos(angle)); } else { distance = Math.Abs(ViewHeight / Math.Sin(angle)); } } int x = Math.Max(2, (int)(Math.Abs(distance * Math.Cos(angle)))); int y = Math.Max(2, (int)(Math.Abs(distance * Math.Sin(angle)))); //int x = (int)(Math.Abs(distance * Math.Cos(angle))); //int y = (int)(Math.Abs(distance * Math.Sin(angle))); OrderedPair <int> destination = new OrderedPair <int>(x, y); //Console.WriteLine("Heading to {0},{1}", destination.X, destination.Y); //Console.WriteLine("T1: {0}, T2: {1}, angle: {2}, position: {3}", theta1 * 180.0 / Math.PI, theta2 * 180.0 / Math.PI, angle * 180.0 / Math.PI, position.ToString()); return(destination); }
public static OrderedPair <double> Minus(this OrderedPair <double> p1, OrderedPair <double> p2) { return(new OrderedPair <double>(p1.X - p2.X, p1.Y - p2.Y)); }
public static OrderedPair <double> Plus(this OrderedPair <double> p1, OrderedPair <double> p2) { return(new OrderedPair <double>(p1.X + p2.X, p1.Y + p2.Y)); }
public static void SetHomePosition(int x, int y) { HomePosition = new OrderedPair <int>(x, y); }
public void SetVelocity(OrderedPair <double> velocity) { Velocity = velocity; }
public void Stop() { Velocity = new OrderedPair <double>(0, 0); }
public static int Dot(this OrderedPair <int> p1, OrderedPair <int> p2) { return(p1.X * p2.X + p1.Y * p2.Y); }
public static double Dot(this OrderedPair <double> p1, OrderedPair <double> p2) { return(p1.X * p2.X + p1.Y * p2.Y); }