AI - Crowd Simulation(集群模拟)

类似鱼群,鸟群这种群体运动模拟。
是Microscopic Models 微观模型,定义每一个个体的行为,然后合在一起。
主要是根据一定范围内族群其他对象的运动状态决定自己的运动状态

Cohesion

保证个体不会脱离群体
求物体一定半径范围内的其他临近物体的所有位置,相加取平均位置,用这个位置进行一个追寻力seek

//求物体一定半径范围内的其他临近物体的所有位置,用这个位置进行一个追寻力seek
Vec2 MoveNode::cohesion() {Vec2 averagePos = Vec2::ZERO;int count = 0;for (auto obj : _cohesionObj) {if (obj->getId() != _id) {averagePos += obj->getPosition();count++;}}if (count > 0) { averagePos *= (1 / (float)count); return seek(averagePos) * _cohesionWeight;}return Vec2::ZERO;
}

一定范围内的个体会自发的聚集在一起
请添加图片描述

separation

保证个体不会聚集太密
求物体一定半径范围内的其他临近物体的位置,用当前物体位置分别减去临近物体位置,获取单位方向向量,乘以根据距离远近算出来的权重
越近权重越大。在把所有向量相加取平均值

Vec2 MoveNode::separation() {Vec2 steering = Vec2::ZERO;int count = 0;for (auto obj : _separationObj) {if (obj->getId() != _id) {float dist = this->getPosition().getDistance(obj->getPosition());Vec2 normalVector = (this->getPosition() - obj->getPosition()).getNormalized();Vec2 desiredVelocity = normalVector;desiredVelocity *= (1 / dist);steering += desiredVelocity;count++;}}if (count > 0) steering *= (1 / (float)count);return steering * _dtSpeed * _separationWeight;
}

一定范围内的个体会逐渐分散开来
请添加图片描述

alignment

保证个体的运动方向是跟随群体的
求物体一定半径范围内的其他临近物体的所有速度向量,相加取平均值

Vec2 MoveNode::alignment() {Vec2 steering = Vec2::ZERO;int count = 0;for (auto obj : _alignmentObj) {if (obj->getId() != _id) {steering += obj->getVelocity();count++;}}if (count > 0) steering *= (1 / (float)count);return steering * _alignmentWeight;
}

可以看到一开始各自不同移动方向的个体,在靠近群体的时候,逐渐跟随上群体的方向
请添加图片描述

合并效果

给三种力分别设置不同的权重,组合在一起可以对比群体运动的效果

node->setCohesionWeight(0.5);
node->setSeparationWeight(30);
node->setAlignmentWeight(0);

对齐力权重为0,即只有聚集力和分散力
集群只是聚成一团,但并没有一个整体的运动方向
请添加图片描述

node->setCohesionWeight(0.5);
node->setSeparationWeight(0);
node->setAlignmentWeight(1);

分散力权重为0,即只有聚集力和对齐力
集群几乎直接聚集成同一个点,进行移动
请添加图片描述

node->setCohesionWeight(0);
node->setSeparationWeight(30);
node->setAlignmentWeight(1);

聚集力权重为0,即只有分散力和对齐力
个体会随着周围的群体方向行进,但是容易散开来
请添加图片描述

node->setCohesionWeight(0.5);
node->setSeparationWeight(30);
node->setAlignmentWeight(1);

三种力都有的
可以通过对三种力设置不同的权重来控制集群的密集程度运动轨迹
请添加图片描述

我这里是简单粗暴的把所有物体加入遍历来筛选周围物体,实际项目中需要各种优化如AOI等来减少遍历的个数

源码

CrowdSimulation.h

#ifndef __CROWD_SIMULATION_SCENE_H__
#define __CROWD_SIMULATION_SCENE_H__#include "cocos2d.h"
#include "MoveNodeManager.h"
USING_NS_CC;
using namespace std;class CrowdSimulationScene : public Scene
{
public:static Scene* createScene();virtual bool init();virtual bool onTouchBegan(Touch* touch, Event* unused_event);void setSeekPos(Vec2 seekPos);void setFleePos(Vec2 fleePos);void setWanderPos(Vec2 wanderPos);void showPursuitModel(Vec2 tarPos);void showCombineModel(Vec2 tarPos);void showCohsionModel();void showSeparationModel();void showAlignmentModel();void showCrowdModel();// implement the "static create()" method manuallyCREATE_FUNC(CrowdSimulationScene);void update(float dt);protected:EventListenerTouchOneByOne* _touchListener;Vec2 _touchBeganPosition;DrawNode* _mapDrawNode;DrawNode* _mapDrawNode1;MoveNodeManager* _manager;MoveNode* _moveNode;MoveNode* _moveNode1;vector<MoveNode*> _fleeNodes;bool _isDrawMoveLine;
};#endif

