This commit is contained in:
aozhiwei 2020-07-20 11:13:41 +08:00
parent 714342d4ce
commit c84de56bbc
2 changed files with 108 additions and 105 deletions

View File

@ -17,6 +17,28 @@ enum ShotType_e
kShotHold = 2, kShotHold = 2,
}; };
class ZombieAINode
{
public:
ZombieState_e main_state = ZSE_Idle;
long long frameno = 0;
long long exec_frame_num = 0;
long long start_shot_frameno = 0;
long long next_random_move_frameno = 0;
int shot_times = 0;
int total_shot_times = 0;
int next_total_shot_times = 0;
long long param1 = 0;
Human* target = nullptr;
Human* nearest_human = nullptr;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
bool moving = false;
MetaData::AI* ai_meta = nullptr;
};
/* /*
nn目标ai可切换/() nn目标ai可切换/()
@ -31,8 +53,14 @@ ai级别
8: 8:
*/ */
ZombieAI::ZombieAI()
{
node_ = new ZombieAINode();
}
ZombieAI::~ZombieAI() ZombieAI::~ZombieAI()
{ {
A8_SAFE_DELETE(node_);
} }
void ZombieAI::Update(int delta_time) void ZombieAI::Update(int delta_time)
@ -55,10 +83,10 @@ void ZombieAI::Update(int delta_time)
float ZombieAI::GetAttackRate() float ZombieAI::GetAttackRate()
{ {
if (!ai_meta) { if (!node_->ai_meta) {
return 1; return 1;
} else { } else {
return ai_meta->i->attack_rate(); return node_->ai_meta->i->attack_rate();
} }
} }
@ -68,15 +96,15 @@ void ZombieAI::UpdateAI()
if (a8::HasBitFlag(hum->status, HS_Disable)) { if (a8::HasBitFlag(hum->status, HS_Disable)) {
return; return;
} }
if (!ai_meta && GetAiLevel() != 0) { if (!node_->ai_meta && GetAiLevel() != 0) {
ai_meta = MetaMgr::Instance()->GetAI(GetAiLevel()); node_->ai_meta = MetaMgr::Instance()->GetAI(GetAiLevel());
if (!ai_meta) { if (!node_->ai_meta) {
abort(); abort();
} }
} }
++node_.exec_frame_num; ++node_->exec_frame_num;
hum->shot_hold = false; hum->shot_hold = false;
switch (node_.main_state) { switch (node_->main_state) {
case ZSE_Idle: case ZSE_Idle:
{ {
UpdateIdle(); UpdateIdle();
@ -108,7 +136,7 @@ void ZombieAI::UpdateAI()
} }
break; break;
} }
if (moving_) { if (node_->moving) {
DoMove(); DoMove();
} }
} }
@ -116,7 +144,7 @@ void ZombieAI::UpdateAI()
void ZombieAI::UpdateIdle() void ZombieAI::UpdateIdle()
{ {
Human* hum = (Human*)owner; Human* hum = (Human*)owner;
if (hum->room->GetFrameNo() > node_.frameno + node_.param1) { if (hum->room->GetFrameNo() > node_->frameno + node_->param1) {
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
} }
} }
@ -134,10 +162,10 @@ void ZombieAI::UpdateThinking()
} else { } else {
Human* target = GetTarget(); Human* target = GetTarget();
if (target) { if (target) {
node_.target = target; node_->target = target;
ChangeToState(ZSE_Attack); ChangeToState(ZSE_Attack);
} else { } else {
if (hum->room->GetFrameNo() >= node_.next_random_move_frameno) { if (hum->room->GetFrameNo() >= node_->next_random_move_frameno) {
if ((rand() % 7) < 4) { if ((rand() % 7) < 4) {
ChangeToState(ZSE_Idle); ChangeToState(ZSE_Idle);
} else { } else {
@ -145,7 +173,7 @@ void ZombieAI::UpdateThinking()
} }
} else { } else {
ChangeToState(ZSE_Idle); ChangeToState(ZSE_Idle);
node_.param1 = node_.next_random_move_frameno - hum->room->GetFrameNo(); node_->param1 = node_->next_random_move_frameno - hum->room->GetFrameNo();
} }
} }
} }
@ -154,21 +182,21 @@ void ZombieAI::UpdateThinking()
void ZombieAI::UpdateAttack() void ZombieAI::UpdateAttack()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (!node_.target || node_.target->dead) { if (!node_->target || node_->target->dead) {
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
return; return;
} }
if (node_.exec_frame_num > SERVER_FRAME_RATE * 8) { if (node_->exec_frame_num > SERVER_FRAME_RATE * 8) {
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
return; return;
} }
float distance = myself->GetPos().Distance(node_.target->GetPos()); float distance = myself->GetPos().Distance(node_->target->GetPos());
if (distance > GetAttackRange()) { if (distance > GetAttackRange()) {
if (ai_meta->i->pursuit_radius() <= 0) { if (node_->ai_meta->i->pursuit_radius() <= 0) {
//站桩 //站桩
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
} else { } else {
if (distance < ai_meta->i->pursuit_radius()) { if (distance < node_->ai_meta->i->pursuit_radius()) {
//追击 //追击
ChangeToState(ZSE_Pursuit); ChangeToState(ZSE_Pursuit);
} else { } else {
@ -178,16 +206,16 @@ void ZombieAI::UpdateAttack()
return; return;
} }
//攻击逻辑 //攻击逻辑
switch (ai_meta->i->attack_type()) { switch (node_->ai_meta->i->attack_type()) {
case kShotClick: case kShotClick:
{ {
if (ai_meta->i->attack_interval() > 0) { if (node_->ai_meta->i->attack_interval() > 0) {
if (node_.shot_times < GetAttackTimes()) { if (node_->shot_times < GetAttackTimes()) {
DoShot(); DoShot();
} else { } else {
ChangeToState(ZSE_Idle); ChangeToState(ZSE_Idle);
node_.next_total_shot_times = node_.total_shot_times; node_->next_total_shot_times = node_->total_shot_times;
node_.param1 = ai_meta->i->attack_interval() / 1000 * SERVER_FRAME_RATE; node_->param1 = node_->ai_meta->i->attack_interval() / 1000 * SERVER_FRAME_RATE;
} }
} else { } else {
myself->shot_hold = true; myself->shot_hold = true;
@ -212,7 +240,7 @@ void ZombieAI::UpdateAttack()
void ZombieAI::UpdateRandomWalk() void ZombieAI::UpdateRandomWalk()
{ {
Human* hum = (Human*)owner; Human* hum = (Human*)owner;
if (hum->room->GetFrameNo() > node_.frameno + node_.param1) { if (hum->room->GetFrameNo() > node_->frameno + node_->param1) {
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
} }
} }
@ -220,11 +248,11 @@ void ZombieAI::UpdateRandomWalk()
void ZombieAI::UpdatePursuit() void ZombieAI::UpdatePursuit()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
float distance = myself->GetPos().Distance(node_.target->GetPos()); float distance = myself->GetPos().Distance(node_->target->GetPos());
if (distance < GetAttackRange()) { if (distance < GetAttackRange()) {
ChangeToState(ZSE_Attack); ChangeToState(ZSE_Attack);
} else { } else {
if (node_.exec_frame_num > 100 * 2) { if (node_->exec_frame_num > 100 * 2) {
ChangeToState(ZSE_RandomWalk); ChangeToState(ZSE_RandomWalk);
} }
} }
@ -243,11 +271,11 @@ void ZombieAI::DoMove()
int speed = std::max(1, (int)hum->GetSpeed()) * 1; int speed = std::max(1, (int)hum->GetSpeed()) * 1;
hum->_UpdateMove(speed); hum->_UpdateMove(speed);
hum->on_move_collision = nullptr; hum->on_move_collision = nullptr;
if (node_.nearest_human) { if (node_->nearest_human) {
if (node_.main_state != ZSE_Pursuit && if (node_->main_state != ZSE_Pursuit &&
hum->GetPos().ManhattanDistance(node_.nearest_human->GetPos()) < 200) { hum->GetPos().ManhattanDistance(node_->nearest_human->GetPos()) < 200) {
ChangeToState(ZSE_Thinking); ChangeToState(ZSE_Thinking);
} else if (hum->GetPos().ManhattanDistance(node_.nearest_human->GetPos()) > 800) { } else if (hum->GetPos().ManhattanDistance(node_->nearest_human->GetPos()) > 800) {
GetTarget(); GetTarget();
} }
} }
@ -260,73 +288,73 @@ void ZombieAI::ChangeToState(ZombieState_e to_state)
switch (to_state) { switch (to_state) {
case ZSE_Idle: case ZSE_Idle:
{ {
node_.target = nullptr; node_->target = nullptr;
node_.param1 = 0; node_->param1 = 0;
node_.start_shot_frameno = 0; node_->start_shot_frameno = 0;
node_.shot_times = 0; node_->shot_times = 0;
moving_ = false; node_->moving = false;
if (hum->room->GetGasData().gas_mode == GasInactive || if (hum->room->GetGasData().gas_mode == GasInactive ||
hum->room->IsWaitingStart()) { hum->room->IsWaitingStart()) {
node_.param1 = rand() % (3 * SERVER_FRAME_RATE); node_->param1 = rand() % (3 * SERVER_FRAME_RATE);
} else { } else {
node_.param1 = rand() % (2 * SERVER_FRAME_RATE); node_->param1 = rand() % (2 * SERVER_FRAME_RATE);
} }
} }
break; break;
case ZSE_Thinking: case ZSE_Thinking:
{ {
node_.target = nullptr; node_->target = nullptr;
node_.param1 = 0; node_->param1 = 0;
node_.start_shot_frameno = 0; node_->start_shot_frameno = 0;
node_.shot_times = 0; node_->shot_times = 0;
moving_ = false; node_->moving = false;
} }
break; break;
case ZSE_Attack: case ZSE_Attack:
{ {
node_.param1 = 0; node_->param1 = 0;
node_.start_shot_frameno = 0; node_->start_shot_frameno = 0;
node_.shot_times = 0; node_->shot_times = 0;
moving_ = false; node_->moving = false;
node_.shot_times = 0; node_->shot_times = 0;
} }
break; break;
case ZSE_RandomWalk: case ZSE_RandomWalk:
{ {
moving_ = true; node_->moving = true;
node_.target = nullptr; node_->target = nullptr;
#if 1 #if 1
node_.param1 = SERVER_FRAME_RATE * ai_meta->GetMoveTime(); node_->param1 = SERVER_FRAME_RATE * node_->ai_meta->GetMoveTime();
#else #else
node_.param1 = SERVER_FRAME_RATE * 5 + rand() % (SERVER_FRAME_RATE * 3); node_->param1 = SERVER_FRAME_RATE * 5 + rand() % (SERVER_FRAME_RATE * 3);
#endif #endif
node_.start_shot_frameno = 0; node_->start_shot_frameno = 0;
node_.shot_times = 0; node_->shot_times = 0;
node_.next_random_move_frameno = hum->room->GetFrameNo() + node_->next_random_move_frameno = hum->room->GetFrameNo() +
SERVER_FRAME_RATE * ai_meta->GetMoveIdleTime(); SERVER_FRAME_RATE * node_->ai_meta->GetMoveIdleTime();
hum->move_dir = a8::Vec2(1.0f, 0); hum->move_dir = a8::Vec2(1.0f, 0);
hum->move_dir.Rotate(a8::RandAngle()); hum->move_dir.Rotate(a8::RandAngle());
hum->move_dir.Normalize(); hum->move_dir.Normalize();
hum->attack_dir = hum->move_dir; hum->attack_dir = hum->move_dir;
if (node_.param1 <= 1) { if (node_->param1 <= 1) {
moving_ = false; node_->moving = false;
} }
} }
break; break;
case ZSE_Pursuit: case ZSE_Pursuit:
{ {
moving_ = true; node_->moving = true;
if (node_.target) { if (node_->target) {
hum->move_dir = node_.target->GetPos() - hum->GetPos(); hum->move_dir = node_->target->GetPos() - hum->GetPos();
hum->move_dir.Normalize(); hum->move_dir.Normalize();
hum->attack_dir = hum->move_dir; hum->attack_dir = hum->move_dir;
} }
} }
break; break;
} }
node_.main_state = to_state; node_->main_state = to_state;
node_.frameno = hum->room->GetFrameNo(); node_->frameno = hum->room->GetFrameNo();
node_.exec_frame_num = 0; node_->exec_frame_num = 0;
} }
Human* ZombieAI::GetTarget() Human* ZombieAI::GetTarget()
@ -363,8 +391,8 @@ Human* ZombieAI::GetTarget()
} }
}); });
if (target) { if (target) {
node_.nearest_human = target; node_->nearest_human = target;
node_.last_check_nearest_human_frameno = myself->room->GetFrameNo(); node_->last_check_nearest_human_frameno = myself->room->GetFrameNo();
float distance = myself->GetPos().Distance(target->GetPos()); float distance = myself->GetPos().Distance(target->GetPos());
if (distance > GetAttackRange()) { if (distance > GetAttackRange()) {
target = nullptr; target = nullptr;
@ -380,29 +408,29 @@ float ZombieAI::GetAttackRange()
if (myself->curr_weapon && myself->curr_weapon->meta) { if (myself->curr_weapon && myself->curr_weapon->meta) {
attack_range = myself->curr_weapon->meta->i->range(); attack_range = myself->curr_weapon->meta->i->range();
} }
attack_range = std::min(ai_meta->i->attack_range(), (int)attack_range); attack_range = std::min(node_->ai_meta->i->attack_range(), (int)attack_range);
return attack_range; return attack_range;
} }
void ZombieAI::DoShot() void ZombieAI::DoShot()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (!node_.target) { if (!node_->target) {
return; return;
} }
bool shot_ok = false; bool shot_ok = false;
a8::Vec2 shot_dir = myself->attack_dir; a8::Vec2 shot_dir = myself->attack_dir;
if (node_.total_shot_times >= node_.next_total_shot_times) { if (node_->total_shot_times >= node_->next_total_shot_times) {
shot_dir = node_.target->GetPos() - myself->GetPos(); shot_dir = node_->target->GetPos() - myself->GetPos();
node_.next_total_shot_times += 7 + (rand() % 6); node_->next_total_shot_times += 7 + (rand() % 6);
myself->attack_dir = shot_dir; myself->attack_dir = shot_dir;
} }
if (std::abs(shot_dir.x) > FLT_EPSILON || if (std::abs(shot_dir.x) > FLT_EPSILON ||
std::abs(shot_dir.y) > FLT_EPSILON) { std::abs(shot_dir.y) > FLT_EPSILON) {
shot_dir.Normalize(); shot_dir.Normalize();
if (ai_meta->i->shot_offset_angle() > 0) { if (node_->ai_meta->i->shot_offset_angle() > 0) {
int shot_offset_angle = a8::RandEx(ai_meta->i->shot_offset_angle(), int shot_offset_angle = a8::RandEx(node_->ai_meta->i->shot_offset_angle(),
1); 1);
if (rand() % 10 < 3) { if (rand() % 10 < 3) {
shot_dir.Rotate(shot_offset_angle / 180.0f); shot_dir.Rotate(shot_offset_angle / 180.0f);
@ -415,11 +443,11 @@ void ZombieAI::DoShot()
myself->Shot(shot_dir, shot_ok); myself->Shot(shot_dir, shot_ok);
myself->attack_dir = old_attack_dir; myself->attack_dir = old_attack_dir;
if (shot_ok) { if (shot_ok) {
if (node_.shot_times <= 0) { if (node_->shot_times <= 0) {
node_.start_shot_frameno = myself->room->GetFrameNo(); node_->start_shot_frameno = myself->room->GetFrameNo();
} }
++node_.shot_times; ++node_->shot_times;
++node_.total_shot_times; ++node_->total_shot_times;
} }
} }
} }
@ -428,8 +456,8 @@ int ZombieAI::GetAttackTimes()
{ {
Human* myself = (Human*)owner; Human* myself = (Human*)owner;
if (myself->curr_weapon) { if (myself->curr_weapon) {
return std::min(ai_meta->i->attack_times(), myself->curr_weapon->GetClipVolume()); return std::min(node_->ai_meta->i->attack_times(), myself->curr_weapon->GetClipVolume());
} else { } else {
return ai_meta->i->attack_times(); return node_->ai_meta->i->attack_times();
} }
} }

View File

@ -12,35 +12,12 @@ enum ZombieState_e
}; };
class Human; class Human;
class ZombieAINode class ZombieAINode;
{
public:
ZombieState_e main_state = ZSE_Idle;
long long frameno = 0;
long long exec_frame_num = 0;
long long start_shot_frameno = 0;
long long next_random_move_frameno = 0;
int shot_times = 0;
int total_shot_times = 0;
int next_total_shot_times = 0;
long long param1 = 0;
Human* target = nullptr;
Human* nearest_human = nullptr;
long long last_check_nearest_human_frameno = 0;
a8::Vec2 shot_dir;
};
namespace MetaData
{
class AI;
}
class Human;
class ZombieAI : public AIComponent class ZombieAI : public AIComponent
{ {
public: public:
ZombieAI();
virtual ~ZombieAI() override; virtual ~ZombieAI() override;
virtual void Update(int delta_time) override; virtual void Update(int delta_time) override;
float GetAttackRate(); float GetAttackRate();
@ -61,7 +38,5 @@ private:
int GetAttackTimes(); int GetAttackTimes();
private: private:
MetaData::AI* ai_meta = nullptr; ZombieAINode* node_ = nullptr;
ZombieAINode node_;
bool moving_ = false;
}; };