b2Vec2 MapController::steeringBehaviourSeparation(Agent &agent) { b2Vec2 totalForce = b2Vec2_zero; int neighboursCount = 0; for (int i = 0; i < agents.size(); i++) { Agent &a = agents[i]; if (&a != &agent) { float32 distance = B2Vec2DHelper::distanceTo(agent.getPosition(), a.getPosition()); if (distance < agent.minSeparation && distance > 0) { b2Vec2 pushForce = agent.getPosition() - a.getPosition(); float32 length = pushForce.Normalize(); //Normalize returns the original length float32 r = (Agent::radius + Agent::radius); totalForce += pushForce * (1 - ((length - r) / (Agent::minSeparation - r)));//agent.minSeparation))); neighboursCount++; } } } if (neighboursCount == 0) { return totalForce; //Zero } return totalForce * (Agent::maxForce / neighboursCount); }
b2Vec2 MapController::steeringBehaviourFlowField(Agent &agent) { b2Vec2 floor = B2Vec2DHelper::floorV(agent.getPosition()); int x = floor.x; int y = floor.y; b2Vec2 f00 = isValid(x, y) ? flow[x][y] : b2Vec2_zero; b2Vec2 f01 = isValid(x, y + 1) ? flow[x][y + 1] : b2Vec2_zero; b2Vec2 f10 = isValid(x + 1, y) ? flow[x + 1][y] : b2Vec2_zero; b2Vec2 f11 = isValid(x + 1, y + 1) ? flow[x + 1][y + 1] : b2Vec2_zero; //Do the x interpolations float32 xWeight = agent.getPosition().x - floor.x; b2Vec2 top = f00 * (1 - xWeight) + f10 * xWeight; b2Vec2 bottom = f01 * (1 - xWeight) + f11 * xWeight; //Do the y interpolation float32 yWeight = agent.getPosition().y - floor.y; //This is now the direction we want to be travelling in (needs to be normalized) b2Vec2 desiredDirection = top * (1 - yWeight) + bottom * yWeight; desiredDirection.Normalize(); //If we are centered on a grid square with no vector this will happen /*if (isnan(desiredDirection.LengthSquared())) { return b2Vec2_zero; }*/ return steerTowards(agent, desiredDirection); }
b2Vec2 MapController::steeringBehaviourSeek(Agent &agent, b2Vec2 dest) { if (dest.x == agent.getPosition().x && dest.y == agent.getPosition().y) { return b2Vec2_zero; } b2Vec2 desired = dest - agent.getPosition(); desired *= (Agent::maxSpeed / desired.Length()); b2Vec2 velocityChange = desired - agent.getVelocity(); return velocityChange * (Agent::maxForce / Agent::maxSpeed); }
b2Vec2 MapController::steeringBehaviourAlignment(Agent &agent) { b2Vec2 averageHeading = b2Vec2_zero; int neighboursCount = 0; //for each of our neighbours (including ourself) for (int i = 0; i < agents.size(); i++) { Agent &a = agents[i]; float32 distance = B2Vec2DHelper::distanceTo(agent.getPosition(), a.getPosition()); //That are within the max distance and are moving if (distance < Agent::maxCohesion && a.getVelocity().Length() > 0 && a.group == agent.group) { //Sum up our headings b2Vec2 head = a.getVelocity(); head.Normalize(); averageHeading += head; neighboursCount++; } } if (neighboursCount == 0) { return averageHeading; //Zero } //Divide to get the average heading averageHeading *= (1 / neighboursCount); //Steer towards that heading return steerTowards(agent, averageHeading); }
b2Vec2 MapController::steeringBehaviourCohesion(Agent &agent) { b2Vec2 centerOfMass = b2Vec2_zero;//agent.position().Copy(); int neighboursCount = 0; for (int i = 0; i < agents.size(); i++) { Agent &a = agents[i]; if (&a != &agent && a.group == agent.group) { float32 distance = B2Vec2DHelper::distanceTo(agent.getPosition(), a.getPosition()); if (distance < Agent::maxCohesion) { //sum up the position of our neighbours centerOfMass += a.body->GetPosition(); neighboursCount++; } } } if (neighboursCount == 0) { return b2Vec2_zero; } //Get the average position of ourself and our neighbours centerOfMass *= (1 / neighboursCount); //seek that position return steeringBehaviourSeek(agent, centerOfMass); }
/** * Agent removes agent in location in group from world and takes resources * It also removes links to agents killed by combat (lenders, borrowers, etc.) * @param loc :Pointer to Location of the winning agent * @param grp : Pointer to Group containing location of losing agent (or possibly an empty location) * @see Combat Rule * @return true if agent exists at loc else false * @exception none */ bool AgentCombat::executeAction(Location *loc, group *grp) { if (loc->hasAgent()) { Agent *winner = grp->getPrimeMover()->getAgent(); //must equal loc->getAgent()! if (grp->getMembers().size()!=0)/*!< we are moving somewhere */ { if (grp->getMembers()[0]->hasAgent()==false) {/*!< moving to empty location */ loc->getAgent()->incSugar(grp->getMembers()[0]->getSugar());/*!< eat sugar at destination */ grp->getMembers()[0]->setSugar(0);/*!< sugar at location is consumed */ } else{ //std::cout <<"COMBAT!"<<std::endl; //1. Update victorious agent resources Agent *loser = grp->getMembers()[0]->getAgent();//only one member in group - the loser winner->incSugar(grp->getMembers()[0]->getReward());//*WHAT IF WE ADD SPICE?* grp->getMembers()[0]->setSugar(0);/*!< sugar at location is consumed */ //2. Kill vanquished agent std::pair<int,int> currPosition=loser->getPosition(); if (loser!=sim->killAgent(currPosition)) { std::cerr << "Delete of agent failed"<<std::endl; } } //Move agent to new position std::pair<int,int> currPosition=winner->getPosition(); sim->setAgent(currPosition, nullptr);//remove old location ptr to agent winner->setPosition(grp->getMembers()[0]->getPosition());//set new position to new location sim->setAgent(grp->getMembers()[0]->getPosition(),winner);//add ptr to agent at new location } else{/*!< we are staying put-not moving */ loc->getAgent()->incSugar(loc->getSugar());/*!< eat sugar at destination */ loc->setSugar(0);/*!< sugar at location is consumed */ } for(auto ag:winner->getChildren())/*!< Remove any links to killed children */ { if (ag->isKilled()) { winner->removeChild(ag); } } winner->removeKilledLoans();/*!< remove loans with killed agents */ winner->removeKilledFather();/*!< remove father link if he is killed */ winner->removeKilledMother();/*!< remove mother link if she is killed */ return true; }else{ return false;/*!< no agent present so did nothing */ } }