CrowdSimulation.cpp

#include "CrowdSimulationScene.h"Scene* CrowdSimulationScene::createScene()
{return CrowdSimulationScene::create();
}static void problemLoading(const char* filename)
{printf("Error while loading: %s\n", filename);printf("Depending on how you compiled you might have to add 'Resources/' in front of filenames in CrowdSimulationScene.cpp\n");
}// on "init" you need to initialize your instance
bool CrowdSimulationScene::init()
{//// 1. super init firstif (!Scene::init()){return false;}auto visibleSize = Director::getInstance()->getVisibleSize();Vec2 origin = Director::getInstance()->getVisibleOrigin();auto layer = LayerColor::create(Color4B(255, 255, 255, 255));layer:setContentSize(visibleSize);this->addChild(layer);_mapDrawNode = DrawNode::create();this->addChild(_mapDrawNode);_mapDrawNode1 = DrawNode::create();this->addChild(_mapDrawNode1);_touchListener = EventListenerTouchOneByOne::create();_touchListener->setSwallowTouches(true);_touchListener->onTouchBegan = CC_CALLBACK_2(CrowdSimulationScene::onTouchBegan, this);this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(_touchListener, layer);_manager = new MoveNodeManager();this->scheduleUpdate();return true;
}bool CrowdSimulationScene::onTouchBegan(Touch* touch, Event* event)
{_touchBeganPosition = touch->getLocation();CCLOG("==========°∑ %f£¨ %f", _touchBeganPosition.x, _touchBeganPosition.y);//    setSeekPos(_touchBeganPosition);//setFleePos(_touchBeganPosition);
//    setWanderPos(_touchBeganPosition);
//    showPursuitModel(_touchBeganPosition);
//    showCombineModel(_touchBeganPosition);
//    showCohsionModel();
//    showSeparationModel();
//    showAlignmentModel();showCrowdModel();return true;
}void CrowdSimulationScene::update(float dt) {if (_isDrawMoveLine && _moveNode->getVelocity() != Vec2::ZERO) _mapDrawNode->drawDot(_moveNode->getPosition(), 3, Color4F(0, 0, 0, 1));_mapDrawNode1->clear();for (auto e : _fleeNodes) {_mapDrawNode1->drawDot(e->getPosition(), 100, Color4F(1, 1, 0, 0.3));}
}void CrowdSimulationScene::setSeekPos(Vec2 seekPos) {if (_moveNode == nullptr) {_moveNode = _manager->getPlayer();_moveNode->setPos(Vec2(100, 100));this->addChild(_moveNode);_isDrawMoveLine = true;}_moveNode->setTarPos(seekPos);_mapDrawNode->clear();_mapDrawNode->drawDot(seekPos, 150, Color4F(0, 1, 1, 0.3));_mapDrawNode->drawDot(seekPos, 10, Color4F(0, 1, 1, 1));
}void CrowdSimulationScene::setFleePos(Vec2 fleePos) {if (_moveNode == nullptr) {_moveNode = _manager->getPlayer();_moveNode->setPos(Vec2(100, 100));this->addChild(_moveNode);_isDrawMoveLine = true;}_moveNode->setFleePos(_touchBeganPosition);_mapDrawNode->clear();_mapDrawNode->drawDot(_touchBeganPosition, 100, Color4F(0, 0, 1, 0.3));_mapDrawNode->drawDot(_touchBeganPosition, 10, Color4F(0, 0, 1, 1));
}void CrowdSimulationScene::setWanderPos(Vec2 wanderPos) {if (_moveNode == nullptr) {_moveNode = _manager->getWanderNode();this->addChild(_moveNode);}_moveNode->setWanderPos(wanderPos);_mapDrawNode->clear();_mapDrawNode->drawDot(wanderPos, 200, Color4F(1, 1, 0, 0.3));
}void CrowdSimulationScene::showPursuitModel(Vec2 tarPos){if (_moveNode == nullptr) {_moveNode = _manager->getPlayer();this->addChild(_moveNode);_moveNode1 = _manager->getPursuitNode();this->addChild(_moveNode1);}_moveNode->setPos(Vec2(100, 100));_moveNode1->setPos(Vec2(100, 500));_moveNode1->switchPursuitObj(_moveNode);setSeekPos(tarPos);
}void CrowdSimulationScene::showCombineModel(Vec2 tarPos) {if (_moveNode == nullptr) {_moveNode = _manager->getPlayer();_moveNode->setPos(Vec2(100, 100));this->addChild(_moveNode);_isDrawMoveLine = true;vector<Vec2> wanderPos = { Vec2(300, 300), Vec2(300, 600), Vec2(450,450),Vec2(600,640),Vec2(500,200),Vec2(650,400),Vec2(850,550) };for (auto v : wanderPos) {auto fleeNode = _manager->getFleeNode();this->addChild(fleeNode);fleeNode->setWanderPos(v);_fleeNodes.push_back(fleeNode);_mapDrawNode1->drawDot(v, 100, Color4F(1, 1, 0, 0.3));}_moveNode->setFleeObjs(_fleeNodes);}setSeekPos(tarPos);
}void CrowdSimulationScene::showCohsionModel() {if (_manager->getFlockObjs().empty()) {for (int i = 0; i < 30; i++) {auto cohesionObj = _manager->getCohesionNode();this->addChild(cohesionObj);/*float x = RandomHelper::random_real<float>(200, 1200);float y = RandomHelper::random_real<float>(200, 500);cohesionObj->setPos(Vec2(x, y));*/}}auto objs = _manager->getFlockObjs();for (auto obj : objs) {float x = RandomHelper::random_real<float>(200, 1200);float y = RandomHelper::random_real<float>(200, 500);obj->setPos(Vec2(x, y));}
}void CrowdSimulationScene::showSeparationModel() {if (_manager->getFlockObjs().empty()) {for (int i = 0; i < 30; i++) {auto separationObj = _manager->getSeparationNode();this->addChild(separationObj);/*float x = RandomHelper::random_real<float>(650, 700);float y = RandomHelper::random_real<float>(250, 300);separationObj->setPos(Vec2(x, y));*/}}auto objs = _manager->getFlockObjs();for (auto obj : objs) {float x = RandomHelper::random_real<float>(650, 700);float y = RandomHelper::random_real<float>(250, 300);obj->setPos(Vec2(x, y));}
}void CrowdSimulationScene::showAlignmentModel() {if (_manager->getFlockObjs().empty()) {for (int i = 0; i < 30; i++) {auto separationObj = _manager->getAlignmentNode();this->addChild(separationObj);/*float x = RandomHelper::random_real<float>(400, 800);float y = RandomHelper::random_real<float>(200, 400);separationObj->setPos(Vec2(x, y));auto angle = RandomHelper::random_real<float>(0, 360);float rad = angle * M_PI / 180;float len = 1;Vec2 v;v.x = len * cos(rad);v.y = len * sin(rad);separationObj->setVelocity(v);*/}}auto objs = _manager->getFlockObjs();for (auto obj : objs) {float x = RandomHelper::random_real<float>(100, 1300);float y = RandomHelper::random_real<float>(100, 540);obj->setPos(Vec2(x, y));auto angle = RandomHelper::random_real<float>(0, 360);float rad = angle * M_PI / 180;float len = 1;Vec2 v;v.x = len * cos(rad);v.y = len * sin(rad);obj->setVelocity(v);}
}void CrowdSimulationScene::showCrowdModel() {if (_manager->getFlockObjs().empty()) {for (int i = 0; i < 30; i++) {auto flockNode = _manager->getFlockNode();this->addChild(flockNode);/*float x = RandomHelper::random_real<float>(100, 1300);float y = RandomHelper::random_real<float>(100, 540);flockNode->setPos(Vec2(x, y));auto angle = RandomHelper::random_real<float>(0, 360);float rad = angle * M_PI / 180;float len = 1;Vec2 v;v.x = len * cos(rad);v.y = len * sin(rad);flockNode->setVelocity(v);*/}}auto objs = _manager->getFlockObjs();for (auto obj : objs) {float x = RandomHelper::random_real<float>(100, 1300);float y = RandomHelper::random_real<float>(100, 540);obj->setPos(Vec2(x, y));auto angle = RandomHelper::random_real<float>(0, 360);float rad = angle * M_PI / 180;float len = 1;Vec2 v;v.x = len * cos(rad);v.y = len * sin(rad);obj->setVelocity(v);}
}

