软件下载网站制作,介绍自己做的网站的论文,房产网排名,昆山外贸网站建设推广游戏AI角色的转向系统#xff08;Steering behaviors#xff09;实现
一些向量的接口是cocos2dx的。但从名字上应该能理解做了什么向量操作
Seek#xff1a;
获取当前位置指向目标点的向量#xff0c;转化为单位向量后再乘以速度值#xff0c;即为所需速度desired velo…游戏AI角色的转向系统Steering behaviors实现
一些向量的接口是cocos2dx的。但从名字上应该能理解做了什么向量操作
Seek
获取当前位置指向目标点的向量转化为单位向量后再乘以速度值即为所需速度desired velocity所需速度减去当前速度current velocity即为seek的转向力将角色推向目标
//追逐转向力
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;Vec2 steering;if (MoveSmooth) steering desiredVelocity - _velocity;else steering desiredVelocity;return steering;
} 物体在追逐目标时会有一个逐渐转弯的过程
如果没有转向力的话物体就是直接切换方向
Flee
与seek类似只是所需速度desired velocity的方向是由目标点指向当前位置。 这里在逃离目标点加了个检测半径在这个范围里的物体将会受到逃离力。
//躲避转向力
Vec2 MoveNode::flee() {Vec2 steering Vec2::ZERO;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;
}逃离时的转向效果 与没有转向力直接逃离的效果对比
arrive
因为seek力的存在所以在到达目标点时会在目标点附近来回弹跳 为此在目标点周围添加一个减速场slowing area。在目标点周围一定范围内当物体越靠近目标时seek力会越小。seek力大小在减速带范围内线性减小与目标点的距离成反比。而在范围外则是正常的seek力大小
//追逐转向力
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;
}Wander
漫游巡逻在物体前进方向的前方一定范围_circleDistance内画个圆用来计算受力行为。位移力 以圆心为原点受半径_circleRadius约束。半径越大以及角色到圆圈的距离越大角色在每个游戏帧中受到的“推力”就越强。 初始会给一个方向wander angle之后每帧会在一定的转向范围_changeAngle内随机一个转角方向。改变物体巡逻的方向wander angle 我在这里加了一个巡逻范围_wanderPullBackSteering当偏离一定范围时会受到回拉的力
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_realfloat(-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;
}Pursuit
追捕某个物体实际上就是seek到某个位置只不过这个位置需要预测追捕目标将来的位置target in the future来seek而不能以追捕目标当前位置来seek 预测的位置即目标当前位置目标当前速度加一定帧数T。如果T的值是个常数时会出现一个问题当目标很近时追击精度往往会变差。这是因为当目标接近时追击者会继续寻找目标位置的进行预测也就是“远离”T帧后的位置。因此可以用动态T 值代替常量T 值 新的T值为目标从当前位置移动到追击者位置还需要更新多少次
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);
}没有预测的追捕的话就会一直沿着追捕目标的路径一直跟在后面
Evading
躲避与追捕类似只不过将预测目标的位置用来做flee而不是做seek
Combining Steering Forces
多种力是可以相互结合的以向量的形式相加得到物体最终受到的力
void MoveNode::update(float dt)
{_dtSpeed _speed * dt;if (MoveSmooth) {Vec2 steering Vec2::ZERO;steering seek(_tarPos);steering flee();steering wander();steering pursuit();steering turncate(steering, _maxForce);steering * ( 1 / (float)_mass );_velocity steering;}else {_velocity seek(_tarPos);_velocity flee();_velocity wander();_velocity pursuit();}_velocity wallAvoid();_velocity turncate(_velocity, _maxSpeed * dt);updatePos();
}下面是一个物体受到多个正在漫游目标产生的逃离力的影响同时还有寻求到目标的力 的例子
源码
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(vectorMoveNode* fleeObjs) { _fleeObjs fleeObjs; };void setWanderPos(Vec2 wanderPos);void switchPursuitObj(MoveNode* pursuitObj);Vec2 seek(Vec2 seekPos);Vec2 flee();Vec2 wander();Vec2 pursuit();Vec2 wallAvoid();Vec2 turncate(Vec2 vector, float maxNumber);Vec2 changeAngle(Vec2 vector, float angle);void updatePos();void update(float dt);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 _dtSpeed; //每帧速度值Vec2 _velocity; //速度float _wanderAngle; //巡逻角度Vec2 _wanderPos; //巡逻范围中心点Vec2 _tarPos; //目标点Vec2 _fleePos; //逃离点MoveNode* _pursuitObj; //追逐目标vectorMoveNode* _fleeObjs; //逃离目标float wallAvoidRadius 50.0f; //墙壁碰撞检测半径
};#endifMoveNode.cpp
#include MoveNode.hbool 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)
{_dtSpeed _speed * dt;if (MoveSmooth) {Vec2 steering Vec2::ZERO;steering seek(_tarPos);steering flee();steering wander();steering pursuit();steering turncate(steering, _maxForce);steering * ( 1 / (float)_mass );_velocity steering;}else {_velocity seek(_tarPos);_velocity flee();_velocity wander();_velocity pursuit();}_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_realfloat(-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);
}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);}
}