MoveNodeManager.h

#ifndef __MOVE_NODE_MANAGER_H__
#define __MOVE_NODE_MANAGER_H__#include "cocos2d.h"
#include "MoveNode.h"
USING_NS_CC;
using namespace std;class MoveNodeManager
{
public:MoveNode* getPlayer();MoveNode* getWanderNode();MoveNode* getPursuitNode();MoveNode* getFleeNode();MoveNode* getCohesionNode();MoveNode* getSeparationNode();MoveNode* getAlignmentNode();MoveNode* getFlockNode();vector<MoveNode*> getFlockObjs() { return _flockObjs; };protected:int _id = 0;vector<MoveNode*> _flockObjs;
};#endif

MoveNodeManager.cpp

#include "MoveNodeManager.h"MoveNode* MoveNodeManager::getPlayer() {auto node = MoveNode::create();node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 0, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 1, 1, 1));node->setSpeed(400);node->setMaxForce(20);node->setMass(10);node->setMaxSpeed(400);node->setTarSlowRadius(150);node->setFleeRadius(100);return node;
}MoveNode* MoveNodeManager::getWanderNode() {auto node = MoveNode::create();node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 1, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 0, 1, 1));node->setSpeed(400);node->setMaxForce(20);node->setMass(20);node->setMaxSpeed(100);node->setCircleDistance(30);node->setCircleRadius(15);node->setChangeAngle(180);node->setWanderRadius(200);node->setWanderPullBackSteering(50);return node;
}MoveNode* MoveNodeManager::getPursuitNode() {auto node = MoveNode::create();node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 1, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 0, 1, 1));node->setSpeed(400);node->setMaxForce(20);node->setMass(10);node->setMaxSpeed(400);return node;
}MoveNode* MoveNodeManager::getFleeNode() {auto node = MoveNode::create();node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 1, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 0, 1, 1));node->setSpeed(400);node->setMaxForce(20);node->setMass(10);node->setMaxSpeed(50);node->setCircleDistance(30);node->setCircleRadius(15);node->setChangeAngle(180);node->setWanderRadius(200);node->setWanderPullBackSteering(50);return node;
}MoveNode* MoveNodeManager::getCohesionNode() {auto node = MoveNode::create();_flockObjs.push_back(node);node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 0, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 1, 1, 1));node->setSpeed(300);node->setMaxForce(20);node->setMass(20);node->setMaxSpeed(50);node->setFleeRadius(50);node->setAllObj(&_flockObjs);node->setCohesionRadius(100);return node;
}MoveNode* MoveNodeManager::getSeparationNode() {auto node = MoveNode::create();_flockObjs.push_back(node);node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 0, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 1, 1, 1));node->setSpeed(300);node->setMaxForce(20);node->setMass(20);node->setMaxSpeed(50);node->setFleeRadius(50);node->setAllObj(&_flockObjs);node->setSeparationRadius(30);return node;
}MoveNode* MoveNodeManager::getAlignmentNode() {auto node = MoveNode::create();_flockObjs.push_back(node);node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 0, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 1, 1, 1));node->setSpeed(300);node->setMaxForce(20);node->setMass(20);node->setMaxSpeed(150);node->setFleeRadius(50);node->setAllObj(&_flockObjs);node->setAlignmentRadius(150);return node;
}MoveNode* MoveNodeManager::getFlockNode() {auto node = MoveNode::create();_flockObjs.push_back(node);node->setId(_id);_id++;auto body = DrawNode::create();node->addChild(body);body->drawDot(Vec2(0, 0), 10, Color4F(0, 0, 0, 1));auto direct = DrawNode::create();node->addChild(direct);node->setDirect(direct);direct->drawDot(Vec2(0, 0), 3, Color4F(1, 1, 1, 1));node->setSpeed(300);node->setMaxForce(20);node->setMass(20);node->setMaxSpeed(100);node->setFleeRadius(50);node->setAllObj(&_flockObjs);node->setCohesionRadius(100);node->setSeparationRadius(40);node->setAlignmentRadius(50);node->setCohesionWeight(0.5);node->setSeparationWeight(30);node->setAlignmentWeight(1);return node;
}

MoveNode.h

#ifndef __MOVE_NODE_H__
#define __MOVE_NODE_H__#include "cocos2d.h"
USING_NS_CC;
using namespace std;class MoveNode : public Node
{
public:static MoveNode* create();CC_CONSTRUCTOR_ACCESS:virtual bool init() override;void setId(int id) { _id = id; };void setDirect(DrawNode* direct) { _direct = direct; };void setSpeed(float speed) { _speed = speed; };void setMaxForce(float maxForce) { _maxForce = maxForce; };void setMass(float mass) { _mass = mass; };void setMaxSpeed(float maxSpeed) { _maxSpeed = maxSpeed; };void setTarSlowRadius(float tarSlowRadius) { _tarSlowRadius = tarSlowRadius; };void setFleeRadius(float fleeRadius) { _fleeRadius = fleeRadius; };void setCircleDistance(float circleDistance) { _circleDistance = circleDistance; };void setCircleRadius(float circleRadius) { _circleRadius = circleRadius; };void setChangeAngle(float changeAngle) { _changeAngle = changeAngle; };void setWanderRadius(float wanderRadius) { _wanderRadius = wanderRadius; };void setWanderPullBackSteering(float wanderPullBackSteering) { _wanderPullBackSteering = wanderPullBackSteering; };void setPos(Vec2 pos);void setTarPos(Vec2 tarPos) { _tarPos = tarPos; };void setFleePos(Vec2 fleePos) { _fleePos = fleePos; };void setFleeObjs(vector<MoveNode*> fleeObjs) { _fleeObjs = fleeObjs; };void setWanderPos(Vec2 wanderPos);void switchPursuitObj(MoveNode* pursuitObj);void setAllObj(vector<MoveNode*>* allObj) { _allObj = allObj; };void setCohesionRadius(float cohesionRadius) { _cohesionRadius = cohesionRadius; };void setSeparationRadius(float separationRadius) { _separationRadius = separationRadius; };void setAlignmentRadius(float alignmentRadius) { _alignmentRadius = alignmentRadius; };void setCohesionWeight(float cohesionWeight) { _cohesionWeight = cohesionWeight; };void setSeparationWeight(float separationWeight) { _separationWeight = separationWeight; };void setAlignmentWeight(float alignmentWeight) { _alignmentWeight = alignmentWeight; };Vec2 seek(Vec2 seekPos);Vec2 flee();Vec2 wander();Vec2 pursuit();Vec2 cohesion();Vec2 separation();Vec2 alignment();Vec2 wallAvoid();Vec2 turncate(Vec2 vector, float maxNumber);Vec2 changeAngle(Vec2 vector, float angle);void updatePos();void update(float dt);void findNeighbourObjs();int getId() { return _id; };Vec2 getVelocity(){ return _velocity; };void setVelocity(Vec2 velocity) { _velocity = velocity; };
protected:DrawNode* _direct;int _id;float _speed; //速度float _maxForce; //最大转向力,即最大加速度float _mass; //质量float _maxSpeed; //最大速度float _tarSlowRadius; //抵达目标减速半径float _fleeRadius; //逃离目标范围半径float _circleDistance; //巡逻前方圆点距离float _circleRadius; //巡逻前方圆半径float _changeAngle; //巡逻转向最大角度float _wanderRadius; //巡逻点范围半径float _wanderPullBackSteering; //超出巡逻范围拉回力float _alignmentRadius; //方向对齐判断的范围半径float _cohesionRadius; //聚集判断的范围半径float _separationRadius; //分离判断得范围半径float _alignmentWeight = 1.0f; //方向对齐力权重float _cohesionWeight = 1.0f; //聚集力权重float _separationWeight = 1.0f; //分离力权重float _dtSpeed; //每帧速度值Vec2 _velocity; //速度float _wanderAngle; //巡逻角度Vec2 _wanderPos; //巡逻范围中心点Vec2 _tarPos; //目标点Vec2 _fleePos; //逃离点MoveNode* _pursuitObj; //追逐目标vector<MoveNode*> _fleeObjs; //逃离目标vector<MoveNode*>* _allObj; //所有对象vector<MoveNode*> _alignmentObj; //方向对齐目标vector<MoveNode*> _cohesionObj; //聚集目标vector<MoveNode*> _separationObj; //分离目标float wallAvoidRadius = 50.0f; //墙壁碰撞检测半径
};#endif

MoveNode.cpp

#include "MoveNode.h"bool MoveSmooth = true;MoveNode* MoveNode::create() {MoveNode* moveNode = new(nothrow) MoveNode();if (moveNode && moveNode->init()) {moveNode->autorelease();return moveNode;}CC_SAFE_DELETE(moveNode);return nullptr;
}bool MoveNode::init()
{_tarPos = Vec2(-1, -1);_wanderPos = Vec2(-1, -1);_velocity.setZero();_pursuitObj = nullptr;this->scheduleUpdate();return true;
}void MoveNode::update(float dt)
{findNeighbourObjs();_dtSpeed = _speed * dt;if (MoveSmooth) {Vec2 steering = Vec2::ZERO;steering += seek(_tarPos);steering += flee();steering += wander();steering += pursuit();steering += cohesion();steering += separation();steering += alignment();steering = turncate(steering, _maxForce);steering *= ( 1 / (float)_mass );_velocity += steering;}else {_velocity += seek(_tarPos);_velocity += flee();_velocity += wander();_velocity += pursuit();_velocity += cohesion();_velocity += separation();_velocity += alignment();}_velocity += wallAvoid();_velocity = turncate(_velocity, _maxSpeed * dt);updatePos();
}Vec2 MoveNode::wallAvoid() {Vec2 temp = _velocity.getNormalized();temp *= wallAvoidRadius;Vec2 tarPos = this->getPosition() + temp;if (!Rect(Vec2::ZERO, Director::getInstance()->getVisibleSize()).containsPoint(tarPos)) {Vec2 steering = Vec2::ZERO;if (tarPos.y >= Director::getInstance()->getVisibleSize().height) steering += Vec2(0, -1);if (tarPos.y <= 0) steering += Vec2(0, 1);if (tarPos.x >= Director::getInstance()->getVisibleSize().width) steering += Vec2(-1, 0);if (tarPos.x <= 0) steering += Vec2(1, 0);return steering * _dtSpeed;}return Vec2::ZERO;
}void MoveNode::updatePos() {Vec2 tarPos = this->getPosition() + _velocity;if (!Rect(Vec2::ZERO, Director::getInstance()->getVisibleSize()).containsPoint(tarPos)) {_velocity = _velocity *= -100;}Vec2 directPos = _velocity.getNormalized() *= 5;_direct->setPosition(directPos);this->setPosition(tarPos);if (_velocity == Vec2::ZERO) _tarPos = Vec2(-1, -1);
}Vec2 MoveNode::turncate(Vec2 vector, float maxNumber) {if (vector.getLength() > maxNumber) { vector.normalize();vector *= maxNumber;}return vector;
}//追逐转向力
Vec2 MoveNode::seek(Vec2 seekPos){if (seekPos == Vec2(-1, -1)) return Vec2::ZERO;Vec2 normalVector = (seekPos - this->getPosition()).getNormalized();float dist = this->getPosition().getDistance(seekPos);Vec2 desiredVelocity = normalVector * _dtSpeed;//靠近目标减速带if (dist < _tarSlowRadius) desiredVelocity *= (dist / _tarSlowRadius);Vec2 steering;if (MoveSmooth) steering = desiredVelocity - _velocity;else steering = desiredVelocity;return steering;
}//躲避转向力
Vec2 MoveNode::flee() {Vec2 steering = Vec2::ZERO;if (!_fleeObjs.empty()) {for (auto eludeObj : _fleeObjs) {auto fleePos = eludeObj->getPosition();if (fleePos.getDistance(this->getPosition()) < _fleeRadius) {Vec2 normalVector = (this->getPosition() - fleePos).getNormalized();Vec2 desiredVelocity = normalVector * _dtSpeed;Vec2 steeringChild;if (MoveSmooth) steeringChild = desiredVelocity - _velocity;else steeringChild = desiredVelocity;steering += steeringChild;}}return steering;}if(_fleePos == Vec2::ZERO) return steering;if (this->getPosition().getDistance(_fleePos) < _fleeRadius) {Vec2 normalVector = (this->getPosition() - _fleePos).getNormalized();Vec2 desiredVelocity = normalVector * _dtSpeed;if (MoveSmooth) steering = desiredVelocity - _velocity;else steering = desiredVelocity;}return steering;
}Vec2 MoveNode::changeAngle(Vec2 vector, float angle) {float rad = angle * M_PI / 180;float len = vector.getLength();Vec2 v;v.x = len * cos(rad);v.y = len * sin(rad);return v;
}Vec2 MoveNode::wander() {if (_wanderPos == Vec2(-1, -1)) return Vec2::ZERO;Vec2 circleCenter = _velocity.getNormalized();circleCenter *= _circleDistance;Vec2 displacement = Vec2(0, -1);displacement *= _circleRadius;displacement = changeAngle(displacement, _wanderAngle);float randomValue = RandomHelper::random_real<float>(-0.5f, 0.5f);_wanderAngle = _wanderAngle + randomValue * _changeAngle;Vec2 wanderForce = circleCenter - displacement;float dist = this->getPosition().getDistance(_wanderPos);if (dist > _wanderRadius) {// 偏离漫游点一定范围的话,给个回头力Vec2 desiredVelocity = (_wanderPos - this->getPosition()).getNormalized() * _wanderPullBackSteering;desiredVelocity -= _velocity;wanderForce += desiredVelocity;}return wanderForce;
}Vec2 MoveNode::pursuit() {if (_pursuitObj == nullptr) return Vec2::ZERO;Vec2 pursuitPos = _pursuitObj->getPosition();float t = this->getPosition().getDistance(pursuitPos) / _dtSpeed;//float t = 3;
//    Vec2 tarPos = pursuitPos + _pursuitObj->getVelocity() * t;Vec2 tarPos = pursuitPos;return seek(tarPos);
}//求物体一定半径范围内的其他临近物体的所有位置,用这个位置进行一个追寻力seek
Vec2 MoveNode::cohesion() {Vec2 averagePos = Vec2::ZERO;int count = 0;for (auto obj : _cohesionObj) {if (obj->getId() != _id) {averagePos += obj->getPosition();count++;}}if (count > 0) { averagePos *= (1 / (float)count); return seek(averagePos) * _cohesionWeight;}return Vec2::ZERO;
}//求物体一定半径范围内的其他临近物体的位置,用当前物体位置分别减去临近物体位置,获取单位方向向量,乘以根据距离远近算出来得权重
//越近权重越大。在把所有向量相加取平均值
Vec2 MoveNode::separation() {Vec2 steering = Vec2::ZERO;int count = 0;for (auto obj : _separationObj) {if (obj->getId() != _id) {float dist = this->getPosition().getDistance(obj->getPosition());Vec2 normalVector = (this->getPosition() - obj->getPosition()).getNormalized();Vec2 desiredVelocity = normalVector;desiredVelocity *= (1 / dist);steering += desiredVelocity;count++;}}if (count > 0) steering *= (1 / (float)count);return steering * _dtSpeed * _separationWeight;
}//求物体一定半径范围内的其他临近物体的所有速度向量,相加取平均值
Vec2 MoveNode::alignment() {Vec2 steering = Vec2::ZERO;int count = 0;for (auto obj : _alignmentObj) {if (obj->getId() != _id) {steering += obj->getVelocity();count++;}}if (count > 0) steering *= (1 / (float)count);return steering * _alignmentWeight;
}void MoveNode::setPos(Vec2 pos) {this->setPosition(pos);_velocity.setZero();
}void MoveNode::setWanderPos(Vec2 wanderPos) {_wanderPos = wanderPos;setPos(wanderPos);
}void MoveNode::switchPursuitObj(MoveNode* pursuitObj) {if (_pursuitObj == nullptr) _pursuitObj = pursuitObj;else {_pursuitObj = nullptr;_velocity = Vec2::ZERO;_tarPos = Vec2(-1, -1);}
}void MoveNode::findNeighbourObjs() {if (_allObj == nullptr) return;_alignmentObj.clear();_cohesionObj.clear();_separationObj.clear();for (auto obj : *_allObj) {float dist = this->getPosition().getDistance(obj->getPosition());if (dist < _alignmentRadius) {_alignmentObj.push_back(obj);}if (dist < _cohesionRadius) {_cohesionObj.push_back(obj);}if (dist < _separationRadius) {_separationObj.push_back(obj);}}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/187733.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【计算机组成原理】指令系统

&#x1f384;欢迎来到边境矢梦的csdn博文&#x1f384; &#x1f384;本文主要梳理计算机组成原理中 指令系统的知识点和值得注意的地方 &#x1f384; &#x1f308;我是边境矢梦&#xff0c;一个正在为秋招和算法竞赛做准备的学生&#x1f308; &#x1f386;喜欢的朋友可以…

vue 提交表单重复点击,重复提交防抖问题

问题&#xff1a;用户点击保存时&#xff0c;可能会多次点击。导致生成重复数据。 目标&#xff1a;多次点击时&#xff0c;1s内只允许提交一次数据。 解决方案&#xff1a; 1.在utils文件夹创建文件preventReClick.js export default {install (Vue) {// 防止按钮重复点击V…

10个顶级Linux开源反向代理服务器 - 解析与导航

反向代理服务器是一种部署在客户端和后端/源服务器之间的代理服务器&#xff0c;例如 NGINX、Apache 等 HTTP 服务器或用 Nodejs、Python、Java、Ruby 编写的应用程序服务器、PHP 和许多其他编程语言。 它是一个网关或中间服务器&#xff0c;它接受客户端请求&#xff0c;将其传…

2023.11.27 使用anoconda搭建tensorflow环境

2023.11.27 使用anoconda搭建tensorflow环境 提供一个简便安装tensorflow的方法 1. 首先安装anoconda&#xff0c;安装过程略&#xff0c;注意安装的时候勾选安装anoconda prompt 2. 进入anoconda prompt 3. 建立python版本 conda create -n tensorflow1 python3.84. 激活t…

勒索解密后oracle无法启动故障处理----惜分飞

客户linux平台被勒索病毒加密,其中有oracle数据库.客户联系黑客进行解密【勒索解密oracle失败】,但是数据库无法正常启动,dbv检查数据库文件报错 [oraclehisdb ~]$ dbv filesystem01.dbf DBVERIFY: Release 11.2.0.1.0 - Production on 星期一 11月 27 21:49:17 2023 Copyrig…

如何在服务器上运行python文件

目录 前置准备 详细步骤 一&#xff0c;在服务器安装Anaconda 下载安装包 上传文件到服务器 安装环境 二&#xff0c;创建虚拟环境 创建环境 三&#xff0c;测试执行python文件 执行python文件 查看进程状态 总结 前置准备 如何在个人服务器上运行python文件&#x…

Mysql索引案例分析

这篇文章写个案例&#xff0c;测试一下MySQL索引机制 测试表结构 CREATE TABLE t_qrcode_op (id int(11) NOT NULL AUTO_INCREMENT COMMENT 主键,op_mobile varchar(16) NOT NULL,pr_code char(10) NOT NULL,PRIMARY KEY (id),UNIQUE KEY om_pc (op_mobile,pr_code) USING BTR…

会员管理系统的意义何在?

在当今的商业环境中&#xff0c;会员管理系统已经成为企业运营的重要组成部分。会员管理系统的意义在于不仅能够帮助企业提高效率&#xff0c;提升用户体验&#xff0c;进行数据分析&#xff0c;营销推广&#xff0c;还能够帮助企业增加收入。下面&#xff0c;我们将详细探讨会…

微调Fine tune

网络架构 一个神经网络一般可以分为两块 特征抽取将原始像素变成容易线性分割的特征线性分类器来做分类 微调&#xff1a;使用之前已经训练好的特征抽取模块来直接使用到现有模型上&#xff0c;而对于线性分类器由于标号可能发生改变而不能直接使用 训练 是一个目标数据集上…

Linux驱动开发——网络设备驱动(实战篇)

目录 四、 网络设备驱动实例 五、DM9000 网络设备驱动代码分析 六、NAPI 七、习题 书接上回&#xff1a; Linux驱动开发——网络设备驱动&#xff08;理论篇&#xff09;-CSDN博客 &#xff08;没看过上面博客的同学&#xff0c;skb是linux对于网络套接字缓冲区的一个虚拟…

Leetcode 136. 只出现一次的数字

class Solution {//任何数与0异或结果都是原来的数//任何数和自身异或结果都是0//异或满足交换律和结合律//a ^ b ^ a (a ^ a) ^ b 0 ^ b bpublic int singleNumber(int[] nums) {int res nums[0];for(int i 1; i < nums.length; i){res ^ nums[i];}return res;} }

OpenCvSharp从入门到实践-(04)色彩空间

目录 1、GRAY色彩空间 2、从BGR色彩空间转换到GRAY色彩空间 2.1色彩空间转换码 2.2实例 BGR色彩空间转换到GRAY色彩空间 3、HSV色彩空间 4、从BGR色彩空间转换到HSV色彩空间 4.1色彩空间转换码 4.2实例 BGR色彩空间转换到HSV色彩空间 1、GRAY色彩空间 GRAY色彩空间通常…

Spring简单的存储和读取

前言 前面讲了spring的创建&#xff0c;现在说说关于Bean和五大类注解 一、Bean是什么&#xff1f; 在 Java 语⾔中对象也叫做 Bean&#xff0c;所以后⾯咱们再遇到对象就以 Bean 著称。这篇文章还是以spring创建为主。 二、存储对象 2.1 俩种存储方式 需要在 spring-conf…

使用Jmeter进行http接口性能测试

在进行网页或应用程序后台接口开发时&#xff0c;一般要及时测试开发的接口能否正确接收和返回数据&#xff0c;对于单次测试&#xff0c;Postman插件是个不错的Http请求模拟工具。 但是Postman只能模拟单客户端的单次请求&#xff0c;而对于模拟多用户并发等性能测试&#xf…

[Verilog语法]:===和!==运算符使用注意事项

[Verilog语法]&#xff1a;和!运算符使用注意事项 1&#xff0c; 和 !运算符使用注意事项2&#xff0c;3&#xff0c; 1&#xff0c; 和 !运算符使用注意事项 参考文献&#xff1a; 1&#xff0c;[SystemVerilog语法拾遗] 和!运算符使用注意事项 2&#xff0c; 3&#xff0c;

机器学习入门(第五天)——决策树(每次选一边)

Decision tree 知识树 Knowledge tree 一个小故事 A story 挑苹果&#xff1a; 根据这些特征&#xff0c;如颜色是否是红色、硬度是否是硬、香味是否是香&#xff0c;如果全部满足绝对是好苹果&#xff0c;或者红色硬但是无味也是好苹果&#xff0c;从上图可以看出来&#…

数据可视化:用图表和图形展示数据

写在开头 在当今信息爆炸的时代,海量的数据如同一座沉默的宝库,等待着我们挖掘和理解。然而,这些庞大的数据集本身可能令人望而生畏。在这个时候,数据可视化成为了解数据、发现模式和传达信息的强大工具。本篇博客将带领你探索数据可视化的奇妙世界,学习如何在python中使…

91基于matlab的以GUI实现指纹的识别和匹配百分比

基于matlab的以GUI实现指纹的识别和匹配百分比,中间有对指纹的二值化&#xff0c;M连接&#xff0c;特征提取等处理功能。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 91M连接 特征提取 (xiaohongshu.com)

Windows 安装redis,设置开机自启动

Windows 安装redis,设置开机自启动 文章目录 Windows 安装redis,设置开机自启动下载, 解压到指定目录设置redis密码启动redis服务端停止redis服务端设置自启动 下载, 解压到指定目录 官网地址: https://redis.io/ 安装包下载地址: https://github.com/tporadowski/redis/relea…

NB-IoT BC260Y Open CPU SDK⑥ADC的应用

NB-IoT BC260Y Open CPU SDK⑥ADC的应用 1、BC260Y_CN_AA模块 ADC的介绍2、ADC相关API的介绍3、软件设计4、实例分析5、以下是调试的结果:1、BC260Y_CN_AA模块 ADC的介绍 BC260Y-CN QuecOpen 模块提供 2 个专用于 ADC(ADC0、ADC1)功能的 I/O 引脚。通过相应的 API函数可以直…